diff --git a/.github/workflows/androidbuild.yml b/.github/workflows/androidbuild.yml new file mode 100644 index 0000000000..b2b9d67f77 --- /dev/null +++ b/.github/workflows/androidbuild.yml @@ -0,0 +1,27 @@ +name: android-apk build + +on: [push, pull_request] + +jobs: + + make-apk: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Pull the Docker Image + run: docker pull analogdevices/scopy-build:android + - name: Run Docker Image + run: | + docker run --privileged --net=host \ + -v `pwd`:$GITHUB_WORKSPACE:rw \ + -e "GITHUB_WORKSPACE=$GITHUB_WORKSPACE" \ + -e "BRANCH=${GITHUB_REF#refs/heads/}" \ + analogdevices/scopy-build:android /bin/bash -xe $GITHUB_WORKSPACE/CI/appveyor/build_scopy_apk.sh + - uses: actions/upload-artifact@v2 + with: + name: scopy-android + path: | + ${{ github.workspace }}/android-build-debug.apk + ${{ github.workspace }}/android-build-debug.aab + ${{ github.workspace }}/android-build-release.aab diff --git a/.github/workflows/dockerimage.yml b/.github/workflows/linuxflatpakbuild.yml similarity index 83% rename from .github/workflows/dockerimage.yml rename to .github/workflows/linuxflatpakbuild.yml index 70f0d00889..cdef2225ce 100644 --- a/.github/workflows/dockerimage.yml +++ b/.github/workflows/linuxflatpakbuild.yml @@ -1,4 +1,4 @@ -name: Docker Image CI +name: linux-flatpak build on: [push, pull_request] @@ -10,13 +10,13 @@ jobs: steps: - uses: actions/checkout@v2 - name: Pull the Docker Image - run: docker pull adisuciu/scopy-flatpak-ubuntu20:latest + run: docker pull analogdevices/scopy-build:flatpak - name: Run Docker Image run: | docker run --privileged \ -v `pwd`:$GITHUB_WORKSPACE:rw \ -e "GITHUB_WORKSPACE=$GITHUB_WORKSPACE" \ - adisuciu/scopy-flatpak-ubuntu20:latest /bin/bash -xe $GITHUB_WORKSPACE/CI/appveyor/inside_flatpak_docker.sh + analogdevices/scopy-build:flatpak /bin/bash -xe $GITHUB_WORKSPACE/CI/appveyor/inside_flatpak_docker.sh - uses: actions/upload-artifact@v2 with: name: Scopy.flatpak @@ -29,4 +29,3 @@ jobs: 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/.github/workflows/mingwbuild.yml b/.github/workflows/mingwbuild.yml new file mode 100644 index 0000000000..3787b8c2ca --- /dev/null +++ b/.github/workflows/mingwbuild.yml @@ -0,0 +1,57 @@ +name: windows-mingw build + +on: [push, pull_request] + +jobs: + + make-exe-64: + runs-on: windows-2019 + + steps: + - uses: actions/checkout@v2 + - name: Pull the Docker Image + run: docker pull analogdevices/scopy-build:mingw64 + + - name: Run Docker Image + shell: cmd + run: | + mkdir %GITHUB_WORKSPACE%\artifacts & echo %GITHUB_WORKSPACE% & docker run -v %cd%:C:\msys64\home\docker\scopy:rw -v %GITHUB_WORKSPACE%\artifacts:C:\msys64\home\docker\artifact_x86_64:rw -e GITHUB_WORKSPACE=%GITHUB_WORKSPACE% analogdevices/scopy-build:mingw64 C:\msys64\usr\bin\bash.exe -c '/home/docker/scopy/CI/appveyor/inside_mingw_docker.sh' + - uses: actions/upload-artifact@v2 + with: + name: scopy-x86_64.zip + path: ${{ github.workspace }}\artifacts\scopy-x86_64.zip + + - uses: actions/upload-artifact@v2 + with: + name: debug-x86_64.zip + path: ${{ github.workspace }}\artifacts\debug-x86_64.zip + - uses: actions/upload-artifact@v2 + with: + name: scopy-x86_64-setup.exe + path: ${{ github.workspace }}\artifacts\scopy-64-setup.exe + +# make-exe-32: +# runs-on: windows-latest +# +# steps: +## - uses: actions/checkout@v2 +# - name: Pull the Docker Image +# run: docker pull analogdevices/scopy-build:mingw32 +# +# - name: Run Docker Image +# shell: cmd +# run: | +# mkdir %GITHUB_WORKSPACE%\artifacts & echo %GITHUB_WORKSPACE% & #docker run -v %cd%:C:\msys64\home\docker\scopy:rw -v #%GITHUB_WORKSPACE%\artifacts:C:\msys64\home\docker\artifact_i686:rw #-e GITHUB_WORKSPACE=%GITHUB_WORKSPACE% analogdevices/#scopy-build:mingw32 C:\msys64\usr\bin\bash.exe -c '/home/docker/#scopy/CI/appveyor/inside_mingw_docker.sh' +# - uses: actions/upload-artifact@v2 +# with: +# name: scopy-i686.zip +# path: ${{ github.workspace }}\artifacts\scopy-i686.zip +# +# - uses: actions/upload-artifact@v2 +# with: +# name: debug-i686.zip +# path: ${{ github.workspace }}\artifacts\debug-i686.zip +# - uses: actions/upload-artifact@v2 +# with: +# name: scopy-i686-setup.exe +# path: ${{ github.workspace }}\artifacts\scopy-32-setup.exe diff --git a/.gitignore b/.gitignore index ee74fe5b0f..944a64cb8e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,16 @@ Makefile moc_*.cpp *_automoc.cpp ui_*.h -build +build* deps scopy +android/assets/libsigrokdecode/* +android/assets/python3.*/* +resources/stylesheets/default.qss +resources/stylesheets/light.qss +!android/src/org/adi/scopy *.swp html/ +build_arm64-v8a/ +android_cmake.sh +android_deploy_qt.sh diff --git a/CI/README.md b/CI/README.md new file mode 100644 index 0000000000..098e43fe49 --- /dev/null +++ b/CI/README.md @@ -0,0 +1,89 @@ + +This file contains dependency information for different platforms + +**Windows (x86_64)** - +https://github.com/analogdevicesinc/scopy-mingw-build-deps +builds the docker image - `docker pull analogdevices/scopy-build:mingw64` +Github Actions workflow: +https://github.com/analogdevicesinc/scopy/blob/master/.github/workflows/mingwbuild.yml + +**Linux (flatpak - x86_64)** +https://github.com/analogdevicesinc/scopy-flatpak +docker pull analogdevices/scopy-build:flatpak + + ARCH=x86_64 make + +Github Actions workflow - https://github.com/analogdevicesinc/scopy/blob/master/.github/workflows/linuxflatpakbuild.yml + +**Linux (flatpak - arm)** +https://github.com/analogdevicesinc/scopy-flatpak +Run locally on arm machine (raspberry pi) + + ARCH=arm make +Not build in CI + +**Linux (ubuntu - x86_64) - development** +Built on appveyor - https://github.com/analogdevicesinc/scopy/blob/master/appveyor.yml +**macOS (x86_64)** +Built on appveyor - https://github.com/analogdevicesinc/scopy/blob/master/appveyor.yml + +**Android (aarch64)** +https://github.com/analogdevicesinc/scopy-android-deps - `docker pull analogdevices/scopy-build:android` +Github Actions workflow - https://github.com/analogdevicesinc/scopy/blob/master/.github/workflows/androidbuild.yml + +Dependency versions (links used in source builds) + + - Qt: 5.15.12 + - Qwt - https://github.com/cseci/qwt - qwt-multiaxes + - libiio - https://github.com/analogdevicesinc/libiio - https://github.com/analogdevicesinc/libiio/tree/cad83146837971acdac28beaeb8156b9da33ba6b - v0.24 + - libxml2 - https://github.com/GNOME/libxml2 + - iconv (only on Android from src) + - libffi (only on Android from src) + - libgettext (only on Android from src) + - libusb - https://downloads.sourceforge.net/project/libusb/libusb-1.0/libusb-1.0.24/libusb-1.0.24.tar.bz2 + - Android specific libusb: https://github.com/xloem/libusb/tree/d1856aa8c246f9e56cf00a0765462b67fc5a4871 + - libm2k- https://github.com/analogdevicesinc/libm2k - master + - glog - https://github.com/google/glog + - boost - + - gnuradio - https://github.com/analogdevicesinc/gnuradio - scopy / scopy-android-2(for Android) + - volk + - log4cpp - https://github.com/cseci/log4cpp + - fftw3 + - libgmp + - gr-iio https://github.com/analogdevicesinc/gr-iio - upgrade3.8 + - libad9361 - https://github.com/analogdevicesinc/ad9361 + - gr-m2k - https://github.com/analogdevicesinc/gr-m2k - master + - gr-scopy - https://github.com/analogdevicesinc/gr-scopy - master + - libsigrokdecode - https://github.com/sigrokproject/libsigrokdecode - master + - glib + - glibmm + - sigcpp + - python + - libtinyiiod - https://github.com/analogdevicesinc/libtinyiiod - master + +How to install Qt from qt.io : https://github.com/analogdevicesinc/scopy-android-deps/blob/master/docker/Dockerfile#L43-L49 + + +| Dependency | Windows | Linux Flatpak | Linux Ubuntu(development) | Linux ARM | macOS | Android | +| --- | --- | --- | --- | --- | --- | --- | +| Qt | pacman | org.kde.Sdk (v5.15)| Qt.io |org.kde.Sdk (v5.14) | brew | Qt.io | +| qwt | src | src | src | src | src | src | +| libxml2 | pacman | src | apt | src | brew | src | +| libusb | pacman | src | apt | src | brew | src - android branch/commit | +| libiio | src | src | src | src | src | src| +| glog | src | src | src | src | brew | src | +| libm2k | src | src | src | src | src | src | +| volk | src | with GR | with GR | src | with GR | src | +| fftw3 | pacman| src | apt | src | brew| src| +| libgmp | pacman | src | apt | src | brew | src | +| boost | 1.75 | 1.72 | apt/src | 1.72 | brew | Boost-for-Android | +| gnuradio | src | src | apt/src | src | src | src | +| gr-iio | src | src | src | src | src | src | +| gr-m2k | src | src | src | src | src | src | +| gr-scopy | src | src | src | src | src | src | +| glib | pacman | src | apt | src | brew | src | +| glibmm | pacman | src | apt | src | src | src | +| sigcpp | pacman | src | apt | src | src | src | +| python | pacman | src | apt | src | brew | src | +| libsigrokdecode | src | src | src | src | src | src | +| libtinyiiod | src | src | src | src | src | src| diff --git a/CI/appveyor/before_install_lib.sh b/CI/appveyor/before_install_lib.sh index 5cbe2000ee..28d4a042f1 100755 --- a/CI/appveyor/before_install_lib.sh +++ b/CI/appveyor/before_install_lib.sh @@ -16,45 +16,26 @@ __cmake() { mkdir -p build pushd build # build - if [ "$APPVEYOR" == "true" ] ; then - cmake $args .. - make -j${NUM_JOBS} - sudo make install - else - cmake -DCMAKE_PREFIX_PATH="$STAGINGDIR" -DCMAKE_INSTALL_PREFIX="$STAGINGDIR" \ - -DCMAKE_EXE_LINKER_FLAGS="-L${STAGINGDIR}/lib" \ - $args .. $SILENCED - CFLAGS=-I${STAGINGDIR}/include LDFLAGS=-L${STAGINGDIR}/lib make -j${NUM_JOBS} $SILENCED - make install - fi - + cmake -DCMAKE_PREFIX_PATH="$STAGINGDIR" -DCMAKE_INSTALL_PREFIX="$STAGINGDIR" \ + -DCMAKE_EXE_LINKER_FLAGS="-L${STAGINGDIR}/lib" \ + $args .. $SILENCED + CFLAGS=-I${STAGINGDIR}/include LDFLAGS=-L${STAGINGDIR}/lib make -j${NUM_JOBS} $SILENCED + make -j${NUM_JOBS} + sudo make install popd } __make() { $preconfigure - if [ "$APPVEYOR" == "true" ] ; then - $configure - $make -j${NUM_JOBS} - sudo $make install - else - $configure --prefix="$STAGINGDIR" $SILENCED - CFLAGS=-I${STAGINGDIR}/include LDFLAGS=-L${STAGINGDIR}/lib $make -j${NUM_JOBS} $SILENCED - $SUDO $make install - fi + $configure --prefix="$STAGINGDIR" + $make -j${NUM_JOBS} + sudo $make install } __qmake() { - if [ "$APPVEYOR" == "true" ] ; then - $QMAKE $qtarget - make -j${NUM_JOBS} - sudo make install - else - $QMAKE "$qtarget" $SILENCED - QMAKE=$QMAKE CFLAGS=-I${STAGINGDIR}/include LDFLAGS=-L${STAGINGDIR}/lib \ - make -j${NUM_JOBS} $SILENCED - $SUDO make install - fi + $QMAKE $qtarget + make -j${NUM_JOBS} + sudo make install } __build_common() { @@ -162,7 +143,6 @@ qmake_build_local() { local dir="$1" local qtarget="$2" local patchfunc="$3" - [ ! -d "$WORKDIR/$dir" ] || { [ -z "$patchfunc" ] || { pushd $WORKDIR/$dir @@ -181,30 +161,21 @@ patch_qwt() { QWT_INSTALL_PREFIX = \$\$[QT_INSTALL_PREFIX] unix { -- QWT_INSTALL_PREFIX = /usr/local/qwt-\$\$QWT_VERSION-svn +- QWT_INSTALL_PREFIX = /usr/local + QWT_INSTALL_PREFIX = $STAGINGDIR - # QWT_INSTALL_PREFIX = /usr/local/qwt-\$\$QWT_VERSION-svn-qt-\$\$QT_VERSION + # QWT_INSTALL_PREFIX = /usr/local/qwt-\$\$QWT_VERSION-ma-qt-\$\$QT_VERSION } - -@@ -107,7 +107,7 @@ - # Otherwise you have to build it from the designer directory. - ###################################################################### - --QWT_CONFIG += QwtDesigner -+#QWT_CONFIG += QwtDesigner - - ###################################################################### - # Compile all Qwt classes into the designer plugin instead -@@ -148,7 +148,7 @@ - # Otherwise you have to build them from the tests directory. + +@@ -42,7 +42,7 @@ QWT_INSTALL_LIBS = \$\${QWT_INSTALL_PREFIX}/lib + # runtime environment of designer/creator. ###################################################################### --QWT_CONFIG += QwtTests -+#QWT_CONFIG += QwtTests +-QWT_INSTALL_PLUGINS = \$\${QWT_INSTALL_PREFIX}/plugins/designer ++#QWT_INSTALL_PLUGINS = \$\${QWT_INSTALL_PREFIX}/plugins/designer - ###################################################################### - # When Qt has been built as framework qmake wants -@@ -157,7 +157,7 @@ + # linux distributors often organize the Qt installation + # their way and QT_INSTALL_PREFIX doesn't offer a good +@@ -163,7 +163,7 @@ QWT_CONFIG += QwtOpenGL macx:!static:CONFIG(qt_framework, qt_framework|qt_no_framework) { @@ -215,49 +186,12 @@ patch_qwt() { ###################################################################### --- a/src/src.pro +++ b/src/src.pro -@@ -30,7 +30,8 @@ contains(QWT_CONFIG, QwtDll) { - - # we increase the SONAME for every minor number - -- QWT_SONAME=libqwt.so.\$\${VER_MAJ}.\$\${VER_MIN} -+ !macx: QWT_SONAME=libqwt.so.\$\${VER_MAJ}.\$\${VER_MIN} -+ macx: QWT_SONAME=\$\${QWT_INSTALL_LIBS}/libqwt.dylib - QMAKE_LFLAGS *= \$\${QMAKE_LFLAGS_SONAME}\$\${QWT_SONAME} - QMAKE_LFLAGS_SONAME= +@@ -36,6 +36,7 @@ contains(QWT_CONFIG, QwtDll) { + QMAKE_LFLAGS_SONAME= + } } -EOF -} - -patch_qwtpolar() { - patch -p1 < ${WORKDIR}/projects/scopy/CI/appveyor/patches/qwtpolar-qwt-qt-compat.patch - - patch -p1 <<-EOF ---- a/qwtpolarconfig.pri -+++ b/qwtpolarconfig.pri -@@ -70,14 +72,14 @@ QWT_POLAR_INSTALL_FEATURES = \$\${QWT_POLAR_INSTALL_PREFIX}/features - # Otherwise you have to build it from the designer directory. - ###################################################################### - --QWT_POLAR_CONFIG += QwtPolarDesigner -+#QWT_POLAR_CONFIG += QwtPolarDesigner - - ###################################################################### - # If you want to auto build the examples, enable the line below - # Otherwise you have to build them from the examples directory. - ###################################################################### - --QWT_POLAR_CONFIG += QwtPolarExamples -+#QWT_POLAR_CONFIG += QwtPolarExamples - - ###################################################################### - # When Qt has been built as framework qmake wants -@@ -86,6 +88,6 @@ QWT_POLAR_CONFIG += QwtPolarExamples - - macx:CONFIG(qt_framework, qt_framework|qt_no_framework) { - -- QWT_POLAR_CONFIG += QwtPolarFramework -+ #QWT_POLAR_CONFIG += QwtPolarFramework ++ macx: QWT_SONAME=\$\${QWT_INSTALL_LIBS}/libqwt.dylib } - EOF } + diff --git a/CI/appveyor/build_appveyor_macos.sh b/CI/appveyor/build_appveyor_macos.sh index 09f7a3c71f..eaea792395 100755 --- a/CI/appveyor/build_appveyor_macos.sh +++ b/CI/appveyor/build_appveyor_macos.sh @@ -1,5 +1,6 @@ #!/bin/bash set -e +STAGINGDIR="${PWD}/staging" # Use the /usr/local/bin/pkg-config instead of /Mono/../pkg-config export PATH="/usr/local/bin:$PATH" @@ -15,22 +16,17 @@ if command -v brew ; then fi NUM_JOBS=4 - 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" .. - CFLAGS=-I${STAGINGDIR}/include LDFLAGS=-L${STAGINGDIR}/lib make -j${NUM_JOBS} +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 -DCMAKE_STAGING_PREFIX="${STAGINGDIR}" \ + -DCMAKE_PREFIX_PATH="${STAGINGDIR};${STAGINGDIR}/lib/cmake;${STAGINGDIR}/lib/pkgconfig;${STAGINGDIR}/lib/cmake/gnuradio;${STAGINGDIR}/lib/cmake/iio;${QT_PATH}/lib/cmake" \ + -DCMAKE_INSTALL_PREFIX="${STAGINGDIR}" \ + -DCMAKE_EXE_LINKER_FLAGS="-L${STAGINGDIR}/lib" .. +CFLAGS=-I${STAGINGDIR}/include LDFLAGS=-L${STAGINGDIR}/lib make -j${NUM_JOBS} +otool -l ./Scopy.app/Contents/MacOS/Scopy \ No newline at end of file diff --git a/CI/appveyor/build_scopy_apk.sh b/CI/appveyor/build_scopy_apk.sh new file mode 100755 index 0000000000..93db40bf9c --- /dev/null +++ b/CI/appveyor/build_scopy_apk.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -xe +source ./android_toolchain.sh $1 $2 + +ARTIFACT_LOCATION=$GITHUB_WORKSPACE +BUILD_FOLDER=build_${ABI}_${BUILD_TYPE} + +build_scopy() { + + git clone https://github.com/analogdevicesinc/scopy.git + pushd scopy + git submodule update --init --recursive iio-emu + + git fetch origin $BRANCH + git checkout FETCH_HEAD + + rm -rf build* + + cp $BUILD_ROOT/android_cmake.sh . + cp $SCRIPT_HOME_DIR/android_deploy_qt.sh . + + ./android_cmake.sh . + + cd $BUILD_FOLDER + make -j$JOBS + cd .. + + ./android_deploy_qt.sh + cd $BUILD_FOLDER + make apk + make aab + cd .. + + popd +} + +move_artifact() { + pushd scopy + sudo cp ./$BUILD_FOLDER/android-build/build/outputs/apk/debug/android-build-debug.apk $ARTIFACT_LOCATION/ + sudo cp ./$BUILD_FOLDER/android-build/build/outputs/bundle/debug/android-build-debug.aab $ARTIFACT_LOCATION/ + sudo cp ./$BUILD_FOLDER/android-build/build/outputs/bundle/release/android-build-release.aab $ARTIFACT_LOCATION/ + pushd $ARTIFACT_LOCATION + sudo chmod 644 ./android-build-debug.apk + sudo chmod 644 ./android-build-debug.aab + sudo chmod 644 ./android-build-release.aab + ls -la $ARTIFACT_LOCATION + popd + + popd +} + +build_scopy +move_artifact diff --git a/CI/appveyor/data b/CI/appveyor/data deleted file mode 100644 index 2c37c2a94b..0000000000 --- a/CI/appveyor/data +++ /dev/null @@ -1 +0,0 @@ -vineri 26 martie 2021, 13:48:33 +0200 diff --git a/CI/appveyor/docker/Dockerfile b/CI/appveyor/docker/Dockerfile deleted file mode 100644 index 640fa68604..0000000000 --- a/CI/appveyor/docker/Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -FROM ubuntu:20.04 -ENV TZ=Europe/Bucharest -RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone - -RUN apt-get update -y - -# Install base dependencies -RUN apt-get install -y software-properties-common build-essential git sudo apt-utils subversion - -# Install flatpak -RUN add-apt-repository ppa:alexlarsson/flatpak -y -RUN apt-get update -y -RUN apt install flatpak flatpak-builder -y - -# Install remote -RUN flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo -RUN flatpak install flathub org.kde.Platform//5.15 -y -RUN flatpak install flathub org.kde.Sdk//5.15 -y - -# Clean -RUN apt-get clean -y && apt-get autoclean -y - -RUN echo Cloning scopy-flatpak -ARG REPO_LINK=https://github.com/analogdevicesinc/scopy-flatpak -ARG REPO_LOCAL=/home/docker/scopy-flatpak -ARG REPO_BRANCH=master - -RUN git clone --recurse-submodules "$REPO_LINK" -b "$REPO_BRANCH" "$REPO_LOCAL" 2> /dev/null || (cd "$REPO_LOCAL"; git pull) - -#RUN cd /home/docker/scopy-flatpak && make -j4 -CMD ["/bin/bash"] - diff --git a/CI/appveyor/docker/README b/CI/appveyor/docker/README deleted file mode 100644 index 4e9a665fdd..0000000000 --- a/CI/appveyor/docker/README +++ /dev/null @@ -1,11 +0,0 @@ -KDE Runtime Docker image based on Ubuntu 18.04 - -The provided Dockerfile will install the KDE Runtime over the Ubuntu 18.04 base image. -Also, the obtained Docker image will contain the clone of https://github.com/analogdevicesinc/scopy-flatpak the scopy-flatpak recipe repository which can be found at /home/docker/scopy-flatpak - -In order to build the Flatpak package for Scopy inside this Docker image, it needs to be run using "--privileged" (otherwise there is a lack of access to necessary utilities). - -We built Scopy Flatpak in this image, then saved the newly created image as alexandratr/scopy-flatpak-bionic:scopy on Dockerhub. However, a clean image (without the Scopy Flatpak build) can be found as alexandratr/scopy-flatpak-bionic:clean on Dockerhub. - -Running make inside the scopy-flatpak folder will build the Scopy.flatpak artifact. An example of how to do this is illustrated in the "build_appveyor_flatpak.sh" and "inside_flatpak_docker.sh" scripts (which deploys a Scopy.flatpak for each Appveyor nightly build). - diff --git a/CI/appveyor/inside_mingw_docker.sh b/CI/appveyor/inside_mingw_docker.sh new file mode 100644 index 0000000000..c319b75848 --- /dev/null +++ b/CI/appveyor/inside_mingw_docker.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +set -x + + +TOOLS_FOLDER=$HOME/scopy-mingw-build-deps +pushd $TOOLS_FOLDER +source ./mingw_toolchain.sh $BUILD_TARGET +popd + +WORKDIR=$HOME +SRC_FOLDER=$WORKDIR/scopy +DEST_FOLDER=$WORKDIR/scopy_$ARCH +BUILD_FOLDER=$WORKDIR/build_$ARCH +DEBUG_FOLDER=$WORKDIR/debug_$ARCH +ARTIFACT_FOLDER=$WORKDIR/artifact_$ARCH +PYTHON_FILES=/$MINGW_VERSION/lib/python3.* +DLL_DEPS=$(cat $SRC_FOLDER/CI/appveyor/mingw_dll_deps) + + + +echo "### Building Scopy " +mkdir -p $BUILD_FOLDER +cd $BUILD_FOLDER +$CMAKE $RC_COMPILER_OPT -DBREAKPAD_HANDLER=ON -DWITH_DOC=ON -DPYTHON_EXECUTABLE=/$MINGW_VERSION/bin/python3.exe $SRC_FOLDER +$MAKE_BIN -j 4 + + +echo "### Deploying application and dependencies" +mkdir $DEST_FOLDER +cp $BUILD_FOLDER/Scopy.exe $DEST_FOLDER/ +cp $BUILD_FOLDER/qt.conf $DEST_FOLDER/ +mkdir $DEST_FOLDER/resources + +cp $BUILD_FOLDER/iio-emu/iio-emu.exe $DEST_FOLDER/ + +# windeployqt was broken in qt version 5.14.2 - it should be fixed in Qt 5.15 - https://bugreports.qt.io/browse/QTBUG-80763 +$STAGING/$MINGW_VERSION/bin/windeployqt.exe --dir $DEST_FOLDER --no-system-d3d-compiler --no-compiler-runtime --no-quick-import --opengl --printsupport $BUILD_FOLDER/Scopy.exe +cp -r $STAGING/$MINGW_VERSION/share/libsigrokdecode/decoders $DEST_FOLDER/ + +#tar -C /c/$DEST_FOLDER --strip-components=3 -xJf /c/scopy-$MINGW_VERSION-build-deps.tar.xz msys64/$MINGW_VERSION/bin +cd /$MINGW_VERSION/bin +cp -r -n $DLL_DEPS $DEST_FOLDER/ +cd $STAGING/$MINGW_VERSION/bin +cp -r $DLL_DEPS $DEST_FOLDER/ +cp -r $PYTHON_FILES $DEST_FOLDER + + +echo "### Extracting debug symbols ..." +mkdir -p $DEST_FOLDER/.debug +#/$MINGW_VERSION/bin/objcopy -v --only-keep-debug /c/$DEST_FOLDER/Scopy.exe /c/$DEST_FOLDER/.debug/Scopy.exe.debug +$STAGING/$MINGW_VERSION/bin/dump_syms -r $DEST_FOLDER/Scopy.exe > $DEST_FOLDER/Scopy.exe.sym +#/c/msys64/$MINGW_VERSION/bin/strip.exe --strip-debug --strip-unneeded /c/$DEST_FOLDER/Scopy.exe +#/c/msys64/$MINGW_VERSION/bin/strip.exe --strip-debug --strip-unneeded /c/$DEST_FOLDER/*.dll +#/c/msys64/$MINGW_VERSION/bin/objcopy.exe -v --add-gnu-debuglink=/c/$DEST_FOLDER/.debug/Scopy.exe.debug /c/$DEST_FOLDER/Scopy.exe +mkdir $DEBUG_FOLDER +mv $DEST_FOLDER/Scopy.exe.sym $DEBUG_FOLDER +mv $DEST_FOLDER/.debug $DEBUG_FOLDER +$TOOLS_FOLDER/cv2pdb/cv2pdb $DEST_FOLDER/Scopy.exe +$TOOLS_FOLDER/cv2pdb/cv2pdb $DEST_FOLDER/libm2k.dll +$TOOLS_FOLDER/cv2pdb/cv2pdb $DEST_FOLDER/libiio.dll +$TOOLS_FOLDER/cv2pdb/cv2pdb $DEST_FOLDER/libgnuradio-m2k.dll +$TOOLS_FOLDER/cv2pdb/cv2pdb $DEST_FOLDER/libgnuradio-scopy.dll +cp -R $DEST_FOLDER/scopy $DEBUG_FOLDER/scopy +mv $DEST_FOLDER/*.pdb $DEBUG_FOLDER + +echo "### Bundling drivers" +cp -R $SRC_FOLDER/drivers $DEST_FOLDER +if [[ $ARCH_BIT == "64" ]]; then + cp -R $TOOLS_FOLDER/dfu-util-static-amd64.exe $DEST_FOLDER/drivers/dfu-util.exe + cp -R $TOOLS_FOLDER/dpinst_amd64.exe $DEST_FOLDER/drivers/dpinst.exe +else + cp -R $TOOLS_FOLDER/dfu-util-static.exe $DEST_FOLDER/drivers/dfu-util.exe + cp -R $TOOLS_FOLDER/dpinst.exe $DEST_FOLDER/drivers/dpinst.exe +fi + + +echo "### Creating archives & installer... " +mkdir -p $ARTIFACT_FOLDER +cd $WORKDIR +zip -r "$ARTIFACT_FOLDER/scopy-${ARCH}.zip" scopy_$ARCH +zip -r "$ARTIFACT_FOLDER/debug-${ARCH}.zip" debug_$ARCH +PATH=/c/innosetup:$PATH +iscc //p $BUILD_FOLDER/scopy-$ARCH_BIT.iss +mv $WORKDIR/scopy-$ARCH_BIT-setup.exe $ARTIFACT_FOLDER + +echo "Done. Artifacts generated in $ARTIFACT_FOLDER" +ls -la $ARTIFACT_FOLDER +echo $GITHUB_WORKSPACE +cp -R $ARTIFACT_FOLDER $SRC_FOLDER +ls -la $SRC_FOLDER diff --git a/CI/appveyor/install_macos_deps.sh b/CI/appveyor/install_macos_deps.sh index fa7ccc56e3..68c87f78a4 100755 --- a/CI/appveyor/install_macos_deps.sh +++ b/CI/appveyor/install_macos_deps.sh @@ -1,6 +1,6 @@ #!/bin/bash -LIBIIO_VERSION=v0.21 +LIBIIO_VERSION=0ed18cd8f6b2fac5204a99e38922bea73f1f778c LIBAD9361_BRANCH=master LIBM2K_BRANCH=master GRIIO_BRANCH=upgrade-3.8 @@ -8,39 +8,21 @@ GNURADIO_FORK=analogdevicesinc GNURADIO_BRANCH=scopy GRSCOPY_BRANCH=master GRM2K_BRANCH=master -QWT_BRANCH=qwt-6.1-multiaxes -QWTPOLAR_BRANCH=master # not used -LIBSIGROK_BRANCH=master +QWT_BRANCH=qwt-multiaxes 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=" ${QT_FORMULAE} boost pkg-config cmake fftw bison gettext autoconf automake libtool libzip glib libusb glog $PYTHON" PACKAGES="$PACKAGES doxygen wget gnu-sed libmatio dylibbundler libxml2 ghr" set -e -cd ~ +REPO_SRC=$BUILD_REPOSITORY_LOCALPATH WORKDIR=${PWD} -NUM_JOBS=4 +JOBS=4 -brew update brew search ${QT_FORMULAE} -brew_install_or_upgrade() { - brew install $1 || \ - brew upgrade $1 || \ - brew ls --versions $1 # check if installed last-ly -} - -brew_install() { - brew install $1 || \ - brew ls --versions $1 -} - -for pak in $PACKAGES ; do - brew_install $pak -done +brew install $PACKAGES for pkg in gcc bison gettext cmake python; do brew link --overwrite --force $pkg @@ -49,7 +31,7 @@ done pip3 install mako six pwd -source ./projects/scopy/CI/appveyor/before_install_lib.sh +source ${REPO_SRC}/CI/appveyor/before_install_lib.sh QT_PATH="$(brew --prefix ${QT_FORMULAE})/bin" @@ -58,6 +40,7 @@ export PATH="/usr/local/opt/bison/bin:$PATH" export PATH="${QT_PATH}:$PATH" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libzip/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libffi/lib/pkgconfig" +export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$STAGINGDIR/lib/pkgconfig" echo $PKG_CONFIG_PATH QMAKE="$(command -v qmake)" @@ -67,7 +50,6 @@ CMAKE_OPTS="-DCMAKE_PREFIX_PATH=$STAGINGDIR -DCMAKE_INSTALL_PREFIX=$STAGINGDIR" build_libiio() { echo "### Building libiio - version $LIBIIO_VERSION" - cd ~ git clone https://github.com/analogdevicesinc/libiio.git ${WORKDIR}/libiio cd ${WORKDIR}/libiio git checkout $LIBIIO_VERSION @@ -79,20 +61,20 @@ build_libiio() { -DWITH_TESTS:BOOL=OFF \ -DWITH_DOC:BOOL=OFF \ -DWITH_MATLAB_BINDINGS:BOOL=OFF \ + -DENABLE_DNS_SD:BOOL=OFF\ -DCSHARP_BINDINGS:BOOL=OFF \ -DPYTHON_BINDINGS:BOOL=OFF \ -DOSX_PACKAGE:BOOL=OFF \ ${WORKDIR}/libiio - make $JOBS - sudo make ${JOBS} install + make -j $JOBS + sudo make -j ${JOBS} install } build_libm2k() { echo "### Building libm2k - branch $LIBM2K_BRANCH" - cd ~ git clone --depth 1 https://github.com/analogdevicesinc/libm2k.git -b $LIBM2K_BRANCH ${WORKDIR}/libm2k mkdir ${WORKDIR}/libm2k/build-${ARCH} @@ -107,14 +89,13 @@ build_libm2k() { -DENABLE_LOG=ON\ ${WORKDIR}/libm2k - make $JOBS - sudo make ${JOBS} install + make -j $JOBS + sudo make -j ${JOBS} install } build_libad9361() { echo "### Building libad9361 - branch $LIBAD9361_BRANCH" - cd ~ git clone --depth 1 https://github.com/analogdevicesinc/libad9361-iio.git -b $LIBAD9361_BRANCH ${WORKDIR}/libad9361 mkdir ${WORKDIR}/libad9361/build-${ARCH} @@ -123,42 +104,29 @@ build_libad9361() { cmake ${CMAKE_OPTS} \ ${WORKDIR}/libad9361 - make $JOBS - sudo make $JOBS install - #DESTDIR=${WORKDIR} make $JOBS install + make -j $JOBS + sudo make -j $JOBS install } build_log4cpp() { + cd ${WORKDIR} wget https://sourceforge.net/projects/log4cpp/files/latest/log4cpp-1.1.3.tar.gz tar xvzf log4cpp-1.1.3.tar.gz cd log4cpp ./configure --prefix=/usr/local/ - make $JOBS - sudo make install -} - -build_boost() { - echo "### Building boost - version $BOOST_VERSION_FILE" - - cd ~ - 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 - ./bootstrap.sh --with-libraries=atomic,date_time,filesystem,program_options,system,chrono,thread,regex,test - ./b2 - ./b2 install + make -j $JOBS + sudo make -j ${JOBS} install } build_gnuradio() { echo "### Building gnuradio - branch $GNURADIO_BRANCH" - cd ~ - git clone --recurse-submodules https://github.com/$GNURADIO_FORK/gnuradio -b $GNURADIO_BRANCH + git clone --recurse-submodules https://github.com/$GNURADIO_FORK/gnuradio -b $GNURADIO_BRANCH ${WORKDIR}/gnuradio mkdir ${WORKDIR}/gnuradio/build-${ARCH} cd ${WORKDIR}/gnuradio/build-${ARCH} - cmake -DENABLE_GR_DIGITAL:BOOL=OFF \ + cmake ${CMAKE_OPTS} \ + -DENABLE_GR_DIGITAL:BOOL=OFF \ -DENABLE_GR_DTV:BOOL=OFF \ -DENABLE_GR_AUDIO:BOOL=OFF \ -DENABLE_GR_CHANNELS:BOOL=OFF \ @@ -169,75 +137,84 @@ build_gnuradio() { -DENABLE_SPHINX:BOOL=OFF \ -DENABLE_DOXYGEN:BOOL=OFF \ -DENABLE_INTERNAL_VOLK=ON \ + -DENABLE_PYTHON=OFF \ + -DENABLE_TESTING=OFF \ + -DENABLE_GR_CHANNELS=OFF \ + -DENABLE_GR_VOCODER=OFF \ + -DENABLE_GR_TRELLIS=OFF \ + -DENABLE_GR_WAVELET=OFF \ + -DENABLE_GR_CTRLPORT=OFF \ + -DENABLE_CTRLPORT_THRIFT=OFF \ -DCMAKE_C_FLAGS=-fno-asynchronous-unwind-tables \ ${WORKDIR}/gnuradio - make $JOBS - sudo make install + make -j $JOBS + sudo make -j $JOBS install } build_griio() { echo "### Building gr-iio - branch $GRIIO_BRANCH" - cd ~ git clone --depth 1 https://github.com/analogdevicesinc/gr-iio.git -b $GRIIO_BRANCH ${WORKDIR}/gr-iio mkdir ${WORKDIR}/gr-iio/build-${ARCH} cd ${WORKDIR}/gr-iio/build-${ARCH} cmake ${CMAKE_OPTS} \ + -DWITH_PYTHON=OFF \ ${WORKDIR}/gr-iio - make $JOBS - sudo make $JOBS install + make -j $JOBS + sudo make -j $JOBS install } build_grm2k() { echo "### Building gr-m2k - branch $GRM2K_BRANCH" - cd ~ git clone --depth 1 https://github.com/analogdevicesinc/gr-m2k.git -b $GRM2K_BRANCH ${WORKDIR}/gr-m2k mkdir ${WORKDIR}/gr-m2k/build-${ARCH} cd ${WORKDIR}/gr-m2k/build-${ARCH} cmake ${CMAKE_OPTS} \ + -DWITH_PYTHON=OFF \ ${WORKDIR}/gr-m2k - make $JOBS - sudo make $JOBS install + make -j $JOBS + sudo make -j $JOBS install } build_grscopy() { echo "### Building gr-scopy - branch $GRSCOPY_BRANCH" - cd ~ + git clone --depth 1 https://github.com/analogdevicesinc/gr-scopy.git -b $GRSCOPY_BRANCH ${WORKDIR}/gr-scopy mkdir ${WORKDIR}/gr-scopy/build-${ARCH} cd ${WORKDIR}/gr-scopy/build-${ARCH} cmake ${CMAKE_OPTS} \ + -DWITH_PYTHON=OFF \ ${WORKDIR}/gr-scopy - make $JOBS - sudo make $JOBS install + make -j $JOBS + sudo make -j $JOBS install } build_glibmm() { echo "### Building glibmm - 2.64.0" - cd ~ + cd ${WORKDIR} wget http://ftp.acc.umu.se/pub/gnome/sources/glibmm/2.64/glibmm-2.64.0.tar.xz tar xzvf glibmm-2.64.0.tar.xz cd glibmm-2.64.0 - ./configure - make $JOBS - sudo make $JOBS install + ./configure --prefix=$STAGINGDIR + make -j $JOBS + sudo make -j $JOBS install } build_sigcpp() { echo "### Building libsigc++ -2.10.0" - cd ~ + cd ${WORKDIR} wget http://ftp.acc.umu.se/pub/GNOME/sources/libsigc++/2.10/libsigc++-2.10.0.tar.xz tar xvzf libsigc++-2.10.0.tar.xz cd libsigc++-2.10.0 - ./configure - make $JOBS - sudo make $JOBS install + ./configure --prefix=$STAGINGDIR + make -j $JOBS + sudo make -j $JOBS install } build_libsigrokdecode() { @@ -247,46 +224,20 @@ build_libsigrokdecode() { cd ${WORKDIR}/libsigrokdecode ./autogen.sh - ./configure + ./configure --prefix=$STAGINGDIR - sudo make $JOBS install -} - - -patch_qwtpolar_mac() { - patch_qwtpolar - - patch -p1 <<-EOF ---- a/qwtpolarconfig.pri -+++ 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 + sudo make -j $JOBS install } build_qwt() { - echo "### Building qwt - branch qwt-6.1-multiaxes" - svn checkout https://svn.code.sf.net/p/qwt/code/branches/$QWT_BRANCH ${WORKDIR}/qwt + echo "### Building qwt - branch qwt-multiaxes" + git clone --depth 1 https://github.com/cseci/qwt -b $QWT_BRANCH ${WORKDIR}/qwt qmake_build_local "qwt" "qwt.pro" "patch_qwt" } -build_qwtpolar() { - qmake_build_wget "qwtpolar-1.1.1" "https://downloads.sourceforge.net/project/qwtpolar/qwtpolar/1.1.1/qwtpolar-1.1.1.tar.bz2" "qwtpolar.pro" "patch_qwtpolar_mac" -} - build_libtinyiiod() { echo "### Building libtinyiiod - branch $LIBTINYIIOD_BRANCH" - cd ~ git clone --depth 1 https://github.com/analogdevicesinc/libtinyiiod.git -b $LIBTINYIIOD_BRANCH ${WORKDIR}/libtinyiiod mkdir ${WORKDIR}/libtinyiiod/build-${ARCH} cd ${WORKDIR}/libtinyiiod/build-${ARCH} @@ -295,8 +246,8 @@ build_libtinyiiod() { -DBUILD_EXAMPLES=OFF \ ${WORKDIR}/libtinyiiod - make $JOBS - sudo make $JOBS install + make -j $JOBS + sudo make -j $JOBS install } build_sigcpp @@ -305,12 +256,10 @@ build_libiio build_libad9361 build_libm2k build_log4cpp -build_boost build_gnuradio build_griio build_grscopy build_grm2k build_qwt -build_qwtpolar build_libsigrokdecode build_libtinyiiod diff --git a/CI/appveyor/install_qt_ubuntu_20.sh b/CI/appveyor/install_qt_ubuntu_20.sh index c31e693a32..1a62f461d9 100755 --- a/CI/appveyor/install_qt_ubuntu_20.sh +++ b/CI/appveyor/install_qt_ubuntu_20.sh @@ -1,2 +1,2 @@ #!/bin/bash -sudo apt-get -y install vim git cmake qt5-default qtcreator qtdeclarative5-dev qtdeclarative5-dev-tools libqt5svg5 libqt5svg5-devqttools5-dev qttools5-dev-tools +sudo apt-get -y install vim git cmake qt5-default qtcreator qtdeclarative5-dev qtdeclarative5-dev-tools libqt5svg5 libqt5svg5-dev qttools5-dev qttools5-dev-tools libqt5opengl5 diff --git a/CI/appveyor/install_ubuntu_18_deps.sh b/CI/appveyor/install_ubuntu_18_deps.sh index d513acb8b3..ecbcefa2aa 100755 --- a/CI/appveyor/install_ubuntu_18_deps.sh +++ b/CI/appveyor/install_ubuntu_18_deps.sh @@ -1,16 +1,15 @@ #!/bin/bash -LIBIIO_VERSION=v0.21 +LIBIIO_VERSION=0ed18cd8f6b2fac5204a99e38922bea73f1f778c LIBAD9361_BRANCH=master GLOG_BRANCH=v0.4.0 LIBM2K_BRANCH=master GRIIO_BRANCH=upgrade-3.8 GNURADIO_FORK=analogdevicesinc -GNURADIO_BRANCH=ming-3.8-clean +GNURADIO_BRANCH=scopy GRSCOPY_BRANCH=master GRM2K_BRANCH=master -QWT_BRANCH=qwt-6.1-multiaxes -QWTPOLAR_BRANCH=master # not used +QWT_BRANCH=qwt-multiaxes LIBSIGROK_BRANCH=master LIBSIGROKDECODE_BRANCH=master LIBTINYIIOD_BRANCH=master @@ -38,7 +37,7 @@ install_apt() { sudo cp -a doxygen-1.8.17/bin/doxy* /usr/local/bin doxygen --version - sudo apt-get -y install build-essential libxml2-dev libxml2 flex bison swig libpython3-all-dev python3 python3-numpy libfftw3-bin libfftw3-dev libfftw3-3 liblog4cpp5v5 liblog4cpp5-dev libboost1.65-dev libboost1.65 g++ git cmake autoconf libzip4 libzip-dev libglib2.0-dev libsigc++-2.0-dev libglibmm-2.4-dev curl libvolk1-bin libvolk1-dev libvolk1.3 libgmp-dev libmatio-dev liborc-0.4-dev subversion mesa-common-dev libgl1-mesa-dev + sudo apt-get -y install build-essential libxml2-dev libxml2 flex bison swig libpython3-all-dev python3 python3-numpy libfftw3-bin libfftw3-dev libfftw3-3 liblog4cpp5v5 liblog4cpp5-dev libboost1.65-dev libboost1.65 g++ git cmake autoconf libzip4 libzip-dev libglib2.0-dev libsigc++-2.0-dev libglibmm-2.4-dev curl libvolk1-bin libvolk1-dev libvolk1.3 libgmp-dev libmatio-dev liborc-0.4-dev subversion mesa-common-dev libgl1-mesa-dev libserialport0 libserialport-dev libusb-1.0 libusb-1.0-0 libusb-1.0-0-dev libaio-dev sudo apt-get -y update sudo apt-get -y install gnuradio @@ -59,6 +58,7 @@ build_libiio() { cmake ${CMAKE_OPTS} \ -DWITH_TESTS:BOOL=OFF \ -DWITH_DOC:BOOL=OFF \ + -DHAVE_DNS_SD:BOOL=OFF\ -DWITH_MATLAB_BINDINGS:BOOL=OFF \ -DCSHARP_BINDINGS:BOOL=OFF \ -DPYTHON_BINDINGS:BOOL=OFF \ @@ -213,42 +213,14 @@ build_libsigrokdecode() { build_qwt() { echo "### Building qwt - branch $QWT_BRANCH" - svn checkout https://svn.code.sf.net/p/qwt/code/branches/$QWT_BRANCH ${WORKDIR}/qwt + git clone https://github.com/cseci/qwt --branch $QWT_BRANCH ${WORKDIR}/qwt cd ${WORKDIR}/qwt - # Disable components that we won't build - sed -i "s/^QWT_CONFIG\\s*+=\\s*QwtTests$/#/g" qwtconfig.pri - sed -i "s/^QWT_CONFIG\\s*+=\\s*QwtDesigner$/#/g" qwtconfig.pri - sed -i "s/^QWT_CONFIG\\s*+=\\s*QwtExamples$/#/g" qwtconfig.pri - - # Fix prefix - sed -i 's/\/usr\/local\/qwt-$$QWT_VERSION-svn/\/usr\/local/g' qwtconfig.pri - $QMAKE qwt.pro make $JOBS sudo make install } -build_qwtpolar() { - echo "### Building qwtpolar - branch $QWTPOLAR_BRANCH" - mkdir -p ${WORKDIR}/qwtpolar - cd ${WORKDIR}/qwtpolar - - wget https://downloads.sourceforge.net/project/qwtpolar/qwtpolar/1.1.1/qwtpolar-1.1.1.tar.bz2 -O- \ - | tar xj --strip-components=1 -C ${WORKDIR}/qwtpolar - - cd ~/qwtpolar - wget https://raw.githubusercontent.com/analogdevicesinc/scopy/master/CI/appveyor/patches/qwtpolar-qwt-qt-compat.patch - patch -p1 < qwtpolar-qwt-qt-compat.patch - sed -i 's/\/usr\/local\/qwtpolar-$$QWT_POLAR_VERSION/\/usr\/local/g' qwtpolarconfig.pri - sed -i 's/QWT_POLAR_CONFIG += QwtPolarExamples/ /g' qwtpolarconfig.pri - sed -i 's/QWT_POLAR_CONFIG += QwtPolarDesigner/ /g' qwtpolarconfig.pri - $QMAKE qwtpolar.pro - make $JOBS - sudo make install - -} - build_libtinyiiod() { echo "### Building libtinyiiod - branch $LIBTINYIIOD_BRANCH" @@ -274,7 +246,5 @@ build_griio build_grscopy build_grm2k build_qwt -build_qwtpolar -#build_libsigrok build_libsigrokdecode build_libtinyiiod diff --git a/CI/appveyor/install_ubuntu_20_deps.sh b/CI/appveyor/install_ubuntu_20_deps.sh index 28de313c84..dd96442b40 100755 --- a/CI/appveyor/install_ubuntu_20_deps.sh +++ b/CI/appveyor/install_ubuntu_20_deps.sh @@ -1,16 +1,15 @@ #!/bin/bash -LIBIIO_VERSION=v0.21 +LIBIIO_VERSION=0ed18cd8f6b2fac5204a99e38922bea73f1f778c LIBAD9361_BRANCH=master GLOG_BRANCH=v0.4.0 LIBM2K_BRANCH=master GRIIO_BRANCH=upgrade-3.8 GNURADIO_FORK=analogdevicesinc -GNURADIO_BRANCH=ming-3.8-clean +GNURADIO_BRANCH=scopy GRSCOPY_BRANCH=master GRM2K_BRANCH=master -QWT_BRANCH=qwt-6.1-multiaxes -QWTPOLAR_BRANCH=master # not used +QWT_BRANCH=qwt-multiaxes LIBSIGROK_BRANCH=master LIBSIGROKDECODE_BRANCH=master LIBTINYIIOD_BRANCH=master @@ -31,7 +30,7 @@ WORKDIR=${PWD} install_apt() { - sudo apt-get -y install libxml2-dev libxml2 flex bison swig libpython3-all-dev python3 python3-numpy libfftw3-bin libfftw3-dev libfftw3-3 liblog4cpp5v5 liblog4cpp5-dev g++ git cmake autoconf libzip5 libzip-dev libglib2.0-dev libsigc++-2.0-dev libglibmm-2.4-dev libclang1-9 doxygen curl libmatio-dev liborc-0.4-dev subversion mesa-common-dev libgl1-mesa-dev gnuradio libserialport0 libserialport-dev libusb-1.0 libusb-1.0-0 libusb-1.0-0-dev + sudo apt-get -y install libxml2-dev libxml2 flex bison swig libpython3-all-dev python3 python3-numpy libfftw3-bin libfftw3-dev libfftw3-3 liblog4cpp5v5 liblog4cpp5-dev g++ git cmake autoconf libzip5 libzip-dev libglib2.0-dev libsigc++-2.0-dev libglibmm-2.4-dev libclang1-9 doxygen curl libmatio-dev liborc-0.4-dev subversion mesa-common-dev libgl1-mesa-dev gnuradio libserialport0 libserialport-dev libusb-1.0 libusb-1.0-0 libusb-1.0-0-dev libtool libaio-dev } @@ -50,6 +49,7 @@ build_libiio() { cmake ${CMAKE_OPTS} \ -DWITH_TESTS:BOOL=OFF \ -DWITH_DOC:BOOL=OFF \ + -DHAVE_DNS_SD:BOOL=OFF\ -DWITH_MATLAB_BINDINGS:BOOL=OFF \ -DCSHARP_BINDINGS:BOOL=OFF \ -DPYTHON_BINDINGS:BOOL=OFF \ @@ -92,7 +92,7 @@ build_libm2k() { cmake ${CMAKE_OPTS} \ -DENABLE_PYTHON=OFF\ -DENABLE_CSHARP=OFF\ - -DENABLE_EXAMPLES=OFF\ + -DBUILD_EXAMPLES=OFF\ -DENABLE_TOOLS=OFF\ -DINSTALL_UDEV_RULES=OFF\ -DENABLE_LOG=ON\ @@ -204,42 +204,14 @@ build_libsigrokdecode() { build_qwt() { echo "### Building qwt - branch $QWT_BRANCH" - svn checkout https://svn.code.sf.net/p/qwt/code/branches/$QWT_BRANCH ${WORKDIR}/qwt + git clone https://github.com/cseci/qwt --branch $QWT_BRANCH ${WORKDIR}/qwt cd ${WORKDIR}/qwt - # Disable components that we won't build - sed -i "s/^QWT_CONFIG\\s*+=\\s*QwtTests$/#/g" qwtconfig.pri - sed -i "s/^QWT_CONFIG\\s*+=\\s*QwtDesigner$/#/g" qwtconfig.pri - sed -i "s/^QWT_CONFIG\\s*+=\\s*QwtExamples$/#/g" qwtconfig.pri - - # Fix prefix - sed -i 's/\/usr\/local\/qwt-$$QWT_VERSION-svn/\/usr\/local/g' qwtconfig.pri - $QMAKE qwt.pro make $JOBS sudo make install } -build_qwtpolar() { - echo "### Building qwtpolar - branch $QWTPOLAR_BRANCH" - mkdir -p ${WORKDIR}/qwtpolar - cd ${WORKDIR}/qwtpolar - - wget https://downloads.sourceforge.net/project/qwtpolar/qwtpolar/1.1.1/qwtpolar-1.1.1.tar.bz2 -O- \ - | tar xj --strip-components=1 -C ${WORKDIR}/qwtpolar - - cd ~/qwtpolar - wget https://raw.githubusercontent.com/analogdevicesinc/scopy/master/CI/appveyor/patches/qwtpolar-qwt-qt-compat.patch - patch -p1 < qwtpolar-qwt-qt-compat.patch - sed -i 's/\/usr\/local\/qwtpolar-$$QWT_POLAR_VERSION/\/usr\/local/g' qwtpolarconfig.pri - sed -i 's/QWT_POLAR_CONFIG += QwtPolarExamples/ /g' qwtpolarconfig.pri - sed -i 's/QWT_POLAR_CONFIG += QwtPolarDesigner/ /g' qwtpolarconfig.pri - $QMAKE qwtpolar.pro - make $JOBS - sudo make install - -} - build_libtinyiiod() { echo "### Building libtinyiiod - branch $LIBTINYIIOD_BRANCH" @@ -265,7 +237,5 @@ build_griio build_grscopy build_grm2k build_qwt -build_qwtpolar -#build_libsigrok build_libsigrokdecode build_libtinyiiod diff --git a/CI/appveyor/mingw_dll_deps b/CI/appveyor/mingw_dll_deps index 7c3be1c6dc..baf925587c 100644 --- a/CI/appveyor/mingw_dll_deps +++ b/CI/appveyor/mingw_dll_deps @@ -1 +1 @@ -libglibmm-*.dll libsigrokdecode-*.dll libgcc_s_*.dll libstdc++-*.dll Qt5Core.dll libboost_thread-mt.dll libgnuradio-analog.dll libgnuradio-blocks.dll libgnuradio-fft.dll libwinpthread-*.dll libgnuradio-filter.dll libgnuradio-m2k.dll libgnuradio-pmt.dll libgnuradio-runtime.dll libgnuradio-scopy.dll libiio.dll Qt5Qml.dll Qt5Xml.dll qwt.dll qwtpolar.dll libglib-*.dll libgmodule-*.dll libsigc-*.dll libgobject-*.dll libpython3.8.dll liblog4cpp.dll libboost_filesystem-mt.dll libboost_chrono-mt.dll libboost_program_options-mt.dll libgmp-*.dll libusb-*.dll libxml2-*.dll Qt5Network.dll Qt5OpenGL.dll Qt5Svg.dll Qt5PrintSupport.dll libintl-*.dll libpcre-*.dll libiconv-*.dll zlib1.dll Qt5Gui.dll libglog.dll tinyiiod.dll libm2k.dll libvolk.dll libfftw3f-*.dll Qt5Widgets.dll libicudt*.dll libffi-*.dll liblzma-5.dll libdouble-conversion.dll libicuin*.dll libicuuc*.dll libpcre2-*.dll libzstd.dll libharfbuzz-*.dll libpng16-*.dll liborc-*.dll libfreetype-*.dll libgraphite2.dll libbrotlidec.dll libbz2-*.dll libbrotlicommon.dll libcrypto*.dll libssl*.dll +libglibmm-*.dll libsigrokdecode-*.dll libgcc_s_*.dll libstdc++-*.dll Qt5Core.dll libboost_thread-mt.dll libgnuradio-analog.dll libgnuradio-blocks.dll libgnuradio-fft.dll libwinpthread-*.dll libgnuradio-filter.dll libgnuradio-m2k.dll libgnuradio-pmt.dll libgnuradio-runtime.dll libgnuradio-scopy.dll libiio.dll Qt5Qml.dll Qt5Xml.dll qwt.dll libglib-*.dll libgmodule-*.dll libsigc-*.dll libgobject-*.dll libpython3.9.dll liblog4cpp.dll libboost_filesystem-mt.dll libboost_chrono-mt.dll libboost_program_options-mt.dll libgmp-*.dll libusb-*.dll libxml2-*.dll Qt5Network.dll Qt5OpenGL.dll Qt5Svg.dll Qt5PrintSupport.dll libintl-*.dll libpcre-*.dll libiconv-*.dll zlib1.dll Qt5Gui.dll libglog.dll tinyiiod.dll libm2k.dll libvolk.dll libfftw3f-*.dll Qt5Widgets.dll libicudt*.dll libffi-*.dll liblzma-5.dll libdouble-conversion.dll libicuin*.dll libicuuc*.dll libpcre2-*.dll libzstd.dll libharfbuzz-*.dll libpng16-*.dll liborc-*.dll libfreetype-*.dll libgraphite2.dll libbrotlidec.dll libbz2-*.dll libbrotlicommon.dll libcrypto*.dll libssl*.dll libmd4c.dll diff --git a/CI/appveyor/package_darwin.sh b/CI/appveyor/package_darwin.sh index 77ea6d3358..1ad85ee169 100755 --- a/CI/appveyor/package_darwin.sh +++ b/CI/appveyor/package_darwin.sh @@ -1,24 +1,26 @@ #!/bin/bash set -e +STAGINGDIR="${PWD}/staging" cd build mkdir -p ./Scopy.app/Contents/Frameworks ## Handle libm2k paths -m2kpath=/usr/local/lib/libm2k.dylib +m2kpath=${STAGINGDIR}/lib/libm2k.dylib m2krpath="$(otool -D ${m2kpath} | grep @rpath)" m2kid=${m2krpath#"@rpath/"} -sudo cp /usr/local/lib/libm2k.* ./Scopy.app/Contents/Frameworks +sudo cp ${STAGINGDIR}/lib/libm2k.* ./Scopy.app/Contents/Frameworks sudo install_name_tool -id @executable_path/../Frameworks/${m2kid} ./Scopy.app/Contents/Frameworks/${m2kid} sudo install_name_tool -change ${m2krpath} @executable_path/../Frameworks/${m2kid} ./Scopy.app/Contents/MacOS/Scopy -## Handle qwtpolar paths -qwtpolarpath=/usr/local/lib/libqwtpolar.1.dylib -sudo install_name_tool -id ${qwtpolarpath} /usr/local/lib/libqwtpolar.dylib -sudo install_name_tool -change libqwtpolar.1.dylib ${qwtpolarpath} ./Scopy.app/Contents/MacOS/Scopy +export DYLD_FALLBACK_LIBRARY_PATH=${STAGINGDIR}/lib + +# Copy the iio and ad9361 to the stagingdir path +sudo cp -R /Library/Frameworks/iio.framework ${STAGINGDIR}/lib +sudo cp -R /Library/Frameworks/ad9361.framework ${STAGINGDIR}/lib -export DYLD_FALLBACK_LIBRARY_PATH=/usr/local/lib ## Bundle some known dependencies -sudo echo "/usr/local/lib" | dylibbundler -od -b -x ./Scopy.app/Contents/MacOS/Scopy -d ./Scopy.app/Contents/Frameworks/ -p @executable_path/../Frameworks/ >/dev/null +# -ns == no signing +sudo echo "${STAGINGDIR}/lib" | dylibbundler -ns -od -b -x ./Scopy.app/Contents/MacOS/Scopy -d ./Scopy.app/Contents/Frameworks/ -p @executable_path/../Frameworks/ >/dev/null ## Copy the frameworks dylibbundler failed to copy sudo cp -R /usr/local/opt/python/Frameworks/Python.framework Scopy.app/Contents/Frameworks/ @@ -87,10 +89,10 @@ fi ## Handle iio-emu + libtinyiiod sudo cp ./iio-emu/iio-emu ./Scopy.app/Contents/MacOS/ -tinypath=/usr/local/lib/tinyiiod.dylib +tinypath=${STAGINGDIR}/lib/tinyiiod.dylib tinyrpath="$(otool -D ${tinypath} | grep @rpath)" tinyid=${tinyrpath#"@rpath/"} -sudo cp /usr/local/lib/tinyiiod.* ./Scopy.app/Contents/Frameworks +sudo cp ${STAGINGDIR}/lib/tinyiiod.* ./Scopy.app/Contents/Frameworks sudo install_name_tool -id @executable_path/../Frameworks/${tinyid} ./Scopy.app/Contents/Frameworks/${tinyid} sudo install_name_tool -change ${tinyrpath} @executable_path/../Frameworks/${tinyid} ./Scopy.app/Contents/MacOS/iio-emu @@ -98,20 +100,9 @@ sudo install_name_tool -change ${tinyrpath} @executable_path/../Frameworks/${tin sudo macdeployqt Scopy.app curl -o /tmp/macdeployqtfix.py https://raw.githubusercontent.com/aurelien-rainone/macdeployqtfix/master/macdeployqtfix.py -sudo python /tmp/macdeployqtfix.py ./Scopy.app/Contents/MacOS/Scopy /usr/local/opt/qt/ -sudo python /tmp/macdeployqtfix.py ./Scopy.app/Contents/MacOS/iio-emu /usr/local/opt/qt/ +sudo python /tmp/macdeployqtfix.py ./Scopy.app/Contents/MacOS/Scopy ${QT_PATH} +sudo python /tmp/macdeployqtfix.py ./Scopy.app/Contents/MacOS/iio-emu ${QT_PATH} sudo python /tmp/macdeployqtfix.py ./Scopy.app/Contents/MacOS/Scopy ./Scopy.app/Contents/Frameworks/ sudo macdeployqt Scopy.app -dmg -ls - -UPLOAD_TOOL=ghr - -if [ "$APPVEYOR_REPO_BRANCH" = "master" ]; then - echo Identified master branch - if [ -z "$APPVEYOR_PULL_REQUEST_NUMBER" ]; then - echo Not a pull request - $UPLOAD_TOOL -u $APPVEYOR_ACCOUNT_NAME -r $APPVEYOR_PROJECT_NAME -name "Continuous build" -b "Latest succesful master build " -prerelease -debug -replace continous $DEPLOY_FILE - fi -fi diff --git a/CI/appveyor/patches/qwtpolar-qwt-qt-compat.patch b/CI/appveyor/patches/qwtpolar-qwt-qt-compat.patch deleted file mode 100644 index d00022eb16..0000000000 --- a/CI/appveyor/patches/qwtpolar-qwt-qt-compat.patch +++ /dev/null @@ -1,112 +0,0 @@ -diff --git a/qwt_polar_curve.cpp b/qwt_polar_curve.cpp ---- a/src/qwt_polar_curve.cpp -+++ b/src/qwt_polar_curve.cpp -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - - static inline bool qwtInsidePole( const QwtScaleMap &map, double radius ) - { -@@ -435,7 +435,12 @@ - { - double off = qCeil( qMax( qreal( 1.0 ), painter->pen().widthF() ) ); - clipRect = clipRect.toRect().adjusted( -off, -off, off, off ); -- polyline = QwtClipper::clipPolygonF( clipRect, polyline ); -+ -+#if QWT_VERSION < 0x060400 -+ polyline = QwtClipper::clipPolygonF( clipRect, polyline ); -+#else /* QWT_VERSION < 0x060400 */ -+ polyline = QwtClipper::clippedPolygonF( clipRect, polyline ); -+#endif /* QWT_VERSION < 0x060400 */ - } - - QwtPainter::drawPolyline( painter, polyline ); - -diff --git a/qwt_polar_fitter.cpp b/qwt_polar_fitter.cpp ---- a/src/qwt_polar_fitter.cpp -+++ b/src/qwt_polar_fitter.cpp -@@ -7,6 +7,7 @@ - *****************************************************************************/ - - #include "qwt_polar_fitter.h" -+#include - - class QwtPolarFitter::PrivateData - { -@@ -25,7 +25,7 @@ public: - \param stepCount Number of points, that will be inserted between 2 points - \sa setStepCount() - */ --QwtPolarFitter::QwtPolarFitter( int stepCount ) -+QwtPolarFitter::QwtPolarFitter( int stepCount ) : QwtCurveFitter(QwtCurveFitter::Polygon) - { - d_data = new PrivateData; - d_data->stepCount = stepCount; - -diff --git a/qwt_polar_fitter.h b/qwt_polar_fitter.h ---- a/src/qwt_polar_fitter.h -+++ b/src/qwt_polar_fitter.h -@@ -12,6 +12,7 @@ - #include "qwt_polar_global.h" - #include - -+class QPolygonF; - /*! - \brief A simple curve fitter for polar points - -diff --git a/qwt_polar_grid.cpp b/qwt_polar_grid.cpp ---- a/src/qwt_polar_grid.cpp -+++ b/src/qwt_polar_grid.cpp -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - - static inline bool isClose( double value1, double value2 ) - { -@@ -726,8 +727,13 @@ - polygon[0] = pole.toPoint(); - polygon[1] = pos.toPoint(); - -- if ( testDisplayFlag( ClipGridLines ) ) -- polygon = QwtClipper::clipPolygonF( canvasRect, polygon ); -+#if QWT_VERSION < 0x060400 -+ if ( testDisplayFlag( ClipGridLines ) ) -+ polygon = QwtClipper::clipPolygonF( canvasRect, polygon ); -+#else /* QWT_VERSION < 0x060400 */ -+ if ( testDisplayFlag( ClipGridLines ) ) -+ polygon = QwtClipper::clippedPolygonF( canvasRect, polygon ); -+#endif /* QWT_VERSION < 0x060400 */ - - QwtPainter::drawPolyline( painter, polygon ); - } - -diff --git a/qwt_polar_spectrogram.cpp b/qwt_polar_spectrogram.cpp ---- a/src/qwt_polar_spectrogram.cpp -+++ b/src/qwt_polar_spectrogram.cpp -@@ -305,12 +305,8 @@ QImage QwtPolarSpectrogram::renderImage( - QImage image( rect.size(), d_data->colorMap->format() == QwtColorMap::RGB - ? QImage::Format_ARGB32 : QImage::Format_Indexed8 ); - -- const QwtInterval intensityRange = d_data->data->interval( Qt::ZAxis ); -- if ( !intensityRange.isValid() ) -- return image; -- - if ( d_data->colorMap->format() == QwtColorMap::Indexed ) -- image.setColorTable( d_data->colorMap->colorTable( intensityRange ) ); -+ image.setColorTable( d_data->colorMap->colorTable256()); - - /* - For the moment we only announce the composition of the image by -@@ -471,7 +467,7 @@ void QwtPolarSpectrogram::renderTile( - const double radius = radialMap.invTransform( r ); - - const double value = d_data->data->value( azimuth, radius ); -- *line++ = d_data->colorMap->colorIndex( intensityRange, value ); -+ *line++ = d_data->colorMap->colorIndex(256, intensityRange, value ); - } - } - } diff --git a/CMakeLists.txt b/CMakeLists.txt index 854d8309a2..e43b8b24f0 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ cmake_minimum_required(VERSION 3.5) -project(scopy LANGUAGES CXX VERSION 1.3.0) +project(scopy LANGUAGES C CXX VERSION 1.4.0) set(Python_ADDITIONAL_VERSIONS 3) FIND_PACKAGE(PythonInterp REQUIRED) @@ -44,6 +44,24 @@ endfunction() function(create_build_info_html_pages) endfunction() + + +function(configure_stylesheets DU_OPTION) + file(GLOB_RECURSE STYLESHEETS ${CMAKE_CURRENT_SOURCE_DIR}/resources/stylesheets/templates/*.qss.c) + + foreach(_stylesheet ${STYLESHEETS}) + string(REPLACE ".c" "" FILE_OUT ${_stylesheet}) + string(REPLACE "templates/" "" FILE_OUT ${FILE_OUT}) + + execute_process ( + COMMAND ${CMAKE_C_COMPILER} -E -P ${DU_OPTION} ${_stylesheet} -o ${FILE_OUT} + ) + + message(STATUS "Done preprocessing ${_stylesheet}, file written to: ${FILE_OUT}") + endforeach() + +endfunction() + # Get the GIT hash of the latest commit include(FindGit OPTIONAL) if (GIT_FOUND) @@ -80,10 +98,22 @@ if (MSVC) add_definitions(-DQWT_DLL) endif (MSVC) +if(ANDROID) + set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + if (ANDROID_ABI STREQUAL "armeabi-v7a") + set(ANDROID_EXTRA_LIBS + ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so + ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so) + endif() +endif() + find_package(Qt5Widgets REQUIRED) find_package(Qt5 COMPONENTS LinguistTools REQUIRED) find_package(Qt5Concurrent REQUIRED) find_package(Qt5Network REQUIRED) +if(ANDROID) + find_package(Qt5AndroidExtras REQUIRED) +endif() FILE(GLOB TS_FILES ${CMAKE_SOURCE_DIR}/resources/translations/*.ts) set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}) @@ -147,7 +177,6 @@ else() endif() -find_package(Qwt REQUIRED) find_package(Qt5Qml REQUIRED) find_package(Qt5Svg REQUIRED) find_package(Qt5UiTools REQUIRED) @@ -165,6 +194,7 @@ add_definitions(-DBOOST_ALL_DYN_LINK) find_package(Boost COMPONENTS system filesystem thread chrono REQUIRED) find_package(libm2k REQUIRED) +find_library(LIBUSB_LIBRARIES NAMES usb-1.0 usb) if (ENABLE_MATIO) message("-- Building with MATLAB support for SignalGenerator") @@ -172,36 +202,29 @@ if (ENABLE_MATIO) add_definitions(-DMATLAB_SUPPORT_SIGGEN) endif() -find_library(QWTPOLAR_LIBRARIES qwtpolar) -find_path(QWTPOLAR_INCLUDE_DIRS qwt_polar_plot.h PATH_SUFFIXES qwt) -if (QWTPOLAR_LIBRARIES) - message(STATUS "QwtPolar libraries found - ${QWTPOLAR_LIBRARIES}") +if(ANDROID) + find_library(QWT_LIBRARIES REQUIRED NAMES qwt_${ANDROID_ABI}) else() - message(STATUS "QwtPolar libraries not found - assuming they are built in Qwt") - set(QWTPOLAR_LIBRARIES "") -endif() -if (NOT QWTPOLAR_INCLUDE_DIRS) - message(SEND_ERROR "QwtPolar includes not found") -else() - message(STATUS "Found QwtPolar include files - ${QWTPOLAR_INCLUDE_DIRS}/qwt_polar_plot.h") + find_library(QWT_LIBRARIES REQUIRED NAMES qwt) endif() find_package(PkgConfig) +set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH ON) pkg_check_modules(GLIB REQUIRED glib-2.0) pkg_check_modules(GLIBMM REQUIRED glibmm-2.4) pkg_check_modules(SIGCPP REQUIRED sigc++-2.0) pkg_check_modules(LIBSIGROK_DECODE REQUIRED libsigrokdecode) + pkg_get_variable(LIBSIGROK_DECODERS_DIR libsigrokdecode decodersdir) -message(CMAKE_PATH ${CMAKE_PREFIX_PATH}) -message(NETWORK ${Qt5Network_INCLUDE_DIRS} ${Qt5Network_LIBRARIES}) + include_directories( ${Boost_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Concurrent_INCLUDE_DIRS} + ${Qt5AndroidExtras_INCLUDE_DIRS} ${Qt5Qml_INCLUDE_DIRS} ${Qt5UiTools_INCLUDE_DIRS} ${QWT_INCLUDE_DIRS} - ${QWTPOLAR_INCLUDE_DIRS} ${Qt5Svg_INCLUDE_DIRS} ${Qt5Xml_INCLUDE_DIRS} ${SCOPY_INCLUDE_DIRS} @@ -229,6 +252,7 @@ FILE(GLOB SRC_LIST src/*.cpp src/*.cc src/patterngenerator/*/*.cpp src/logicanalyzer/*.cpp src/logicanalyzer/*/*.cpp + src/gui/*.cpp ) FILE(GLOB M2KSCOPE_UIS ui/patterns/*.ui ui/*.ui) @@ -248,6 +272,25 @@ if (APPLE) option(ENABLE_APPLICATION_BUNDLE "Enable application bundle for OSX" ON) endif(APPLE) +option(CONFIG_STYLESHEETS "Preprocess stylesheets using ${CMAKE_C_COMPILER}" ON) +message(STATUS CONFIG_STYLESHEETS - ${CONFIG_STYLESHEETS}) +if (${CONFIG_STYLESHEETS}) + if (ANDROID) + set(PROCESSING_OPTIONS "-D__ANDROID__") + endif(ANDROID) + + if (APPLE) + set(PROCESSING_OPTIONS "-D__MACOS__") + endif(APPLE) + + if (WIN32) + set(PROCESSING_OPTIONS "-D__WINDOWS__") + endif(WIN32) + + configure_stylesheets("${PROCESSING_OPTIONS}") + +endif() + if (ENABLE_APPLICATION_BUNDLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") @@ -311,7 +354,7 @@ if($ENV{APPVEYOR}) set(APPVEYOR_INFO ${APPVEYOR_INFO}job_id:\ $ENV{APPVEYOR_JOB_ID}\n) set(APPVEYOR_INFO ${APPVEYOR_INFO}job_name:\ $ENV{APPVEYOR_JOB_NAME}\n) set(APPVEYOR_INFO ${APPVEYOR_INFO}job_nr:\ $ENV{APPVEYOR_JOB_NUMBER}\n) - set(APPVEYOR_INFO ${APPVEYOR_INFO}job_link:\ $ENV{APPVEYOR_URL}/project/$ENV{APPVEYOR_ACCOUNT_NAME}/$ENV{APPVEYOR_PROJECT_NAME}/builds/$ENV{APPVEYOR_BUILD_ID}/job/$ENV{APPVEYOR_JOB_ID}\n) + set(APPVEYOR_INFO ${APPVEYOR_INFO}job_link:\ $ENV{APPVEYOR_URL}/project/$ENV{APPVEYOR_ACCOUNT_NAME}/$ENV{APPVEYOR_PROJECT_NAME}/builds/$ENV{APPVEYOR_BUILD_ID}/job/$ENV{APPVEYOR_JOB_ID}\n) if(EXISTS ${CMAKE_SOURCE_DIR}/scopy-mingw-build-status) message(scopy-mingw-build-status found .. populating) FILE(READ ${CMAKE_SOURCE_DIR}/scopy-mingw-build-status SCOPY_MINGW_BUILD_STATUS_INFO) @@ -352,7 +395,8 @@ if (CLONE_IIO_EMU) add_subdirectory(iio-emu) endif() -add_executable(${PROJECT_NAME} WIN32 ${OSX_BUNDLE} +if(ANDROID) + add_library(${PROJECT_NAME} SHARED ${SRC_LIST} ${RESOURCES} ${m2kscope_RESOURCES} @@ -360,7 +404,19 @@ add_executable(${PROJECT_NAME} WIN32 ${OSX_BUNDLE} ${EXTRA_BUNDLE_FILES} ${TRANSLATION_RESOURCES} ${ABOUT_PAGE_RESOURCES} -) + ) + else() + add_executable(${PROJECT_NAME} WIN32 ${OSX_BUNDLE} + ${SRC_LIST} + ${RESOURCES} + ${m2kscope_RESOURCES} + ${m2kscope_FORMS_HEADERS} + ${EXTRA_BUNDLE_FILES} + ${TRANSLATION_RESOURCES} + ${ABOUT_PAGE_RESOURCES} + ) +endif() + if (WIN32 OR ENABLE_APPLICATION_BUNDLE) set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME Scopy) @@ -374,6 +430,8 @@ target_link_libraries(${PROJECT_NAME} LINK_PRIVATE ${Qt5Qml_LIBRARIES} ${Qt5UiTools_LIBRARIES} ${Qt5Network_LIBRARIES} + ${Qt5AndroidExtras_LIBRARIES} + ${LIBUSB_LIBRARIES} gnuradio::gnuradio-runtime gnuradio::gnuradio-analog gnuradio::gnuradio-blocks @@ -385,7 +443,6 @@ target_link_libraries(${PROJECT_NAME} LINK_PRIVATE gnuradio::gnuradio-m2k ${Boost_LIBRARIES} ${QWT_LIBRARIES} - ${QWTPOLAR_LIBRARIES} ${Qt5Svg_LIBRARIES} ${Qt5Xml_LIBRARIES} ${MATIO_LIBRARIES} diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 0000000000..b3774e0b25 --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/assets/README.MD b/android/assets/README.MD new file mode 100644 index 0000000000..ab10509ffc --- /dev/null +++ b/android/assets/README.MD @@ -0,0 +1,9 @@ +To have a correct deploy, this should look something like: + +assets + - libsigrokdecode + | - decoders + | | - + - python3.8 + | - + - iio-emu (wip) diff --git a/android/assets/libsigrokdecode/README.MD b/android/assets/libsigrokdecode/README.MD new file mode 100644 index 0000000000..b589d0077b --- /dev/null +++ b/android/assets/libsigrokdecode/README.MD @@ -0,0 +1 @@ +Decoders that are copied here will be bundled in the .apk. They can be found in the staging folder/share/libsigrokdecode. diff --git a/android/assets/python3.8/README.MD b/android/assets/python3.8/README.MD new file mode 100644 index 0000000000..b12db040ac --- /dev/null +++ b/android/assets/python3.8/README.MD @@ -0,0 +1 @@ +For decoders to work, we need to ship a python environment. You can copy it from stagingfolder/lib/python3.8 diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000000..443a800244 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.6.0' + } +} + +repositories { + google() + jcenter() +} + +apply plugin: 'com.android.application' + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) +} + +android { + /******************************************************* + * The following variables: + * - androidBuildToolsVersion, + * - androidCompileSdkVersion + * - qt5AndroidDir - holds the path to qt android files + * needed to build any Qt application + * on Android. + * + * are defined in gradle.properties file. This file is + * updated by QtCreator and androiddeployqt tools. + * Changing them manually might break the compilation! + *******************************************************/ + + compileSdkVersion androidCompileSdkVersion.toInteger() + + buildToolsVersion '28.0.3' + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java'] + aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl'] + res.srcDirs = [qt5AndroidDir + '/res', 'res'] + resources.srcDirs = ['resources'] + renderscript.srcDirs = ['src'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } + + tasks.withType(JavaCompile) { + options.incremental = true + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lintOptions { + abortOnError false + } + + // Do not compress Qt binary resources file + aaptOptions { + noCompress 'rcc' + } + + defaultConfig { + resConfig "en" + minSdkVersion = qtMinSdkVersion + targetSdkVersion = qtTargetSdkVersion + } +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000000..fded106b17 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,11 @@ +# Project-wide Gradle settings. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m + +# Gradle caching allows reusing the build artifacts from a previous +# build with the same inputs. However, over time, the cache size will +# grow. Uncomment the following line to enable it. +#org.gradle.caching=true diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..f6b961fd5a Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..6623300beb --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/android/gradlew b/android/gradlew new file mode 100755 index 0000000000..cccdd3d517 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 0000000000..f9553162f1 --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/libs/arm64-v8a/.gitignore b/android/libs/arm64-v8a/.gitignore new file mode 100644 index 0000000000..72e8ffc0db --- /dev/null +++ b/android/libs/arm64-v8a/.gitignore @@ -0,0 +1 @@ +* diff --git a/android/res/drawable-hdpi/icon.png b/android/res/drawable-hdpi/icon.png new file mode 100644 index 0000000000..3ae98caf6b Binary files /dev/null and b/android/res/drawable-hdpi/icon.png differ diff --git a/android/res/drawable-hdpi/logo.png b/android/res/drawable-hdpi/logo.png new file mode 100644 index 0000000000..119fc5b33d Binary files /dev/null and b/android/res/drawable-hdpi/logo.png differ diff --git a/android/res/drawable-hdpi/logo_land.png b/android/res/drawable-hdpi/logo_land.png new file mode 100644 index 0000000000..119fc5b33d Binary files /dev/null and b/android/res/drawable-hdpi/logo_land.png differ diff --git a/android/res/drawable-hdpi/logo_port.png b/android/res/drawable-hdpi/logo_port.png new file mode 100644 index 0000000000..119fc5b33d Binary files /dev/null and b/android/res/drawable-hdpi/logo_port.png differ diff --git a/android/res/drawable-ldpi/icon.png b/android/res/drawable-ldpi/icon.png new file mode 100644 index 0000000000..5bf398f9bd Binary files /dev/null and b/android/res/drawable-ldpi/icon.png differ diff --git a/android/res/drawable-ldpi/logo.png b/android/res/drawable-ldpi/logo.png new file mode 100644 index 0000000000..4a2cd30e9e Binary files /dev/null and b/android/res/drawable-ldpi/logo.png differ diff --git a/android/res/drawable-ldpi/logo_land.png b/android/res/drawable-ldpi/logo_land.png new file mode 100644 index 0000000000..4a2cd30e9e Binary files /dev/null and b/android/res/drawable-ldpi/logo_land.png differ diff --git a/android/res/drawable-ldpi/logo_port.png b/android/res/drawable-ldpi/logo_port.png new file mode 100644 index 0000000000..4a2cd30e9e Binary files /dev/null and b/android/res/drawable-ldpi/logo_port.png differ diff --git a/android/res/drawable-mdpi/icon.png b/android/res/drawable-mdpi/icon.png new file mode 100644 index 0000000000..4d36b946a4 Binary files /dev/null and b/android/res/drawable-mdpi/icon.png differ diff --git a/android/res/drawable-mdpi/logo.png b/android/res/drawable-mdpi/logo.png new file mode 100644 index 0000000000..bc60acaa50 Binary files /dev/null and b/android/res/drawable-mdpi/logo.png differ diff --git a/android/res/drawable-mdpi/logo_land.png b/android/res/drawable-mdpi/logo_land.png new file mode 100644 index 0000000000..bc60acaa50 Binary files /dev/null and b/android/res/drawable-mdpi/logo_land.png differ diff --git a/android/res/drawable-mdpi/logo_port.png b/android/res/drawable-mdpi/logo_port.png new file mode 100644 index 0000000000..bc60acaa50 Binary files /dev/null and b/android/res/drawable-mdpi/logo_port.png differ diff --git a/android/res/drawable-xhdpi/icon.png b/android/res/drawable-xhdpi/icon.png new file mode 100644 index 0000000000..e64f3bad1a Binary files /dev/null and b/android/res/drawable-xhdpi/icon.png differ diff --git a/android/res/drawable-xhdpi/logo.png b/android/res/drawable-xhdpi/logo.png new file mode 100644 index 0000000000..a0d35d63db Binary files /dev/null and b/android/res/drawable-xhdpi/logo.png differ diff --git a/android/res/drawable-xhdpi/logo_land.png b/android/res/drawable-xhdpi/logo_land.png new file mode 100644 index 0000000000..a0d35d63db Binary files /dev/null and b/android/res/drawable-xhdpi/logo_land.png differ diff --git a/android/res/drawable-xhdpi/logo_port.png b/android/res/drawable-xhdpi/logo_port.png new file mode 100644 index 0000000000..a0d35d63db Binary files /dev/null and b/android/res/drawable-xhdpi/logo_port.png differ diff --git a/android/res/drawable-xxhdpi/icon.png b/android/res/drawable-xxhdpi/icon.png new file mode 100644 index 0000000000..1a83ad1c54 Binary files /dev/null and b/android/res/drawable-xxhdpi/icon.png differ diff --git a/android/res/drawable-xxhdpi/logo.png b/android/res/drawable-xxhdpi/logo.png new file mode 100644 index 0000000000..e3f8b02a58 Binary files /dev/null and b/android/res/drawable-xxhdpi/logo.png differ diff --git a/android/res/drawable-xxhdpi/logo_land.png b/android/res/drawable-xxhdpi/logo_land.png new file mode 100644 index 0000000000..e3f8b02a58 Binary files /dev/null and b/android/res/drawable-xxhdpi/logo_land.png differ diff --git a/android/res/drawable-xxhdpi/logo_port.png b/android/res/drawable-xxhdpi/logo_port.png new file mode 100644 index 0000000000..e3f8b02a58 Binary files /dev/null and b/android/res/drawable-xxhdpi/logo_port.png differ diff --git a/android/res/drawable-xxxhdpi/icon.png b/android/res/drawable-xxxhdpi/icon.png new file mode 100644 index 0000000000..fc73a6f117 Binary files /dev/null and b/android/res/drawable-xxxhdpi/icon.png differ diff --git a/android/res/drawable-xxxhdpi/logo.png b/android/res/drawable-xxxhdpi/logo.png new file mode 100644 index 0000000000..3545c6ce89 Binary files /dev/null and b/android/res/drawable-xxxhdpi/logo.png differ diff --git a/android/res/drawable-xxxhdpi/logo_land.png b/android/res/drawable-xxxhdpi/logo_land.png new file mode 100644 index 0000000000..3545c6ce89 Binary files /dev/null and b/android/res/drawable-xxxhdpi/logo_land.png differ diff --git a/android/res/drawable-xxxhdpi/logo_port.png b/android/res/drawable-xxxhdpi/logo_port.png new file mode 100644 index 0000000000..3545c6ce89 Binary files /dev/null and b/android/res/drawable-xxxhdpi/logo_port.png differ diff --git a/android/res/drawable/splashscreen.xml b/android/res/drawable/splashscreen.xml new file mode 100644 index 0000000000..405a7fae44 --- /dev/null +++ b/android/res/drawable/splashscreen.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/android/res/drawable/splashscreen_land.xml b/android/res/drawable/splashscreen_land.xml new file mode 100644 index 0000000000..0a0b3e8e18 --- /dev/null +++ b/android/res/drawable/splashscreen_land.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/android/res/drawable/splashscreen_port.xml b/android/res/drawable/splashscreen_port.xml new file mode 100644 index 0000000000..25fe888676 --- /dev/null +++ b/android/res/drawable/splashscreen_port.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/android/res/values-land/splashscreentheme.xml b/android/res/values-land/splashscreentheme.xml new file mode 100644 index 0000000000..800b923fc9 --- /dev/null +++ b/android/res/values-land/splashscreentheme.xml @@ -0,0 +1,6 @@ + + + + diff --git a/android/res/values-port/splashscreentheme.xml b/android/res/values-port/splashscreentheme.xml new file mode 100644 index 0000000000..a20302e451 --- /dev/null +++ b/android/res/values-port/splashscreentheme.xml @@ -0,0 +1,6 @@ + + + + diff --git a/android/res/values/libs.xml b/android/res/values/libs.xml new file mode 100644 index 0000000000..6b1a4a2a02 --- /dev/null +++ b/android/res/values/libs.xml @@ -0,0 +1,22 @@ + + + + https://download.qt.io/ministro/android/qt5/qt-5.14 + + + + + + + + + + + + + + + + + diff --git a/android/res/values/splashscreentheme.xml b/android/res/values/splashscreentheme.xml new file mode 100644 index 0000000000..53b3673d83 --- /dev/null +++ b/android/res/values/splashscreentheme.xml @@ -0,0 +1,6 @@ + + + + diff --git a/android/res/xml/device_filter.xml b/android/res/xml/device_filter.xml new file mode 100644 index 0000000000..e30fe0e84b --- /dev/null +++ b/android/res/xml/device_filter.xml @@ -0,0 +1,3 @@ + + + diff --git a/android/src/org/adi/scopy/ScopyActivity.java b/android/src/org/adi/scopy/ScopyActivity.java new file mode 100644 index 0000000000..5f8570d762 --- /dev/null +++ b/android/src/org/adi/scopy/ScopyActivity.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2021 Analog Devices Inc. + * + * This file is part of Scopy + * (see http://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.adi.scopy; + +import java.io.File; +import java.io.IOException; +import org.qtproject.qt5.android.bindings.QtActivity; +import android.content.pm.PackageManager; +import android.content.Intent; +import android.content.Context; +import android.content.ComponentName; +import android.os.Bundle; +import android.util.DisplayMetrics; + +public class ScopyActivity extends QtActivity +{ + public static native void saveSessionJavaHelper(); + + @Override + public void onCreate(Bundle savedInstanceState) + { + System.out.println("-- ScopyActivity: onCreate"); + super.onCreate(savedInstanceState); + } + + @Override + protected void onStart() + { + System.out.println("-- ScopyActivity: onStart"); + super.onStart(); + } + + @Override + protected void onStop() + { + System.out.println("-- ScopyActivity: onStop"); + super.onStop(); + } + + protected void onPause(){ + System.out.println("-- ScopyActivity: onPause - saving application state to ini file "); + saveSessionJavaHelper(); // actually save the data + super.onPause(); + } + + protected void onDestroy(){ + System.out.println("-- ScopyActivity: onDestroy "); + super.onDestroy(); + } + + public void restart() { + saveSessionJavaHelper(); + System.out.println("-- ScopyActivity: Restarting "); + Context context = getApplicationContext(); + PackageManager packageManager = context.getPackageManager(); + Intent intent = packageManager.getLaunchIntentForPackage(context.getPackageName()); + ComponentName componentName = intent.getComponent(); + Intent mainIntent = Intent.makeRestartActivityTask(componentName); + context.startActivity(mainIntent); + Runtime.getRuntime().exit(0); + } + + public String getScaleFactor() { + DisplayMetrics displayMetrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + + double scaleFactor = ((double)displayMetrics.widthPixels/displayMetrics.heightPixels) + /displayMetrics.scaledDensity; + String formattedScaleFactor = String.format("%.02f", scaleFactor); + System.out.println("-- ScopyActivity: scale factor is: " + formattedScaleFactor); + + + return formattedScaleFactor.replace(",","."); + } +} diff --git a/android/src/org/adi/scopy/ScopyApplication.java b/android/src/org/adi/scopy/ScopyApplication.java new file mode 100644 index 0000000000..3679319e18 --- /dev/null +++ b/android/src/org/adi/scopy/ScopyApplication.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 Analog Devices Inc. + * + * This file is part of Scopy + * (see http://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.adi.scopy; + +import org.qtproject.qt5.android.bindings.QtApplication; + +import java.io.File; +import java.io.IOException; +import android.system.Os; +import android.system.ErrnoException; + + +public class ScopyApplication extends QtApplication +{ + @Override + public void onCreate() + { + System.out.println("QtApplication started"); + String apk = getApplicationInfo().sourceDir; + String cache = getApplicationContext().getCacheDir().toString(); + System.out.println("sourcedir: "+ getApplicationInfo().sourceDir); + System.out.println("public sourcedir: "+ getApplicationInfo().publicSourceDir); + String libdir = getApplicationInfo().nativeLibraryDir; + System.out.println("native library dir:" + libdir); + System.out.println("applcation cache dir:" + cache); + System.out.println("Hello Scopy !"); + + try { + Os.setenv("PYTHONHOME",".",true); + Os.setenv("PYTHONPATH",apk + "/assets/python3.8",true); + Os.setenv("SIGROKDECODE_DIR", apk + "/assets/libsigrokdecode/decoders",true); + Os.setenv("APPDATA", cache, true); + Os.setenv("LD_LIBRARY_PATH", libdir, true); + Os.setenv("IIOEMU_BIN", libdir+"/iio-emu.so", true); + + } + + catch(ErrnoException x) { + System.out.println("Cannot set envvars"); + } + + super.onCreate(); + } + +} diff --git a/android/src/org/qtproject/example/jnimessenger/JniMessenger.java b/android/src/org/qtproject/example/jnimessenger/JniMessenger.java new file mode 100644 index 0000000000..750a643568 --- /dev/null +++ b/android/src/org/qtproject/example/jnimessenger/JniMessenger.java @@ -0,0 +1,113 @@ +package org.qtproject.example.jnimessenger; +import android.content.Context; +import android.hardware.usb.UsbManager; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbDeviceConnection; +import android.content.IntentFilter; +import android.app.PendingIntent; +import android.content.pm.PackageManager; +import android.content.Intent; +import android.content.BroadcastReceiver; +import android.os.ParcelFileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileDescriptor; +import android.util.Log; +import java.util.HashMap; +import java.util.Iterator; + + +public class JniMessenger +{ + + +private static final String ACTION_USB_PERMISSION = + "com.android.example.USB_PERMISSION"; +private static final String TAG = "MyActivity"; + +private final BroadcastReceiver usbReceiver = new BroadcastReceiver() { + + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (ACTION_USB_PERMISSION.equals(action)) { + synchronized (this) { + UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); + + if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { + if(device != null){ + //call method to set up device communication + } + } + else { + Log.d(TAG, "permission denied for device " + device); + } + } + } + if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { + UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); + if (device != null) { + // call your method that cleans up and closes communication with the device + } + } + } +}; + + private static native void callFromJava(String message); + + public JniMessenger() {} + + public static void printFromJava(String message) + { + System.out.println("This is printed from JAVA, message is: " + message); + callFromJava("Hello from JAVA!"); + } + + + UsbDeviceConnection connection; + UsbDevice device; + + public int getUsbFd(Context ctx) { + + UsbManager manager = (UsbManager) ctx.getSystemService(Context.USB_SERVICE); + + PendingIntent permissionIntent = PendingIntent.getBroadcast(ctx, 0, new Intent(ACTION_USB_PERMISSION), 0); + IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); + ctx.registerReceiver(usbReceiver, filter); + + HashMap deviceList = manager.getDeviceList(); + Iterator deviceIterator = deviceList.values().iterator(); + System.out.println("Devices found " + Integer.toString(deviceList.size())); + while(deviceIterator.hasNext()){ + device = deviceIterator.next(); + System.out.println("Device " + device.getDeviceName()); + manager.requestPermission(device, permissionIntent); + + // if(ContextCompat.checkSelfPermission(ACTION_USB_PERMISSION) == PackageManager.PERMISSION_GRANTED) { + try { + connection = manager.openDevice(device); + + + String fd = Integer.toString(connection.getFileDescriptor()); + String usbfsPath = device.getDeviceName(); + String serial = device.getSerialNumber(); + String man = device.getManufacturerName(); + String pn = device.getProductName(); + String vid = Integer.toString(device.getVendorId(),16); + String pid = Integer.toString(device.getProductId(),16); + + System.out.println("fd: " + fd + "\nusbfs: "+usbfsPath+"\nserial: "+serial+"\nvid: "+vid+" pid: "+ pid + "\nManufacturer: "+ man + "\nProduct Name: "+ pn); + return connection.getFileDescriptor(); + }catch(Exception e) {System.out.println(e);} + + //} + } + return -1; + } + + public String getUsbFs() { + return device.getDeviceName(); + } + + +}; + diff --git a/appveyor.yml b/appveyor.yml index aad1551016..b9d40beb32 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,42 +9,6 @@ environment: BRANCH: $(APPVEYOR_REPO_BRANCH) REPO: $(APPVEYOR_REPO_NAME) matrix: - - MINGW_VERSION: mingw64 - ARCH: x86_64 - ARCH_BIT: 64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - BUILD_DEPS_CMD: "C:\\msys64\\usr\\bin\\bash CI\\appveyor\\build_appveyor_mingw.sh" - DEPLOY_FILE: "C:\\scopy-%ARCH_BIT%-setup.exe" - - - MINGW_VERSION: mingw32 - ARCH: i686 - ARCH_BIT: 32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - BUILD_DEPS_CMD: "C:\\msys64\\usr\\bin\\bash CI\\appveyor\\build_appveyor_mingw.sh" - DEPLOY_FILE: "C:\\scopy-%ARCH_BIT%-setup.exe" - - - ARCH: x86_64 - ARCH_BIT: 64 - APPVEYOR_BUILD_WORKER_IMAGE: macos-mojave - BUILD_DEPS_CMD: "/Users/appveyor/projects/scopy/CI/appveyor/install_macos_deps.sh" - BUILD_CMD: "/Users/appveyor/projects/scopy/CI/appveyor/build_appveyor_macos.sh" - PACKAGE_CMD: "/Users/appveyor/projects/scopy/CI/appveyor/package_darwin.sh" - DEPLOY_FILE: "/Users/appveyor/projects/scopy/build/Scopy.dmg" - C_COMPILER: -DCMAKE_C_COMPILER=/usr/bin/gcc - CXX_COMPILER: -DCMAKE_CXX_COMPILER=/usr/bin/g++ - QT_FORMULAE: "qt5" - - - ARCH: x86_64 - ARCH_BIT: 64 - APPVEYOR_BUILD_WORKER_IMAGE: macos - BUILD_DEPS_CMD: "/Users/appveyor/projects/scopy/CI/appveyor/install_macos_deps.sh" - BUILD_CMD: "/Users/appveyor/projects/scopy/CI/appveyor/build_appveyor_macos.sh" - PACKAGE_CMD: "/Users/appveyor/projects/scopy/CI/appveyor/package_darwin.sh" - DEPLOY_FILE: "/Users/appveyor/projects/scopy/build/Scopy.dmg" - C_COMPILER: -DCMAKE_C_COMPILER=/usr/bin/gcc - CXX_COMPILER: -DCMAKE_CXX_COMPILER=/usr/bin/g++ - QT_FORMULAE: "qt5" - - ARCH: x86_64 ARCH_BIT: 64 APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu1804 diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000..e7343254b3 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,74 @@ +variables: + QT_FORMULAE: qt@5 + REPO_SLUG: $(Build.Repository.Name) + CURRENT_COMMIT: $(Build.SourceVersion) +trigger: + branches: + include: + - main + - master + - staging/* + - ci-* + tags: + include: + - v* + +pr: + branches: + include: + - main + - master + - 20* + +stages: +- stage: Builds + jobs: + - job: macOSBuilds + strategy: + matrix: + macOS_10_15: + vmImage: 'macOS-10.15' + artifactName: 'macOS-10.15' + macOS_11: + vmImage: 'macOS-11' + artifactName: 'macOS-11' + pool: + vmImage: $[ variables['vmImage'] ] + steps: + - checkout: self + fetchDepth: 1 + clean: true + - script: ./CI/appveyor/install_macos_deps.sh + displayName: 'Dependencies' + workingDirectory: $(Build.Repository.LocalPath) + - script: ./CI/appveyor/build_appveyor_macos.sh + displayName: 'Build' + workingDirectory: $(Build.Repository.LocalPath) + - script: ./CI/appveyor/package_darwin.sh + displayName: 'Create Scopy.dmg' + workingDirectory: $(Build.Repository.LocalPath) + - script: cp -R staging ${BUILD_ARTIFACTSTAGINGDIRECTORY} + displayName: 'Copy staging dir' + workingDirectory: $(Build.Repository.LocalPath) + - script: cp build/Scopy.dmg ${BUILD_ARTIFACTSTAGINGDIRECTORY} + displayName: 'Copy Scopy.dmg' + workingDirectory: $(Build.Repository.LocalPath) + - script: | + ACCOUNT_NAME=`echo $REPO_SLUG | awk -F "/" '{print $1}'` + PROJECT_NAME=`echo $REPO_SLUG | awk -F "/" '{print $2}'` + echo "ACCOUNT_NAME = " ${ACCOUNT_NAME} + echo "PROJECT_NAME = " ${PROJECT_NAME} + MACOS_VERSION=$(/usr/libexec/PlistBuddy -c "Print:ProductVersion" /System/Library/CoreServices/SystemVersion.plist) + DEPLOY_FILE=Scopy-macos${MACOS_VERSION}-${CURRENT_COMMIT:0:7}.dmg + cp build/Scopy.dmg ${DEPLOY_FILE} + ls -la + # TODO: Add GH_TOKEN for github cont release upload + #ghr -u $ACCOUNT_NAME -r $PROJECT_NAME -name "Continuous build" -b "Latest succesful master build " -prerelease -debug -replace continous ${DEPLOY_FILE} + displayName: 'Push to github continuous release' + workingDirectory: $(Build.Repository.LocalPath) + condition: and(succeeded(), and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))) + - task: PublishPipelineArtifact@1 + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)' + artifactName: '$(artifactName)' diff --git a/drivers/dpinst.xml b/drivers/dpinst.xml index 6d607f8352..12f25fb160 100644 --- a/drivers/dpinst.xml +++ b/drivers/dpinst.xml @@ -1,14 +1,14 @@ - - - - * - - - PlutoSDR/M2k Device Driver Updater - Welcome to the PlutoSDR/M2k Installer! - This wizard will walk you through updating the drivers for your PlutoSDR/M2k. - Installing the software for your PlutoSDR/M2k... - Congratulations! You finished installing your PlutoSDR/M2k drivers. - - - + + + + * + + + PlutoSDR/M2k Device Driver Updater + Welcome to the PlutoSDR/M2k Installer! + This wizard will walk you through updating the drivers for your PlutoSDR/M2k. + Installing the software for your PlutoSDR/M2k... + Congratulations! You finished installing your PlutoSDR/M2k drivers. + + + diff --git a/drivers/pluto-cdc-acm.cat b/drivers/pluto-cdc-acm.cat index 96f22e185a..cec05966da 100644 Binary files a/drivers/pluto-cdc-acm.cat and b/drivers/pluto-cdc-acm.cat differ diff --git a/drivers/pluto-cdc-acm.inf b/drivers/pluto-cdc-acm.inf index 9957d3745f..357d8c76eb 100644 Binary files a/drivers/pluto-cdc-acm.inf and b/drivers/pluto-cdc-acm.inf differ diff --git a/drivers/pluto-dfu.cat b/drivers/pluto-dfu.cat index ab7ee2715d..035b0cc630 100644 Binary files a/drivers/pluto-dfu.cat and b/drivers/pluto-dfu.cat differ diff --git a/drivers/pluto-dfu.inf b/drivers/pluto-dfu.inf index 77474db91a..22c75b05e6 100644 Binary files a/drivers/pluto-dfu.inf and b/drivers/pluto-dfu.inf differ diff --git a/drivers/pluto-rndis.cat b/drivers/pluto-rndis.cat index 1d7e66a9a2..bb680c4077 100644 Binary files a/drivers/pluto-rndis.cat and b/drivers/pluto-rndis.cat differ diff --git a/drivers/pluto-rndis.inf b/drivers/pluto-rndis.inf index 38274e92cb..aaa283a522 100644 Binary files a/drivers/pluto-rndis.inf and b/drivers/pluto-rndis.inf differ diff --git a/drivers/pluto-usbd.cat b/drivers/pluto-usbd.cat index 57bd2f6703..616789f303 100644 Binary files a/drivers/pluto-usbd.cat and b/drivers/pluto-usbd.cat differ diff --git a/drivers/pluto-usbd.inf b/drivers/pluto-usbd.inf index bc9157bba1..4825b92a2b 100644 Binary files a/drivers/pluto-usbd.inf and b/drivers/pluto-usbd.inf differ diff --git a/iio-emu b/iio-emu index 710386fda8..b8208485f5 160000 --- a/iio-emu +++ b/iio-emu @@ -1 +1 @@ -Subproject commit 710386fda8daa5bbb3ffb6d4f214f014aa260f57 +Subproject commit b8208485f50573a38263031ab05e9cd30712bf0c diff --git a/js/startupscript.js b/js/startupscript.js new file mode 100644 index 0000000000..b1acead1d9 --- /dev/null +++ b/js/startupscript.js @@ -0,0 +1,38 @@ +#!/usr/bin/scopy -s + +/* This is the script that starts scopy up and connects to the emulator */ +var host = "127.0.0.1" + + +function connect(host) { + print("Connecting to " + host + "...") + + var success = launcher.connect("ip:" + host) + + if (success) + print("Connected!") + else + print("Failed!") + + return success; +} + + +function main() { + /* hardcoded for now */ + + var connected = connect(host) + if (!connected) + return Error() + + /* Run signal generator with values saved in .ini file*/ + siggen.running=true + /* Run oscilloscope */ + osc.running=true + /* Focus oscilloscope */ + launcher.focused_instrument=0 + /* Resume control to the application*/ + returnToApplication(); +} + +main() diff --git a/resources/icon_big.png b/resources/icon_big.png new file mode 100644 index 0000000000..3545c6ce89 Binary files /dev/null and b/resources/icon_big.png differ diff --git a/resources/stylesheets/default.qss b/resources/stylesheets/default-old.qss similarity index 96% rename from resources/stylesheets/default.qss rename to resources/stylesheets/default-old.qss index 1ac70060d6..66bea6b5a3 100644 --- a/resources/stylesheets/default.qss +++ b/resources/stylesheets/default-old.qss @@ -12,6 +12,14 @@ QWidget { font-size: 13px; } +QDockWidget { + titlebar-normal-icon: url(); +} + +QDockWidget::title { + background-color: transparent; +} + QToolTip { padding: 6px; border: 1px solid rgba(149, 152, 154, 150); @@ -347,6 +355,27 @@ QPushButton[blue_button=true]:hover{ background-color: #4a34ff; } QPushButton[blue_button=true]:disabled { background-color: grey; } +/*********************************** SubsectionSeparator ***************************************/ + +QLabel#lblSubsectionSeparator{ + font-size: 12px; + color: rgba(255, 255, 255, 70); +} + +QFrame#lineSubsectionSeparator{ border: 1px solid rgba(255, 255, 255, 70); } + +QPushButton#btnSubsectionSeparator{ + max-height: 6px; + max-width: 10px; + border-image: url(:/icons/sba_cmb_box_arrow_right.svg); +} + +QPushButton#btnSubsectionSeparator:checked{ + max-height: 10px; + max-width: 6px; + border-image: url(:/icons/sba_cmb_box_arrow.svg); +} + /* Info button for each tool */ QPushButton[info_button=true]{ diff --git a/resources/stylesheets/light.qss b/resources/stylesheets/light-old.qss similarity index 96% rename from resources/stylesheets/light.qss rename to resources/stylesheets/light-old.qss index 77a251b5f9..a8b4b297d9 100644 --- a/resources/stylesheets/light.qss +++ b/resources/stylesheets/light-old.qss @@ -12,6 +12,15 @@ QWidget { font-size: 13px; } +QDockWidget { + titlebar-normal-icon: url(); + background-color: #F7F7F7; +} + +QDockWidget::title { + background-color: transparent; +} + QToolTip { padding: 6px; border: 1px solid rgba(149, 152, 154, 150); @@ -346,6 +355,27 @@ QPushButton[blue_button=true]:hover{ background-color: #4a34ff; } QPushButton[blue_button=true]:disabled { background-color: grey; } +/*********************************** SubsectionSeparator ***************************************/ + +QLabel#lblSubsectionSeparator{ + font-size: 12px; + color: rgba(0, 0, 0, 70); +} + +QFrame#lineSubsectionSeparator{ border: 1px solid rgba(0, 0, 0, 70); } + +QPushButton#btnSubsectionSeparator{ + max-height: 6px; + max-width: 10px; + border-image: url(:/icons/sba_cmb_box_arrow_right.svg); +} + +QPushButton#btnSubsectionSeparator:checked{ + max-height: 10px; + max-width: 6px; + border-image: url(:/icons/sba_cmb_box_arrow.svg); +} + /* Info button for each tool */ QPushButton[info_button=true]{ diff --git a/resources/stylesheets/templates/default.qss.c b/resources/stylesheets/templates/default.qss.c new file mode 100644 index 0000000000..604bd51b42 --- /dev/null +++ b/resources/stylesheets/templates/default.qss.c @@ -0,0 +1,917 @@ +#include "values.h" + +/* Default background color */ +QMainWindow > .QWidget, adiscope--Sismograph > QwtPlotCanvas, QMessageBox, QToolTip { + background-color: #272730; +} + +/* Default settings for QWidget and its sub-classes */ +QWidget { + background-color: transparent; + color: #bebebe; + font-style: normal; + font-weight: normal; + font-size: 13px; +} + +QDockWidget { + titlebar-normal-icon: url(:/icons/sba_cmb_box_arrow_right.svg); +} + +QDockWidget::title { + background-color: transparent; +} + +QDockWidget::float-button { + background-color: transparent; + border: none; +} + +QDockWidget::float-button:hover { + background-color: rgba(255, 255, 255, 30); + padding: 2px; +} + +QDockWidget::float-button:hover { + background-color: rgba(0, 0, 0, 60); +} + +QToolTip { + padding: 6px; + border: 1px solid rgba(149, 152, 154, 150); + color: white; +} + +QLabel { + color: rgba(255, 255, 255, 150); + font-size: 13px; + font-style: normal; + font-weight: normal; + text-align: left; +} + +QLabel:disabled, QRadioButton:disabled {color: rgba(255, 255, 255, 80); } + +QLabel[invalid=true] { color: red; } + +QLabel[valid=true] { color: rgba(255, 255, 255, 150) } + +QTextBrowser { background-color: rgba(0, 0, 0, 150); } + +/* Apply a gradient to the MenuAnim widgets */ +adiscope--MenuAnim, adiscope--DMM #widget_2, .adiscope--PowerController #rightMenu { + background-color: qlineargradient(spread:pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgba(0, 0, 0, 40), stop: 0.15 transparent, stop: 0.85 transparent, stop: 1.0 rgba(0, 0, 0, 40)); +} + +/* Except for the tool launcher's MenuAnim */ +QMainWindow > .QWidget > .adiscope--MenuAnim { background-color: none; } + +QwtPlot, QwtPolarPlot, pv--view--Viewport, QWidget[plot_container=true]{ + background-color: black; +} + +/* QwtPlot should have a black background, except the sismographs */ +adiscope--Sismograph { background-color: transparent; } + +QwtPlotCanvas { background-color: #141416; } + +QwtPolarCanvas { background-color: none; } + +QwtScaleWidget { color: rgba(255, 255, 255, 180); } + +QwtThermo { + color: #999999; + font-size: 26px; +} + +adiscope--BufferPreviewer { + border: 1px solid #7092be; + alternate-background-color: #4a64ff; + selection-background-color: #141416; + selection-color: #ff7200; + color: white; +} + +QDial { + background-color: black; + color: #4963ff; +} + +QTabWidget::tab-bar { left: 0; } + +QTabWidget::pane { border-top: 0px; } + +QTabBar::tab { + min-width: 100px; + min-height: 32px; + padding-bottom: 5px; + font: normal; +} + +QTabBar::tab:selected { + color: white; + border-bottom: 2px solid #f36d0a; + margin-top: 0px; +} + +QTabBar::tab:!selected { + border-bottom: 2px solid #373740; +} + +QRadioButton { + color: white; + spacing: 12px; +} + +QRadioButton::indicator { + width: INDICATOR_SIZE; + height: INDICATOR_SIZE; + border: 2px solid; + border-radius: 9px; + border-color: #4963FF; +} + +QRadioButton::indicator:checked { background-color: #4963FF; } + +QRadioButton::indicator:disabled { border-color: #555555; } + +QRadioButton::indicator:checked:disabled { background-color: #555555; } + +QLineEdit { + color: white; + font-size: 16px; + border: 0px solid gray; + border-bottom: 1px solid rgba(255, 255, 255, 102); + padding: 2px; +} + +QLineEdit[valid=true]{ color: white; } +QLineEdit[invalid=true]{ color: red; } + +QComboBox { + height: 24px; + border: none; + font-size: 14px; + + border-bottom: 1px solid rgba(255, 255, 255, 102); + padding-bottom: 4px; +} + +QComboBox:disabled, QLineEdit:disabled { color: #555555; } + +QComboBox QAbstractItemView { + border: none; + background-color: #1b1b21; + text-align: left; + color: #bebebe; + outline: none; + + border-bottom: 1px solid #bebebe; + border-top: 1px solid #bebebe; +} + +/* This only works on Windows */ +QComboBox QAbstractItemView { + selection-background-color: #272730; +} + +/* This does not work on Windows */ +QComboBox::item:selected { + font-weight: bold; + font-size: 18px; + border-bottom: 0px solid none; + background-color: #272730; +} + +QComboBox::drop-down { + subcontrol-position: center right; + border-image: url(:/icons/sba_cmb_box_arrow.svg); + width: 10px; + height: 6px; + font-size: 16px; + text-align: left; +} + +QComboBox::indicator { + background-color: transparent; + selection-background-color: transparent; + color: transparent; + selection-color: transparent; +} + +QMessageBox QLabel { + height: 420px; + width: 680px; + color: rgba(255,255,255,240); + font-size: 14px; + font: bold; +} + +QMessageBox QPushButton { + height: 20px; + width: 120px; + background-color: #4a64ff; + color: white; + font-size: 16px; + font: bold; + border-radius: 5px; + border-color: #4a64ff; + border-style: solid; + border-width: 1px; +} + +QAbstractSpinBox { + height: 45px; + font-size: 16px; + font-weight: bold; + border-bottom: 1px solid rgba(255, 255, 255, 102); +} + +QAbstractSpinBox::up-button, QAbstractSpinBox::down-button { + height: 20px; + width: 20px; +} + +QAbstractSpinBox::up-button { border-image: url(:/icons/sba_up_btn.svg); } + +QAbstractSpinBox::up-button:hover { border-image: url(:/icons/sba_up_btn_hover.svg); } + +QAbstractSpinBox::up-button:pressed { border-image: url(:/icons/sba_up_btn_pressed.svg); } + +QAbstractSpinBox::down-button { border-image: url(:/icons/sba_dn_btn.svg); } + +QAbstractSpinBox::down-button:hover { border-image: url(:/icons/sba_dn_btn_hover.svg); } + +QAbstractSpinBox::down-button:pressed { border-image: url(:/icons/sba_dn_btn_pressed.svg); } + +QGroupBox { + border: 2px solid rgba(255, 255, 255, 40); + border-radius: 8px; + color: rgba(255, 255, 255, 40); + font-size: 16px; + font-weight: bold; + margin-top: 9px; + padding-top: 5px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; /* position at the top center */ +} + +QScrollBar:vertical { + background: #262628; + max-width: 8px; +} + +QScrollBar::handle:vertical { + background: #404040; + border: 0; + border-radius: 3px; +} +QScrollBar::handle:vertical:hover { + background: #4a4a4b; + border: 0; + border-radius: 3px; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } + +QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + border: none; + background: none; +} + +QScrollBar:horizontal { + background: #262628; + max-height: 6px; + border-radius: 3px; +} + +QScrollBar::handle:horizontal { + background: #404040; + border: 0; + border-radius: 3px; +} + +QScrollBar::handle:horizontal:hover { + background: #4a4a4b; + border: 0; + border-radius: 3px; +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } + +QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { + border: none; + background: none; +} + +QDialog { background-color: #1b1b21; } + +ScopyAboutDialog QPushButton{ + background-color: #4a64ff; + color: #ffffff; +} + +QTextBrowser#aboutTextBrowser{ + background-color: transparent; + link-color: yellow; + selection-color: yellow; + color: white; +} + +/* Label, line and arrow button dividers between sections */ + +QLabel[subsection_label=true]{ + font-size: 12px; + color: rgba(255, 255, 255, 70); +} + +QFrame[subsection_line=true]{ border: 1px solid rgba(255, 255, 255, 70); } + +QPushButton[subsection_arrow_button=true]{ + max-height: 6px; + max-width: 10px; + border-image: url(:/icons/sba_cmb_box_arrow.svg); +} + +QPushButton[subsection_arrow_button=true]:checked{ + max-height: 10px; + max-width: 6px; + border-image: url(:/icons/sba_cmb_box_arrow_right.svg); +} + + +/* Label associated with settings menu, right above a blue line divider */ + +QLabel[general_settings_label=true]{ + color: white; + font-size: 14px; + font-weight: normal; +} + +/* Blue line divider */ + +QFrame[blue_line=true]{ border: 2px solid #4A64FF; } + + +/* General style for blue buttons */ + +QPushButton[blue_button=true]{ + background-color: #4a64ff; + color: #ffffff; + border-radius: 4px; + font-size: 14px; +} + +QPushButton[blue_button=true]:pressed{ background-color: #2a44df; } + +#ifndef __ANDROID__ +QPushButton[blue_button=true]:hover{ background-color: #4a34ff; } +#endif + +QPushButton[blue_button=true]:disabled { background-color: grey; } + +/* Info button for each tool */ + +QPushButton[info_button=true]{ + min-height: 40px; + max-height: 40px; + min-width: 40px; + max-width: 40px; + background-color: transparent; + border-radius: 4px; +} + +#ifndef __ANDROID__ +QPushButton[info_button=true]:hover { background-color: rgba(0, 0, 0, 60); } +#endif + +/* Menu title label */ + +QLabel[menu_title_label=true]{ + color: white; + font-weight: normal; + font-size: 14px; +} + + +/* Style for all SpinBoxes */ + +QSpinBox{ + color: white; + border: 0px; + border-bottom: 1px solid rgba(255, 255, 255, 100); +} + + +QCheckBox { + spacing: 8px; + background-color: transparent; + font-size: 14px; + font-weight: bold; + color: rgba(255, 255, 255, 153); +} + +QCheckBox::indicator { + width: INDICATOR_SIZE; + height: INDICATOR_SIZE; + 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); } + + +QSlider::groove { + border: 1px solid #444444; + height: 2px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */ + background: #999999; + margin: 2px 0; + border-radius: 2px; +} + +QSlider::handle { + background: rgb(73, 99, 255); + border: 0px solid; + width: 18px; + margin: -8px 0; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */ + border-radius: 8px; +} + +QSlider::handle:disabled { background: #444444; } + +QSlider::sub-page:horizontal { background: #4A64FF; } + + +/* Style for settings and general settings buttons from all menus */ + +QPushButton[menu_icon_button=true] { + min-height: 40px; + max-height: 40px; + min-width: 60px; + max-width: 60px; + padding-top:5px +} + +QPushButton[menu_icon_button=true]:checked { border-top: 1px solid rgba(255,255,255,150); } + +QPushButton[menu_icon_button=true]:!checked { border-top: 1px solid rgba(255,255,255,0); } + +QPushButton[menu_icon_button=true]:!checked:hover { border-top: 1px solid rgba(255,255,255,0); } + +QPushButton[menu_icon_button=true]:checked:hover { border-top: 1px solid rgba(255,255,255,200); } + + +/* Style for all Tool launcher buttons, such as Home, Menu, Preferences, Load, Save, Notes, etc. */ + +QPushButton[tool_launcher_custom_widget=true] { + text-align:left; + border: none; + background-color: none; +} + +#ifndef __ANDROID__ +.QWidget[tool_launcher_custom_widget=true]:hover { + background-color: rgba(0, 0, 0, 60); + border: 1px solid rgba(0, 0, 0, 30); + border-radius:5px; +} +#endif + +#ifdef __ANDROID__ +.QWidget[tool_launcher_custom_widget=true]:pressed { + background-color: rgba(0, 0, 0, 60); + border: 1px solid rgba(0, 0, 0, 30); + border-radius:5px; +} +#endif + +QWidget[tool_launcher_custom_widget=true][selected=true] { + background-color: rgba(0, 0, 0, 60); + border: 1px solid rgba(0, 0, 0, 30); + border-radius:5px; +} + + +/* Style for icon-buttons such as Device, Home, Plus, etc. */ + +QWidget[menu_button=true][selected=true] { + opacity: 0.6; + border-radius: 4px; + background-color: #141416; +} + +QWidget[menu_button=true][selected=false] { background-color: transparent; } + + +/* Styles for DigitalIO widgets */ + +QWidget#page { + border-radius: 12px; + background-color: rgba(0, 0, 0, 80); +} + +QWidget#stackedWidgetPage1 { + border-radius: 12px; + background-color: #141416; +} + + +/* Background color for info page */ + +.adiscope--StackedHomepage#stackedWidget{ background-color: black; } + + +/* Style for all line separators */ + +QFrame[line_separator=true]{ background-color: rgba(255, 255, 255, 16); } + + +/* Background color for Voltmeter and Power Supply */ + +.adiscope--PowerController #leftPanel, .adiscope--DMM #leftPanel{ + background-color: rgba(0, 0, 0, 40); +} + + +/* Gradient background for all instruments */ + +.adiscope--Oscilloscope #mainWidget, .adiscope--SpectrumAnalyzer #mainWidget, +.adiscope--NetworkAnalyzer #mainWidget, .adiscope--SignalGenerator #mainWidget, +.adiscope--logic--LogicAnalyzer #mainWidget, .adiscope--logic--PatternGenerator #mainWidget, +.adiscope--DigitalIO #widget, .adiscope--DMM #hLayout_top_btn_area_voltmeter, .adiscope--PowerController #hWidget_top_area { + background-color: qlineargradient(spread:pad, x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 rgba(0, 0, 0, 40), stop: 0.1 transparent, stop: 1.0 transparent); +} + +/* Remove inherited gradient from the export setting of the Oscilloscope */ + +.adiscope--ExportSettings #mainWidget, .adiscope--ImportSettings #mainWidget { + background-color: none; +} + +adiscope--CursorReadouts { + background-color: black; +} + +QWidget[scopy_logo=true]{ + background-image: url(:/menu/scopy_title.png); + background-repeat: no-repeat; + background-position: left center; +} + +QPushButton[menu_icon=true]{ + background-image: url(:/menu/menu_button.png); + background-repeat: no-repeat; + background-position: left center; +} + +QWidget[adi_logo=true]{ + background-image: url(:/menu/adi.png); + background-repeat: no-repeat; + background-position: left center; + min-width: 104px; + min-height: 30px; +} + +QPushButton[save_logo=true]{ + background-image: url(:/icons/ic save.svg); + background-repeat: no-repeat; +} + +QPushButton[load_logo=true]{ + background-image: url(:/icons/ic load.svg); + background-repeat: no-repeat; + background-position: left center; +} + +QPushButton[preferences_icon=true]{ + background-image: url(:/menu/debugger.png); + background-repeat: no-repeat; + background-position: left center; + qproperty-text: "Preferences"; + text-align: center; +} + +QPushButton[general_settings_icon=true]:checked { + image: url(:/icons/gear_wheel_pressed.svg); +} + +QPushButton[general_settings_icon=true]:!checked { + image: url(:/icons/gear_wheel.svg); +} + + +QPushButton[general_settings_icon=true]:!checked:hover { + image: url(:/icons/gear_wheel_hover.svg); +} + +QPushButton[general_settings_icon=true]:checked:hover { + image: url(:/icons/gear_wheel_pressed.svg); +} + +QPushButton[settings_icon=true]:checked { + image: url(:/icons/setup3_checked_hover.svg); +} + +QPushButton[settings_icon=true]:!checked { + image: url(:/icons/setup3_unchecked.svg); +} + +QPushButton[settings_icon=true]:!checked:hover { + image: url(:/icons/setup3_unchecked_hover.svg); +} + +QPushButton[settings_icon=true]:checked:hover { + image: url(:/icons/setup3_checked_hover.svg); +} + +QHeaderView::section { + background-color: transparent; +} + +QHeaderView::section:checked { + background-color: transparent; +} + +/*************************************************************/ + + + +/************************** Channel widget **************************/ + +adiscope--ChannelWidget QWidget { + color: rgba(255, 255, 255, 153); + + border-width: 0px; + border-radius: 6px; +} + +/* Widget containing box, name, btn */ + +adiscope--ChannelWidget QWidget#widget { + background-color: transparent; + border-radius: 4px; +} +adiscope--ChannelWidget QWidget#widget[selected=true] { + background-color: rbga(20, 20, 22, 153); +} + +/* Round check box */ +adiscope--ChannelWidget QCheckBox#box{ + spacing: 0px; + background-color: none; + font-size: 14px; + font-weight: bold; +} + +adiscope--ChannelWidget QCheckBox#box::indicator { + width: INDICATOR_SIZE; + height: INDICATOR_SIZE; + border: 2px solid #000000; /* Will be overwritted in the ChannelWidget constructor */ + border-radius: 9px; +} + +adiscope--ChannelWidget QCheckBox#box::indicator:unchecked { + background-color: transparent; +} +adiscope--ChannelWidget QCheckBox#box::indicator:checked { + background-color: #000000; /* Will be overwritted in the ChannelWidget constructor */ +} + +/* Name */ +adiscope--ChannelWidget QPushButton#name { + font-size: 14px; + font-weight: bold; + background-color: none; +} + +/* Delete Button */ +adiscope--ChannelWidget QPushButton#delBtn { + width: 24px; + height: 24px; + background-color: transparent; + background-position: center center; + background-repeat: no-repeat; + background-image: url(:/icons/redX.svg); +} +adiscope--ChannelWidget QPushButton#delBtn::hover { + background-image: url(:/icons/redX.svg); +} + +/* Menu button */ +adiscope--ChannelWidget QPushButton#btn { + width: 40px; + height: 20px; + background-color: transparent; +} +adiscope--ChannelWidget QPushButton#btn:pressed { + border-image: url(:/icons/setup_btn_checked.svg) +} +adiscope--ChannelWidget QPushButton#btn:!pressed { + border-image: url(:/icons/setup_btn_unchecked.svg) +} +adiscope--ChannelWidget QPushButton#btn:hover:!pressed:!checked { + border-image: url(:/icons/setup_btn_hover.svg) +} +adiscope--ChannelWidget QPushButton#btn:checked { + border-image: url(:/icons/setup_btn_checked.svg) +} + +/* Underline */ +adiscope--ChannelWidget QFrame#line { + border: 2px solid transparent; +} +adiscope--ChannelWidget QFrame#line[selected=true] { + border: 2px solid #000000; /* Will be overwritted in the ChannelWidget constructor */ +} + +/*************************************************************/ + + + +/******************** Dropdown switch list ************************/ + +adiscope--DropdownSwitchList { + height: 30px; + border: 0px; + font-size: 18px; + border-radius: 4px; + padding-left: 20px; +} + +adiscope--DropdownSwitchList:editable{ + background-color: #141416; + color: white; +} + +adiscope--DropdownSwitchList::drop-down { + subcontrol-position: center right; + width: 10px; + height: 6px; + border-image: url(:/icons/sba_cmb_box_arrow.svg); + margin-right: 20px; +} + +adiscope--DropdownSwitchList QAbstractItemView { + border: 0px; + background-color: #141416; + font-size: 18px; + outline: 0px; + + /* Add left space. Color should match background-color*/ + border-left: 0px solid #141416; /* setting to 0 for now */ +} + +adiscope--DropdownSwitchList QAbstractItemView::item { + color: #ffffff; + height: 60px; +} + +adiscope--DropdownSwitchList QAbstractItemView::item:hover { + background-color: #141416; + font-weight: bold; + border-bottom: 0px solid none; +} + +adiscope--DropdownSwitchList QHeaderView { + /* Cancel the effect of the QAbstractItemView border-left property. It's + necessary because the border (or padding) of the QAbstractItemView applies to + this element as well. */ + padding-left: -0px; +} + +adiscope--DropdownSwitchList QHeaderView:section { + color: rgba(255, 255, 255, 153); + background-color: #141416; + border: 0px; + font: 14px; +} + +adiscope--DropdownSwitchList QCheckBox { + background-color: #141416; +} + +adiscope--DropdownSwitchList QCheckBox::indicator { + width: 16px; + height: 16px; + subcontrol-position: center; +} + +/*************************************************************/ + + + +/************************* SpinBoxes *************************/ + +adiscope--SpinBoxA QPushButton#SBA_UpButton { + width: 30px; + height: 30px; + border-image: url(:/icons/sba_up_btn.svg); + border: 0px; +} + +adiscope--SpinBoxA QPushButton#SBA_UpButton:pressed { + border-image: url(:/icons/sba_up_btn_pressed.svg); +} +adiscope--SpinBoxA QPushButton#SBA_UpButton:hover:!pressed { + border-image: url(:/icons/sba_up_btn_hover.svg); +} + +adiscope--SpinBoxA QPushButton#SBA_DownButton { + width: 30px; + height: 30px; + border-image: url(:/icons/sba_dn_btn.svg); + border: 0px; +} +adiscope--SpinBoxA QPushButton#SBA_DownButton:pressed { + border-image: url(:/icons/sba_dn_btn_pressed.svg); +} +adiscope--SpinBoxA QPushButton#SBA_DownButton:hover:!pressed { + border-image: url(:/icons/sba_dn_btn_hover.svg); +} + +adiscope--SpinBoxA QLabel#SBA_Label { + color: rgba(255, 255, 255, 102); + font-size: 14px; +} + +adiscope--SpinBoxA QLineEdit#SBA_LineEdit { + height: 20px; + width: 75px; + font-size: 18px; + border: 0px; + bottom: 10px; +} + +adiscope--SpinBoxA QFrame#SBA_Line { + color: #4a64ff; +} + +adiscope--SpinBoxA QFrame#SBA_Line:disabled { + color: #555555; +} + +adiscope--SpinBoxA QComboBox#SBA_Combobox { + height: 20px; + font-size: 12px; + font-weight: normal; + border-bottom: 0px; + padding-bottom: 0px; +} + +adiscope--SpinBoxA QComboBox#SBA_Combobox::drop-down { + subcontrol-position: center right; + width: 10px; + height: 6px; + border-image: url(:/icons/sba_cmb_box_arrow.svg); +} + +adiscope--SpinBoxA QComboBox#SBA_Combobox::drop-down:disabled { + subcontrol-position: center right; + width: 0px; + height: 0px; + border-image: url(:/icons/sba_cmb_box_arrow.svg); +} + +adiscope--SpinBoxA QDial#SBA_CompletionCircle { + background-color: black; + color: #4963ff; +} +/*************************************************************/ + + +/******************** Stop buttons *************************/ + +QPushButton[stopButton=true] { + background-repeat: no-repeat; + background-position: center center; +} + +QPushButton[stopButton=true]:enabled { + background-image: url(:/icons/ico-stop.svg); +} + +QPushButton[stopButton=true][disabled=true][enabled=false] { + background-image: url(:/icons/ico-stop.svg); +} + +QPushButton[stopButton=true]:checked { + background-image: url(:/icons/ico-play-green.svg); +} + +/*************************************************************/ + +/******************** User Notes *************************/ + +QPushButton[userNote=true] { + background-image: url(:/icons/ic_note_unchecked.svg); +} + +QPushButton[userNote=true]:checked { + background-image: url(:/icons/ic_note_checked.svg); +} + +/*************************************************************/ diff --git a/resources/stylesheets/templates/light.qss.c b/resources/stylesheets/templates/light.qss.c new file mode 100644 index 0000000000..cf28ac36dd --- /dev/null +++ b/resources/stylesheets/templates/light.qss.c @@ -0,0 +1,917 @@ +#include "values.h" + +/* Default background color */ +QMainWindow > .QWidget, adiscope--Sismograph > QwtPlotCanvas, QMessageBox, QToolTip { + background-color: #F7F7F7; +} + +/* Default settings for QWidget and its sub-classes */ +QWidget { + background-color: transparent; + color: #141416; + font-style: normal; + font-weight: normal; + font-size: 13px; +} + +QDockWidget { + titlebar-normal-icon: url(:/icons/scopy-light/icons/sba_cmb_box_arrow_right.svg); + background-color: #F7F7F7; +} + +QDockWidget::title { + background-color: transparent; +} + +QDockWidget::float-button { + background-color: transparent; + border: none; +} + +QDockWidget::float-button:hover { + background-color: rgba(0, 0, 0, 30); + padding: 2px; +} + +QDockWidget::float-button:hover { + background-color: rgba(0, 0, 0, 60); +} + +QToolTip { + padding: 6px; + border: 1px solid rgba(149, 152, 154, 150); + color: rgba(0, 0, 0, 200); +} + +QLabel { + color: rgba(0, 0, 0, 200); + font-size: 13px; + font-style: normal; + font-weight: normal; + text-align: left; +} + +QLabel:disabled, QRadioButton:disabled {color: rgba(0, 0, 0, 70); } + +QLabel[invalid=true] { color: red; } + +QLabel[valid=true] { color: rgba(0, 0, 0, 200); } + +QTextBrowser { background-color: #EDEDED; } + +/* Apply a gradient to the MenuAnim widgets */ +adiscope--MenuAnim, adiscope--DMM #widget_2, .adiscope--PowerController #rightMenu { + background-color: qlineargradient(spread:pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #EDEDED, stop: 0.15 #F7F7F7, stop: 0.85 #F7F7F7, stop: 1.0 #EDEDED); +} + +/* Except for the tool launcher's MenuAnim */ +QMainWindow > .QWidget > .adiscope--MenuAnim { background-color: none; } + +QwtPlot, QwtPolarPlot, pv--view--Viewport, QWidget[plot_container=true] { + background-color: white; +} + +/* QwtPlot should have a black background, except the sismographs */ +adiscope--Sismograph { background-color: transparent; } + +QwtPlotCanvas { background-color: white; } + +QwtPolarCanvas { background-color: none; } + +QwtScaleWidget { color: rgba(0, 0, 0, 180); } + +QwtThermo { + color: #999999; + font-size: 26px; +} + +adiscope--BufferPreviewer { + border: 1px solid #7092be; + alternate-background-color: #4a64ff; + selection-background-color: #F7F7F7; + selection-color: #ff7200; + color: white; +} + +QDial { + background-color: white; + color: #4963ff; +} + +QTabWidget::tab-bar { left: 0; } + +QTabWidget::pane { border-top: 0px; } + +QTabBar::tab { + min-width: 100px; + min-height: 32px; + padding-bottom: 5px; + font: normal; +} + +QTabBar::tab:selected { + color: #7D7D83; + border-bottom: 2px solid #f36d0a; + margin-top: 0px; +} + +QTabBar::tab:!selected { + border-bottom: 2px solid #7D7D83; +} + +QRadioButton { + color: rgba(0, 0, 0, 200); + spacing: 12px; +} + +QRadioButton::indicator { + width: INDICATOR_SIZE; + height: INDICATOR_SIZE; + border: 2px solid; + border-radius: 9px; + border-color: #4963FF; +} + +QRadioButton::indicator:checked { background-color: #4963FF; } + +QRadioButton::indicator:disabled { border-color: #C5C5C5; } + +QRadioButton::indicator:checked:disabled { background-color: #C5C5C5; } + +QLineEdit { + color: rgba(0, 0, 0, 200); + font-size: 16px; + border: 0px solid gray; + border-bottom: 1px solid rgba(0, 0, 0, 40); + padding: 2px; +} + +QLineEdit[valid=true]{ color: rgba(0, 0, 0, 200); } +QLineEdit[invalid=true]{ color: red; } + +QComboBox { + height: 24px; + border: none; + font-size: 14px; + + border-bottom: 1px solid rgba(0, 0, 0, 40); + padding-bottom: 4px; +} + +QComboBox:disabled, QLineEdit:disabled { color: rgba(0, 0, 0, 70); } + +QComboBox QAbstractItemView { + border: none; + background-color: white; + text-align: left; + color: black; + outline: none; + + border-bottom: 1px solid #bebebe; + border-top: 1px solid #bebebe; + + /* This only works on Windows */ + selection-color: black; + selection-background-color: #EDEDED; +} + +/* This does not work on Windows */ +QComboBox::item:selected { + font-weight: bold; + font-size: 18px; + border-bottom: 0px solid none; + background-color: #EDEDED; +} + +QComboBox::drop-down { + subcontrol-position: center right; + border-image: url(:/icons/scopy-light/icons/sba_cmb_box_arrow.svg); + width: 10px; + height: 6px; + font-size: 16px; + text-align: left; +} + +QComboBox::indicator { + background-color: transparent; + selection-background-color: transparent; + color: transparent; + selection-color: transparent; +} + +QMessageBox QLabel { + height: 420px; + width: 680px; + color: rgba(0, 0, 0, 200); + font-size: 14px; + font: bold; +} + +QMessageBox QPushButton { + height: 20px; + width: 120px; + background-color: #4a64ff; + color: white; + font-size: 16px; + font: bold; + border-radius: 5px; + border-color: #4a64ff; + border-style: solid; + border-width: 1px; +} + +QAbstractSpinBox { + height: 45px; + font-size: 16px; + font-weight: bold; + border-bottom: 1px solid rgba(0, 0, 0, 40); +} + +QAbstractSpinBox::up-button, QAbstractSpinBox::down-button { + height: 20px; + width: 20px; +} + +QAbstractSpinBox::up-button { border-image: url(:/icons/sba_up_btn.svg); } + +QAbstractSpinBox::up-button:hover { border-image: url(:/icons/sba_up_btn_hover.svg); } + +QAbstractSpinBox::up-button:pressed { border-image: url(:/icons/sba_up_btn_pressed.svg); } + +QAbstractSpinBox::down-button { border-image: url(:/icons/sba_dn_btn.svg); } + +QAbstractSpinBox::down-button:hover { border-image: url(:/icons/sba_dn_btn_hover.svg); } + +QAbstractSpinBox::down-button:pressed { border-image: url(:/icons/sba_dn_btn_pressed.svg); } + +QGroupBox { + border: 2px solid rgba(255, 255, 255, 40); + border-radius: 8px; + color: rgba(255, 255, 255, 40); + font-size: 16px; + font-weight: bold; + margin-top: 9px; + padding-top: 5px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; /* position at the top center */ +} + +QScrollBar:vertical { + background: #F7F7F7; + max-width: 8px; +} + +QScrollBar::handle:vertical { + background: #BEBEC1; + border: 0; + border-radius: 3px; +} +QScrollBar::handle:vertical:hover { + background: #7D7D83; + border: 0; + border-radius: 3px; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } + +QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + border: none; + background: none; +} + +QScrollBar:horizontal { + background: #F7F7F7; + max-height: 6px; + border-radius: 3px; +} + +QScrollBar::handle:horizontal { + background: #BEBEC1; + border: 0; + border-radius: 3px; +} + +QScrollBar::handle:horizontal:hover { + background: #7D7D83; + border: 0; + border-radius: 3px; +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } + +QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { + border: none; + background: none; +} + +QDialog { background-color: white; } + +ScopyAboutDialog QPushButton{ + background-color: #4a64ff; + color: #ffffff; +} + +QTextBrowser#aboutTextBrowser{ + background-color: transparent; + link-color: yellow; + selection-color: yellow; + color: rgba(0, 0, 0, 200); +} + +/* Label, line and arrow button dividers between sections */ + +QLabel[subsection_label=true]{ + font-size: 12px; + color: rgba(0, 0, 0, 70); +} + +QFrame[subsection_line=true]{ border: 1px solid rgba(0, 0, 0, 50); } + +QPushButton[subsection_arrow_button=true]{ + max-height: 6px; + max-width: 10px; + border-image: url(:/icons/scopy-light/icons/sba_cmb_box_arrow.svg); +} + +QPushButton[subsection_arrow_button=true]:checked{ + max-height: 10px; + max-width: 6px; + border-image: url(:/icons/scopy-light/icons/sba_cmb_box_arrow_right.svg); +} + + +/* Label associated with settings menu, right above a blue line divider */ + +QLabel[general_settings_label=true]{ + color: rgba(0, 0, 0, 200); + font-size: 14px; + font-weight: normal; +} + +/* Blue line divider */ + +QFrame[blue_line=true]{ border: 2px solid #4A64FF; } + + +/* General style for blue buttons */ + +QPushButton[blue_button=true]{ + background-color: #4a64ff; + color: #ffffff; + border-radius: 4px; + font-size: 14px; +} + +QPushButton[blue_button=true]:pressed{ background-color: #2a44df; } + +#ifndef __ANDROID__ +QPushButton[blue_button=true]:hover{ background-color: #4a34ff; } +#endif + +QPushButton[blue_button=true]:disabled { background-color: grey; } + +/* Info button for each tool */ + +QPushButton[info_button=true]{ + min-height: 40px; + max-height: 40px; + min-width: 40px; + max-width: 40px; + background-color: transparent; + border-radius: 4px; +} + +#ifndef __ANDROID__ +QPushButton[info_button=true]:hover { background-color: rgba(0, 0, 0, 60); } +#endif + +/* Menu title label */ + +QLabel[menu_title_label=true]{ + color: rgba(0, 0, 0, 200); + font-weight: normal; + font-size: 14px; +} + + +/* Style for all SpinBoxes */ + +QSpinBox{ + color: rgba(0, 0, 0, 200); + border: 0px; + border-bottom: 1px solid rgba(0, 0, 0, 40); +} + + +QCheckBox { + spacing: 8px; + background-color: transparent; + font-size: 14px; + font-weight: normal; + color: rgba(0, 0, 0, 200); +} + +QCheckBox::indicator { + width: INDICATOR_SIZE; + height: INDICATOR_SIZE; + 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); } + + +QSlider::groove { + border: 1px solid #444444; + height: 2px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */ + background: #999999; + margin: 2px 0; + border-radius: 2px; +} + +QSlider::handle { + background: rgb(73, 99, 255); + border: 0px solid; + width: 18px; + margin: -8px 0; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */ + border-radius: 8px; +} + +QSlider::handle:disabled { background: #444444; } + +QSlider::sub-page:horizontal { background: #4A64FF; } + + +/* Style for settings and general settings buttons from all menus */ + +QPushButton[menu_icon_button=true] { + min-height: 40px; + max-height: 40px; + min-width: 60px; + max-width: 60px; + padding-top:5px +} + +QPushButton[menu_icon_button=true]:checked { border-top: 1px solid rgba(0, 0, 0, 150); } + +QPushButton[menu_icon_button=true]:!checked { border-top: 1px solid rgba(0, 0, 0, 0); } + +QPushButton[menu_icon_button=true]:!checked:hover { border-top: 1px solid rgba(0, 0, 0, 0); } + +QPushButton[menu_icon_button=true]:checked:hover { border-top: 1px solid rgba(0, 0, 0, 200); } + + +/* Style for all Tool launcher buttons, such as Home, Menu, Preferences, Load, Save, Notes, etc. */ + +QPushButton[tool_launcher_custom_widget=true] { + text-align:left; + border: none; + background-color: none; +} + +#ifndef __ANDROID__ +.QWidget[tool_launcher_custom_widget=true]:hover { + background-color: rgba(0, 0, 0, 60); + border: 1px solid rgba(0, 0, 0, 30); + border-radius:5px; +} +#endif + +#ifdef __ANDROID__ +.QWidget[tool_launcher_custom_widget=true]:pressed { + background-color: rgba(0, 0, 0, 60); + border: 1px solid rgba(0, 0, 0, 30); + border-radius:5px; +} +#endif + +QWidget[tool_launcher_custom_widget=true][selected=true] { + background-color: rgba(0, 0, 0, 60); + border: 1px solid rgba(0, 0, 0, 30); + border-radius:5px; +} + + +/* Style for icon-buttons such as Device, Home, Plus, etc. */ + +QWidget[menu_button=true][selected=true] { + opacity: 0.6; + border-radius: 4px; + background-color: #C5C5C5; +} + +QWidget[menu_button=true][selected=false] { background-color: transparent; } + + +/* Styles for DigitalIO widgets */ + +QWidget#page { + border-radius: 12px; + background-color: rgba(0, 0, 0, 40); +} + +QWidget#stackedWidgetPage1 { + border-radius: 12px; + background-color: rgba(0, 0, 0, 80); +} + + +/* Background color for info page */ + +.adiscope--StackedHomepage#stackedWidget{ background-color: #EDEDED; } + + +/* Style for all line separators */ + +QFrame[line_separator=true]{ background-color: rgba(0, 0, 0, 20); } + + +/* Background color for Voltmeter and Power Supply */ + +.adiscope--PowerController #leftPanel, .adiscope--DMM #leftPanel{ + background-color: #EDEDED; +} + + +/* Gradient background for all instruments */ + +.adiscope--Oscilloscope #mainWidget, .adiscope--SpectrumAnalyzer #mainWidget, +.adiscope--NetworkAnalyzer #mainWidget, .adiscope--SignalGenerator #mainWidget, +.adiscope--logic--LogicAnalyzer #mainWidget, .adiscope--logic--PatternGenerator #mainWidget, +.adiscope--DigitalIO #widget, .adiscope--DMM #hLayout_top_btn_area_voltmeter, .adiscope--PowerController #hWidget_top_area { + background-color: qlineargradient(spread:pad, x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #EDEDED, stop: 0.1 #F7F7F7, stop: 1.0 #F7F7F7); +} + +/* Remove inherited gradient from the export setting of the Oscilloscope */ + +.adiscope--ExportSettings #mainWidget, .adiscope--ImportSettings #mainWidget { + background-color: none; +} + +adiscope--CursorReadouts { + background-color: white; +} + +QWidget[scopy_logo=true]{ + background-image: url(:/icons/scopy-light/icons/logo.png); + background-repeat: no-repeat; + background-position: left center; +} + +QPushButton[menu_icon=true]{ + background-image: url(:/icons/scopy-light/icons/menu.png); + background-repeat: no-repeat; + background-position: left center; +} + +QWidget[adi_logo=true]{ + background-image: url(:/icons/scopy-light/icons/logo analog.png); + background-repeat: no-repeat; + background-position: left center; + min-width: 104px; + min-height: 30px; +} + +QPushButton[save_logo=true]{ + background-image: url(:/icons/scopy-light/icons/ic save.svg); + background-repeat: no-repeat; +} + +QPushButton[load_logo=true]{ + background-image: url(:/icons/scopy-light/icons/ic load.svg); + background-repeat: no-repeat; + background-position: left center; +} + +QPushButton[preferences_icon=true]{ + background-image: url(:/icons/scopy-light/icons/Gear.png); + background-repeat: no-repeat; + background-position: left center; + qproperty-text: "Preferences"; + text-align: center; +} + +QPushButton[general_settings_icon=true]:checked { + image: url(:/icons/scopy-light/icons/gear_wheel_pressed.svg); +} + +QPushButton[general_settings_icon=true]:!checked { + image: url(:/icons/scopy-light/icons/Gear.png); +} + + +QPushButton[general_settings_icon=true]:!checked:hover { + image: url(:/icons/scopy-light/icons/gear_wheel_hover.png); +} + +QPushButton[general_settings_icon=true]:checked:hover { + image: url(:/icons/scopy-light/icons/gear_wheel_pressed.svg); +} + +QPushButton[settings_icon=true]:checked { + image: url(:/icons/scopy-light/icons/setup3_checked_hover.svg); +} + +QPushButton[settings_icon=true]:!checked { + image: url(:/icons/scopy-light/icons/setup3_unchecked.png); +} + +QPushButton[settings_icon=true]:!checked:hover { + image: url(:/icons/scopy-light/icons/setup3_unchecked_hover.png); +} + +QPushButton[settings_icon=true]:checked:hover { + image: url(:/icons/scopy-light/icons/setup3_checked_hover.svg); +} + +QHeaderView::section { + background-color: #D3D3D3; +} + +QHeaderView::section:checked { + background-color: #D3D3D3; +} + +/*************************************************************/ + + + +/*********************** Channel widget *******************/ + +adiscope--ChannelWidget QWidget { + color: rgba(0, 0, 0, 170); + + border-width: 0px; + border-radius: 6px; +} + +/* Widget containing box, name, btn */ +adiscope--ChannelWidget QWidget#widget { + background-color: transparent; + border-radius: 4px; +} +adiscope--ChannelWidget QWidget#widget[selected=true] { + background-color: rbga(0, 0, 0, 40); +} + +/* Round check box */ +adiscope--ChannelWidget QCheckBox#box{ + spacing: 0px; + background-color: none; + font-size: 14px; + font-weight: bold; +} + +adiscope--ChannelWidget QCheckBox#box::indicator { + width: INDICATOR_SIZE; + height: INDICATOR_SIZE; + border: 2px solid #000000; /* Will be overwritted in the ChannelWidget constructor */ + border-radius: 9px; +} + +adiscope--ChannelWidget QCheckBox#box::indicator:unchecked { + background-color: transparent; +} +adiscope--ChannelWidget QCheckBox#box::indicator:checked { + background-color: #000000; /* Will be overwritted in the ChannelWidget constructor */ +} + +/* Name */ +adiscope--ChannelWidget QPushButton#name { + font-size: 14px; + font-weight: bold; + background-color: none; +} + +/* Delete Button */ +adiscope--ChannelWidget QPushButton#delBtn { + width: 24px; + height: 24px; + background-color: transparent; + background-position: center center; + background-repeat: no-repeat; + background-image: url(:/icons/redX.svg); +} +adiscope--ChannelWidget QPushButton#delBtn::hover { + background-image: url(:/icons/redX.svg); +} + +/* Menu button */ +adiscope--ChannelWidget QPushButton#btn { + width: 40px; + height: 20px; + background-color: transparent; +} +adiscope--ChannelWidget QPushButton#btn:pressed { + border-image: url(:/icons/setup_btn_checked.svg) +} +adiscope--ChannelWidget QPushButton#btn:!pressed { + border-image: url(:/icons/setup_btn_unchecked.svg) +} +adiscope--ChannelWidget QPushButton#btn:hover:!pressed:!checked { + border-image: url(:/icons/setup_btn_hover.svg) +} +adiscope--ChannelWidget QPushButton#btn:checked { + border-image: url(:/icons/setup_btn_checked.svg) +} + +/* Underline */ +adiscope--ChannelWidget QFrame#line { + border: 2px solid transparent; +} +adiscope--ChannelWidget QFrame#line[selected=true] { + border: 2px solid #000000; /* Will be overwritted in the ChannelWidget constructor */ +} + +/*************************************************************/ + + + +/******************* Dropdown ***************/ + +adiscope--DropdownSwitchList { + height: 30px; + border: 0px; + font-size: 18px; + border-radius: 4px; + padding-left: 20px; +} + +adiscope--DropdownSwitchList:editable{ + background-color: white; + color: rgba(0, 0, 0, 200); +} + +adiscope--DropdownSwitchList::drop-down { + subcontrol-position: center right; + width: 10px; + height: 6px; + border-image: url(:/icons/scopy-light/icons/sba_cmb_box_arrow.svg); + margin-right: 20px; +} + +adiscope--DropdownSwitchList QAbstractItemView { + border: 0px; + background-color: white; + font-size: 18px; + outline: 0px; + + /* Add left space. Color should match background-color*/ + border-left: 0px solid white; /* setting to 0 for now */ +} + +adiscope--DropdownSwitchList QAbstractItemView::item { + color: rgba(0, 0, 0, 200); + height: 60px; +} + +adiscope--DropdownSwitchList QAbstractItemView::item:hover { + background-color: #EDEDED; + font-weight: bold; + border-bottom: 0px solid none; +} + +adiscope--DropdownSwitchList QHeaderView { + /* Cancel the effect of the QAbstractItemView border-left property. It's + necessary because the border (or padding) of the QAbstractItemView applies to + this element as well. */ + padding-left: -0px; +} + +adiscope--DropdownSwitchList QHeaderView:section { + color: rgba(0, 0, 0, 200); + background-color: white; + border: 0px; + font: 14px; +} + +adiscope--DropdownSwitchList QCheckBox { + background-color: white; +} + +adiscope--DropdownSwitchList QCheckBox::indicator { + width: 16px; + height: 16px; + subcontrol-position: center; +} + +/*************************************************************/ + + + +/**************** SpinBoxes *****************/ + +adiscope--SpinBoxA QPushButton#SBA_UpButton { + width: 30px; + height: 30px; + border-image: url(:/icons/sba_up_btn.svg); + border: 0px; +} + +adiscope--SpinBoxA QPushButton#SBA_UpButton:pressed { + border-image: url(:/icons/sba_up_btn_pressed.svg); +} +adiscope--SpinBoxA QPushButton#SBA_UpButton:hover:!pressed { + border-image: url(:/icons/sba_up_btn_hover.svg); +} + +adiscope--SpinBoxA QPushButton#SBA_DownButton { + width: 30px; + height: 30px; + border-image: url(:/icons/sba_dn_btn.svg); + border: 0px; +} +adiscope--SpinBoxA QPushButton#SBA_DownButton:pressed { + border-image: url(:/icons/sba_dn_btn_pressed.svg); +} +adiscope--SpinBoxA QPushButton#SBA_DownButton:hover:!pressed { + border-image: url(:/icons/sba_dn_btn_hover.svg); +} + +adiscope--SpinBoxA QLabel#SBA_Label { + color: rgba(0, 0, 0, 200); + font-size: 14px; +} + +adiscope--SpinBoxA QLineEdit#SBA_LineEdit { + height: 20px; + width: 75px; + font-size: 18px; + border: 0px; + bottom: 10px; +} + +adiscope--SpinBoxA QFrame#SBA_Line { + color: #4a64ff; +} + +adiscope--SpinBoxA QFrame#SBA_Line:disabled { + color: #555555; +} + +adiscope--SpinBoxA QComboBox#SBA_Combobox { + height: 20px; + font-size: 12px; + font-weight: normal; + border-bottom: 0px; + padding-bottom: 0px; +} + +adiscope--SpinBoxA QComboBox#SBA_Combobox::drop-down { + subcontrol-position: center right; + width: 10px; + height: 6px; + border-image: url(:/icons/scopy-light/icons/sba_cmb_box_arrow.svg); +} + +adiscope--SpinBoxA QComboBox#SBA_Combobox::drop-down:disabled { + subcontrol-position: center right; + width: 0px; + height: 0px; + border-image: url(:/icons/scopy-light/icons/sba_cmb_box_arrow.svg); +} + +adiscope--SpinBoxA QDial#SBA_CompletionCircle { + background-color: #C5C5C5; + color: #4963ff; +} + +/*************************************************************/ + + +/******************** Stop buttons *************************/ + +QPushButton[stopButton=true] { + background-repeat: no-repeat; + background-position: center center; +} + +QPushButton[stopButton=true]:enabled { + background-image: url(:/icons/scopy-light/icons/ico-stop.svg); +} + +QPushButton[stopButton=true][disabled=true][enabled=false] { + background-image: url(:/icons/scopy-light/icons/ico-stop.svg); +} + +QPushButton[stopButton=true]:checked { + background-image: url(:/icons/scopy-light/icons/ico-play-green.svg); +} + +/*************************************************************/ + +/******************** User Notes *************************/ + +QPushButton[userNote=true] { + background-image: url(:/icons/scopy-light/icons/ic_note_unchecked.svg); +} + +QPushButton[userNote=true]:checked { + background-image: url(:/icons/scopy-light/icons/ic_note_checked.svg); +} + +/*************************************************************/ diff --git a/resources/stylesheets/templates/values.h b/resources/stylesheets/templates/values.h new file mode 100644 index 0000000000..5f2b3486b7 --- /dev/null +++ b/resources/stylesheets/templates/values.h @@ -0,0 +1,7 @@ +#ifdef __ANDROID__ + #define INDICATOR_SIZE 18px +#endif + +#ifndef __ANDROID__ + #define INDICATOR_SIZE 14px +#endif diff --git a/resources/svg_sketch.zip b/resources/svg_sketch.zip new file mode 100644 index 0000000000..3c5400cbcb Binary files /dev/null and b/resources/svg_sketch.zip differ diff --git a/scopy-32.iss.cmakein b/scopy-32.iss.cmakein index 39e573b98c..45b3bf7367 100644 --- a/scopy-32.iss.cmakein +++ b/scopy-32.iss.cmakein @@ -2,7 +2,7 @@ #define AppName "Scopy" #define AppDev "Analog Devices" #define Python "@PYTHON_VERSION@" -#define DriverVersion "0.7" +#define DriverVersion "0.8" [Setup] AppId={{02A7A7F9-F068-4B1C-85F6-B6D325938E19} @@ -15,8 +15,8 @@ AppUpdatesURL="http://www.analog.com" AppCopyright="Copyright 2018 Analog Devices, Inc." CreateAppDir=yes OutputBaseFilename=scopy-32-setup -LicenseFile="C:\projects\scopy\LICENSE" -OutputDir="C:\" +LicenseFile="C:\msys64\home\docker\scopy\LICENSE" +OutputDir="C:\msys64\home\docker\" AllowNoIcons=yes Compression=lzma SolidCompression=yes @@ -247,7 +247,7 @@ Name: "drivers"; Description: Install drivers for ADALM2000; Check: not isDriver 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 +Source: "c:\msys64\home\docker\scopy_i686\*"; DestDir: "{app}"; Check: not Is64BitInstallMode; Flags: ignoreversion recursesubdirs createallsubdirs [Icons] Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}" diff --git a/scopy-64.iss.cmakein b/scopy-64.iss.cmakein index ddaf9f0de1..0b5f6c3ccf 100644 --- a/scopy-64.iss.cmakein +++ b/scopy-64.iss.cmakein @@ -2,7 +2,7 @@ #define AppName "Scopy" #define AppDev "Analog Devices" #define Python "@PYTHON_VERSION@" -#define DriverVersion "0.7" +#define DriverVersion "0.8" [Setup] AppId={{02A7A7F9-F068-4B1C-85F6-B6D325938E19} @@ -15,8 +15,8 @@ AppUpdatesURL="http://www.analog.com" AppCopyright="Copyright 2018 Analog Devices, Inc." CreateAppDir=yes OutputBaseFilename=scopy-64-setup -LicenseFile="C:\projects\scopy\LICENSE" -OutputDir="C:\" +LicenseFile="C:\msys64\home\docker\scopy\LICENSE" +OutputDir="C:\msys64\home\docker\" AllowNoIcons=yes Compression=lzma SolidCompression=yes @@ -249,7 +249,7 @@ Name: "drivers"; Description: Install drivers for ADALM2000; Check: not isDriver 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 +Source: "c:\msys64\home\docker\scopy_x86_64\*"; DestDir: "{app}"; Check: Is64BitInstallMode; Flags: ignoreversion recursesubdirs createallsubdirs [Icons] Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}" diff --git a/scopy.iss.cmakein b/scopy.iss.cmakein index c37ae5a061..8e70afa04b 100644 --- a/scopy.iss.cmakein +++ b/scopy.iss.cmakein @@ -2,7 +2,7 @@ #define AppName "Scopy" #define AppDev "Analog Devices" #define Python "@PYTHON_VERSION@" -#define DriverVersion "0.7" +#define DriverVersion "0.8" [Setup] AppId={{02A7A7F9-F068-4B1C-85F6-B6D325938E19} @@ -15,8 +15,8 @@ AppUpdatesURL="http://www.analog.com" AppCopyright="Copyright 2018 Analog Devices, Inc." CreateAppDir=yes OutputBaseFilename=scopy-setup -LicenseFile="C:\projects\scopy\LICENSE" -OutputDir="C:\" +LicenseFile="C:\msys64\home\docker\scopy\LICENSE" +OutputDir="C:\msys64\home\docker\" AllowNoIcons=yes Compression=lzma SolidCompression=yes @@ -247,8 +247,8 @@ Name: "drivers"; Description: Install drivers for ADALM2000; Check: not isDriver 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 -Source: "c:\scopy_32\*"; DestDir: "{app}"; Check: not Is64BitInstallMode; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "c:\msys64\home\docker\scopy_x86_64\*"; DestDir: "{app}"; Check: Is64BitInstallMode; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "c:\msys64\home\docker\scopy_i686\*"; DestDir: "{app}"; Check: not Is64BitInstallMode; Flags: ignoreversion recursesubdirs createallsubdirs [Icons] diff --git a/src/BasicPlot.cpp b/src/BasicPlot.cpp new file mode 100644 index 0000000000..b71c97dd61 --- /dev/null +++ b/src/BasicPlot.cpp @@ -0,0 +1,169 @@ +#include "BasicPlot.h" + +#include +#include +#include +#include + +#include +#include + +namespace adiscope { + +int BasicPlot::staticPlotId = 0; +BasicPlot::BasicPlot(QWidget* parent) : QwtPlot(parent), started(false), replotFrameRate(60), debug(false) +{ + useOpenGlCanvas = getToolLauncherInstance()->isOpenGlLoaded(); + connect(&replotTimer,SIGNAL(timeout()),this,SLOT(replotNow())); + + if(useOpenGlCanvas) { + QwtPlotOpenGLCanvas* plotCanvas = qobject_cast< QwtPlotOpenGLCanvas* >( canvas() ); + if ( plotCanvas == NULL ) + { + plotCanvas = new QwtPlotOpenGLCanvas(this); + plotCanvas->setPaintAttribute(QwtPlotAbstractGLCanvas::BackingStore ); +#ifdef IMMEDIATE_PAINT + plotCanvas->setPaintAttribute(QwtPlotAbstractGLCanvas::ImmediatePaint, true); +#endif + setCanvas( plotCanvas ); + } else { + ; + } + } else { + QwtPlotCanvas *plotCanvas = qobject_cast( canvas() ); + plotCanvas->setPaintAttribute(QwtPlotCanvas::BackingStore, true); +#ifdef IMMEDIATE_PAINT + plotCanvas->setPaintAttribute(QwtPlotCanvas::ImmediatePaint, true); +#endif + } + + qDebug(CAT_PLOT)< fpsLabelRefreshTime) { + QString rendering = (useOpenGlCanvas) ? "OpenGl rendering" : "Software rendering"; + fpsTxt.setText(rendering + "\n" + + "instrument: " + QString::number(1000.0 / instrumentCycleAvg) + " fps / " + QString::number(instrumentCycleAvg) + " ms" + "\n" +#ifdef IMMEDIATE_PAINT + + "plot: " + QString::number(replotTheoreticalFpsAvg) + "fps / " + QString::number(replotDurationAvg) + " ms" +#endif + ); + fpsLabel.setText(fpsTxt); + fpsLabelTimer.restart(); + } +} + +void BasicPlot::replot() { +#ifdef IMMEDIATE_PAINT + if(!replotTimer.isActive()) { + replotTimer.setSingleShot(true); + replotTimer.start(1000.0/replotFrameRate); + } + else + { + if(debug) qDebug(CAT_PLOT)< +#include +#include +#include +#include +#include +#include + + +/*Qt includes*/ +#include +#include +#include + +/*Own includes */ +#include + +//#define IMMEDIATE_PAINT + +namespace adiscope { + +class BasicPlot : public QwtPlot +{ + Q_OBJECT +public: + BasicPlot(QWidget* parent); + +public Q_SLOTS: + void start(); + void startStop(bool en = true); + void stop(); + bool isStarted(); + + void setRefreshRate(double hz); + double getRefreshRate(); + + void replotNow(); + void setVisibleFpsLabel(bool vis); + void hideFpsLabel(); + void showFpsLabel(); + void replot() override; + +protected: + QTimer replotTimer; +private: + static int staticPlotId; + bool started; + bool debug; + bool useOpenGlCanvas; + double replotFrameRate; + int id = 0; + MovingAverage pfps, pms; + MovingAverage ifps, ims; + const int fpsHistoryCount = 30; + const int fpsLabelRefreshTime = 500; + QwtPlotTextLabel fpsLabel; + QwtText fpsTxt; + QElapsedTimer fpsTimer; + QElapsedTimer fpsLabelTimer; + + +}; + +} + +#endif // BASICPLOT_H diff --git a/src/ConstellationDisplayPlot.cc b/src/ConstellationDisplayPlot.cc index f5e551e642..eb19cb1acb 100644 --- a/src/ConstellationDisplayPlot.cc +++ b/src/ConstellationDisplayPlot.cc @@ -108,13 +108,13 @@ ConstellationDisplayPlot::ConstellationDisplayPlot(int nplots, QWidget* parent) d_zoomer[0]->setRubberBandPen(c); d_zoomer[0]->setTrackerPen(c); -// setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); +// setAxisScaleEngine(QwtAxis::XBottom, new QwtLinearScaleEngine); // set_xaxis(-2.0, 2.0); -// setAxisTitle(QwtPlot::xBottom, "In-phase"); +// setAxisTitle(QwtAxis::XBottom, "In-phase"); -// setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); +// setAxisScaleEngine(QwtAxis::YLeft, new QwtLinearScaleEngine); // set_yaxis(-2.0, 2.0); -// setAxisTitle(QwtPlot::yLeft, "Quadrature"); +// setAxisTitle(QwtAxis::YLeft, "Quadrature"); updateAxes(); // Setup dataPoints and plot vectors @@ -192,7 +192,7 @@ ConstellationDisplayPlot::set_pen_size(int size) void ConstellationDisplayPlot::replot() { - QwtPlot::replot(); + BasicPlot::replot(); } diff --git a/src/DisplayPlot.cc b/src/DisplayPlot.cc index 7157c9d374..f5782993f6 100644 --- a/src/DisplayPlot.cc +++ b/src/DisplayPlot.cc @@ -58,6 +58,7 @@ #include #include #include +#include using namespace adiscope; @@ -396,11 +397,11 @@ PlotAxisConfiguration::PlotAxisConfiguration(int axisPos, int axisIdx, DisplayPl Qt::CursorShape shape; switch (axisPos) { - case QwtPlot::yLeft: + case QwtAxis::YLeft: shape = Qt::CursorShape::SizeVerCursor; break; - case QwtPlot::xBottom: + case QwtAxis::XBottom: shape = Qt::CursorShape::SizeHorCursor; break; @@ -413,7 +414,7 @@ PlotAxisConfiguration::PlotAxisConfiguration(int axisPos, int axisIdx, DisplayPl // Avoid jumping when labels with more/less digits // appear/disappear when scrolling vertically - if (axisPos == QwtPlot::yLeft) { + if (axisPos == QwtAxis::YLeft) { const QFontMetrics fm(d_plot->axisWidget(d_axis)->font()); QwtScaleDraw *scaleDraw = d_plot->axisScaleDraw(d_axis); scaleDraw->setMinimumExtent( fm.width("100.00") ); @@ -429,7 +430,7 @@ PlotAxisConfiguration::PlotAxisConfiguration(int axisPos, int axisIdx, DisplayPl d_ptsPerDiv = 1.0; d_offset = 0.0; - if (axisPos == QwtPlot::yLeft) { + if (axisPos == QwtAxis::YLeft) { d_mouseGestures = new VertMouseGestures(d_plot->axisWidget(d_axis), d_axis); d_mouseGestures->setEnabled(false); @@ -442,7 +443,7 @@ PlotAxisConfiguration::PlotAxisConfiguration(int axisPos, int axisIdx, DisplayPl d_plot, SLOT(onVertAxisOffsetDecrease())); QObject::connect(this->d_mouseGestures, SIGNAL(downMovement(double)), d_plot, SLOT(onVertAxisOffsetIncrease())); - } else if (axisPos == QwtPlot::xBottom) { + } else if (axisPos == QwtAxis::XBottom) { d_mouseGestures = new HorizMouseGestures(d_plot->axisWidget(d_axis), d_axis); d_mouseGestures->setEnabled(false); @@ -508,7 +509,6 @@ void PlotAxisConfiguration::setMouseGesturesEnabled(bool en) /* * DisplayPlot class */ - DisplayPlot::DisplayPlot(int nplots, QWidget* parent, bool isdBgraph, unsigned int xNumDivs, unsigned int yNumDivs) : PrintablePlot(parent), d_nplots(nplots), d_stop(false), @@ -559,7 +559,7 @@ DisplayPlot::DisplayPlot(int nplots, QWidget* parent, bool isdBgraph, setPaletteColor(default_palette_color); d_panner = new QwtPlotPanner(canvas()); - d_panner->setAxisEnabled(QwtPlot::yRight, false); + d_panner->setAxisEnabled(QwtAxis::YRight, false); d_panner->setMouseButton(Qt::MidButton, Qt::ControlModifier); // emit the position of clicks on widget @@ -592,10 +592,10 @@ DisplayPlot::DisplayPlot(int nplots, QWidget* parent, bool isdBgraph, 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, QwtAxis::YLeft); + this->plotLayout()->setCanvasMargin(0, QwtAxis::YRight); + this->plotLayout()->setCanvasMargin(0, QwtAxis::XTop); + this->plotLayout()->setCanvasMargin(0, QwtAxis::XBottom); ((QFrame*) canvas())->setLineWidth(0); @@ -664,7 +664,7 @@ void DisplayPlot::setupDisplayPlotDiv(bool isdBgraph) { scaleItem->scaleDraw()->setAlignment(scale); scaleItem->scaleDraw()->enableComponent(QwtAbstractScaleDraw::Backbone, false); scaleItem->scaleDraw()->enableComponent(QwtAbstractScaleDraw::Labels, false); - scaleItem->setFont(this->axisWidget(QwtPlot::yLeft)->font()); + scaleItem->setFont(this->axisWidget(QwtAxis::YLeft)->font()); QPalette palette = scaleItem->palette(); palette.setBrush(QPalette::Foreground, QColor("#6E6E6F")); @@ -807,7 +807,7 @@ void DisplayPlot::setupReadouts() { d_cursorReadoutsVisible = false; d_cursorReadouts = new CursorReadouts(this); - d_cursorReadouts->setAxis(QwtPlot::xTop,QwtPlot::yLeft); + d_cursorReadouts->setAxis(QwtAxis::XTop,QwtAxis::YLeft); d_cursorReadouts->setTopLeftStartingPoint(QPoint(8, 8)); d_cursorReadouts->setTimeReadoutVisible(false); d_cursorReadouts->setVoltageReadoutVisible(false); @@ -1171,17 +1171,17 @@ void DisplayPlot::displayIntersection() attachmk2 = false; } - bool value = isAxisValid(QwtAxisId(QwtPlot::yLeft, d_selected_channel)); + bool value = isAxisValid(QwtAxisId(QwtAxis::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)); + markerIntersection1->setAxes(QwtAxis::XBottom, QwtAxisId(QwtAxis::YLeft, d_selected_channel)); + markerIntersection2->setAxes(QwtAxis::XBottom, QwtAxisId(QwtAxis::YLeft, d_selected_channel)); } else { - markerIntersection1->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, 0)); - markerIntersection2->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, 0)); + markerIntersection1->setAxes(QwtAxis::XBottom, QwtAxisId(QwtAxis::YLeft, 0)); + markerIntersection2->setAxes(QwtAxis::XBottom, QwtAxisId(QwtAxis::YLeft, 0)); } markerIntersection1->setValue(d_vBar1->plotCoord().x(), intersectionCursor1); @@ -1276,7 +1276,7 @@ void DisplayPlot::setAllYAxis(double min, double max) { for (unsigned int i = 0; i < vertAxes.size(); ++i) { - setAxisScale(QwtAxisId(QwtPlot::yLeft, i), min, max); + setAxisScale(QwtAxisId(QwtAxis::YLeft, i), min, max); } if (!d_autoscale_state) { @@ -1288,7 +1288,7 @@ DisplayPlot::setAllYAxis(double min, double max) void DisplayPlot::setYaxis(double min, double max) { - setAxisScale(QwtPlot::yLeft, min, max); + setAxisScale(QwtAxis::YLeft, min, max); if(!d_autoscale_state) { for (unsigned int i = 0; i < d_zoomer.size(); ++i) d_zoomer[i]->setZoomBase(); @@ -1298,7 +1298,7 @@ DisplayPlot::setYaxis(double min, double max) void DisplayPlot::setXaxis(double min, double max) { - setAxisScale(QwtPlot::xBottom, min, max); + setAxisScale(QwtAxis::XBottom, min, max); for (unsigned int i = 0; i < d_zoomer.size(); ++i) d_zoomer[i]->setZoomBase(); } @@ -1422,13 +1422,13 @@ DisplayPlot::getAxisLabelFontSize(int axisId) const { void DisplayPlot::setYaxisLabelFontSize(int fs) { - setAxisLabelFontSize(QwtPlot::yLeft, fs); + setAxisLabelFontSize(QwtAxis::YLeft, fs); } void DisplayPlot::printWithNoBackground(const QString& toolName, bool editScaleDraw) { - OscScaleDraw *scaleDraw = static_cast(this->axisScaleDraw(QwtAxisId(QwtPlot::yLeft, d_activeVertAxis))); + OscScaleDraw *scaleDraw = static_cast(this->axisScaleDraw(QwtAxisId(QwtAxis::YLeft, d_activeVertAxis))); QStack colors; for (int i = 0; i < d_plot_curve.size(); ++i) { colors.push_back(getLineColor(i)); @@ -1453,32 +1453,32 @@ DisplayPlot::printWithNoBackground(const QString& toolName, bool editScaleDraw) int DisplayPlot::getYaxisLabelFontSize() const { - int fs = getAxisLabelFontSize(QwtPlot::yLeft); + int fs = getAxisLabelFontSize(QwtAxis::YLeft); return fs; } void DisplayPlot::setXaxisLabelFontSize(int fs) { - setAxisLabelFontSize(QwtPlot::xBottom, fs); + setAxisLabelFontSize(QwtAxis::XBottom, fs); } int DisplayPlot::getXaxisLabelFontSize() const { - int fs = getAxisLabelFontSize(QwtPlot::xBottom); + int fs = getAxisLabelFontSize(QwtAxis::XBottom); return fs; } void DisplayPlot::setAxesLabelFontSize(int fs) { - setAxisLabelFontSize(QwtPlot::yLeft, fs); - setAxisLabelFontSize(QwtPlot::xBottom, fs); + setAxisLabelFontSize(QwtAxis::YLeft, fs); + setAxisLabelFontSize(QwtAxis::XBottom, fs); } int DisplayPlot::getAxesLabelFontSize() const { // Returns 0 if all axes do not have the same font size. - int fs = getAxisLabelFontSize(QwtPlot::yLeft); - if (getAxisLabelFontSize(QwtPlot::xBottom) != fs) + int fs = getAxisLabelFontSize(QwtAxis::YLeft); + if (getAxisLabelFontSize(QwtAxis::XBottom) != fs) return 0; return fs; } @@ -1661,10 +1661,10 @@ DisplayPlot::onPickerPointSelected6(const QPointF & p) Q_EMIT plotPointSelected(point); } -void DisplayPlot::zoomBaseUpdate() +void DisplayPlot::zoomBaseUpdate(bool force) { for (unsigned int i = 0; i < d_zoomer.size(); ++i) - d_zoomer[i]->setZoomBase(true); + d_zoomer[i]->setZoomBase(force); } void DisplayPlot::AddAxisOffset(int axisPos, int axisIdx, double offset) @@ -1674,12 +1674,12 @@ void DisplayPlot::AddAxisOffset(int axisPos, int axisIdx, double offset) double ptsPerDiv = 1; switch (axisPos) { - case QwtPlot::yLeft: + case QwtAxis::YLeft: ptsPerDiv = vertAxes[axisIdx]->ptsPerDiv(); min = d_yAxisMin * ptsPerDiv; max = d_yAxisMax * ptsPerDiv; break; - case QwtPlot::xBottom: + case QwtAxis::XBottom: ptsPerDiv = horizAxis->ptsPerDiv(); min = d_xAxisMin * ptsPerDiv; max = d_xAxisMax * ptsPerDiv; @@ -1694,7 +1694,7 @@ void DisplayPlot::AddAxisOffset(int axisPos, int axisIdx, double offset) void DisplayPlot::setVertOffset(double offset, int axisIdx) { - AddAxisOffset(QwtPlot::yLeft, axisIdx, offset); + AddAxisOffset(QwtAxis::YLeft, axisIdx, offset); vertAxes[axisIdx]->setOffset(offset); } @@ -1707,7 +1707,7 @@ double DisplayPlot::VertOffset(int axisIdx) void DisplayPlot::setHorizOffset(double offset) { - AddAxisOffset(QwtPlot::xBottom, 0, offset); + AddAxisOffset(QwtAxis::XBottom, 0, offset); horizAxis->setOffset(offset); } @@ -1726,7 +1726,7 @@ void DisplayPlot::setVertUnitsPerDiv(double upd, int axisIdx) vertAxes[axisIdx]->setPtsPerDiv(upd); min = (d_yAxisMin * upd) + offset; max = (d_yAxisMax * upd) + offset; - setAxisScale(QwtAxisId(QwtPlot::yLeft, axisIdx), min, max, upd); + setAxisScale(QwtAxisId(QwtAxis::YLeft, axisIdx), min, max, upd); Q_EMIT vertScaleDivisionChanged(upd); } } @@ -1746,7 +1746,7 @@ void DisplayPlot::setHorizUnitsPerDiv(double upd) horizAxis->setPtsPerDiv(upd); min = (d_xAxisMin * upd) + offset; max = (d_xAxisMax * upd) + offset; - setAxisScale(QwtPlot::xBottom, min, max, upd); + setAxisScale(QwtAxis::XBottom, min, max, upd); Q_EMIT horizScaleDivisionChanged(upd); } } @@ -1765,15 +1765,15 @@ void DisplayPlot::setDisplayScale(double value) { d_displayScale = value; OscScaleDraw *osd = nullptr; - osd = static_cast(axisWidget(QwtAxisId(QwtPlot::yLeft, d_activeVertAxis))->scaleDraw()); + osd = static_cast(axisWidget(QwtAxisId(QwtAxis::YLeft, d_activeVertAxis))->scaleDraw()); osd->setDisplayScale(d_displayScale); osd->invalidateCache(); - axisWidget(QwtAxisId(QwtPlot::yLeft, d_activeVertAxis))->update(); + axisWidget(QwtAxisId(QwtAxis::YLeft, d_activeVertAxis))->update(); } void DisplayPlot::setActiveVertAxis(unsigned int axisIdx, bool selected) { - int numAxes = this->axesCount(QwtPlot::yLeft); + int numAxes = this->axesCount(QwtAxis::YLeft); if (axisIdx >= numAxes) return; @@ -1782,13 +1782,13 @@ void DisplayPlot::setActiveVertAxis(unsigned int axisIdx, bool selected) if (d_usingLeftAxisScales && selected) { for (int i = 0; i < numAxes; i++) { - this->setAxisVisible(QwtAxisId(QwtPlot::yLeft, i), + this->setAxisVisible(QwtAxisId(QwtAxis::YLeft, i), (i == axisIdx)); } } if (d_coloredLabels && selected) { - OscScaleDraw *scaleDraw = static_cast(this->axisScaleDraw(QwtAxisId(QwtPlot::yLeft, axisIdx))); + OscScaleDraw *scaleDraw = static_cast(this->axisScaleDraw(QwtAxisId(QwtAxis::YLeft, axisIdx))); scaleDraw->setColor(getLineColor(axisIdx)); scaleDraw->invalidateCache(); } @@ -1972,6 +1972,18 @@ void DisplayPlot::_onYleftAxisWidgetScaleDivChanged() } } +#ifdef __ANDROID__ +void DisplayPlot::mousePressEvent(QMouseEvent *event) +{ + if (event->type() == QEvent::MouseButtonDblClick) { + for (unsigned int i = 0; i < d_zoomer.size(); ++i) { + OscPlotZoomer *zoomer = static_cast(d_zoomer[i]); + zoomer->popZoom(); + } + } +} +#endif + QwtPlotZoomer *DisplayPlot::getZoomer() const { if (d_zoomer.isEmpty()) @@ -2052,7 +2064,7 @@ void DisplayPlot::removeLeftVertAxis(unsigned int axis) if (axis >= numAxis) return; - setAxesCount(QwtPlot::yLeft, numAxis - 1); + setAxesCount(QwtAxis::YLeft, numAxis - 1); for (unsigned int i = axis + 1; i < numAxis; i++) vertAxes[i]->axis().id = i - 1; @@ -2064,7 +2076,7 @@ void DisplayPlot::removeLeftVertAxis(unsigned int axis) double ptsPerDiv = vertAxes[i]->ptsPerDiv(); double offset = vertAxes[i]->offset(); - setAxisScale(QwtAxisId(QwtPlot::yLeft, i), + setAxisScale(QwtAxisId(QwtAxis::YLeft, i), (d_yAxisMin * ptsPerDiv) + offset, (d_yAxisMax * ptsPerDiv) + offset, ptsPerDiv); @@ -2073,7 +2085,7 @@ void DisplayPlot::removeLeftVertAxis(unsigned int axis) void DisplayPlot::setLeftVertAxesCount(int count) { - setAxesCount(QwtPlot::yLeft, count); + setAxesCount(QwtAxis::YLeft, count); const int numAxis = vertAxes.size(); @@ -2083,9 +2095,9 @@ void DisplayPlot::setLeftVertAxesCount(int count) vertAxes.resize(count); for (int i = numAxis; i < count; i++) { - vertAxes[i] = new PlotAxisConfiguration(QwtPlot::yLeft, i, this); - configureAxis(QwtPlot::yLeft, i); - this->setAxisVisible(QwtAxisId(QwtPlot::yLeft, i), + vertAxes[i] = new PlotAxisConfiguration(QwtAxis::YLeft, i, this); + configureAxis(QwtAxis::YLeft, i); + this->setAxisVisible(QwtAxisId(QwtAxis::YLeft, i), d_usingLeftAxisScales); connect(axisWidget(vertAxes[i]->axis()), SIGNAL(scaleDivChanged()), this, SLOT(_onYleftAxisWidgetScaleDivChanged())); @@ -2129,9 +2141,9 @@ void DisplayPlot::resizeEvent(QResizeEvent *event) void DisplayPlot::bottomHorizAxisInit() { - horizAxis = new PlotAxisConfiguration(QwtPlot::xBottom, 0, this); + horizAxis = new PlotAxisConfiguration(QwtAxis::XBottom, 0, this); horizAxis->setMouseGesturesEnabled(d_mouseGesturesEnabled); - configureAxis(QwtPlot::xBottom, 0); + configureAxis(QwtAxis::XBottom, 0); connect(axisWidget(horizAxis->axis()), SIGNAL(scaleDivChanged()), this, SLOT(_onXbottomAxisWidgetScaleDivChanged())); } diff --git a/src/DisplayPlot.h b/src/DisplayPlot.h index 91469c15c4..bdc98e406e 100644 --- a/src/DisplayPlot.h +++ b/src/DisplayPlot.h @@ -67,7 +67,7 @@ #include "printableplot.h" #include "symbol_controller.h" #include "plot_line_handle.h" -#include "cursor_readouts.h" +#include "gui/cursor_readouts.h" #include "handles_area.hpp" #include "plotpickerwrapper.h" #include @@ -370,7 +370,7 @@ class DisplayPlot:public PrintablePlot QwtPlotCurve *Curve(unsigned int curveIdx); - void zoomBaseUpdate(); + void zoomBaseUpdate(bool force = false); void setMinXaxisDivision(double minDivison); double minXaxisDivision(); @@ -590,6 +590,10 @@ protected Q_SLOTS: void _onXbottomAxisWidgetScaleDivChanged(); void _onYleftAxisWidgetScaleDivChanged(); +#ifdef __ANDROID__ + void mousePressEvent(QMouseEvent *event); +#endif + protected: enum PlotMarker diff --git a/src/FftDisplayPlot.cc b/src/FftDisplayPlot.cc index 3efe221bf8..9c088c5cd3 100644 --- a/src/FftDisplayPlot.cc +++ b/src/FftDisplayPlot.cc @@ -88,6 +88,10 @@ FftDisplayPlot::FftDisplayPlot(int nplots, QWidget *parent) : for (unsigned int i = 0; i < nplots; i++) { auto plot = new QwtPlotCurve(QString("CH %1").arg(i + 1)); + plot->setPaintAttribute(QwtPlotCurve::ClipPolygons); + plot->setPaintAttribute(QwtPlotCurve::ImageBuffer); + plot->setPaintAttribute(QwtPlotCurve::FilterPoints); + plot->setPaintAttribute(QwtPlotCurve::FilterPointsAggressive); plot->setPen(QPen(d_CurveColors[i])); plot->attach(this); @@ -124,16 +128,13 @@ FftDisplayPlot::FftDisplayPlot(int nplots, QWidget *parent) : freqFormatter.setTwoDecimalMode(true); OscScaleDraw *yScaleDraw = new OscScaleDraw(&dBFormatter, ""); - setAxisScaleDraw(QwtPlot::yLeft, yScaleDraw); + setAxisScaleDraw(QwtAxis::YLeft, yScaleDraw); yScaleDraw->setFloatPrecision(2); - OscScaleDraw *xScaleDraw = new OscScaleDraw(&freqFormatter, "Hz"); - setAxisScaleDraw(QwtPlot::xBottom, xScaleDraw); + OscScaleDraw *xScaleDraw = new OscScaleDraw(&freqFormatter, ""); + setAxisScaleDraw(QwtAxis::XBottom, xScaleDraw); xScaleDraw->setFloatPrecision(2); - d_yAxisUnit = "dB"; - d_xAxisUnit = "Hz"; - _resetXAxisPoints(); d_mrkCtrl = new MarkerController(this); @@ -174,8 +175,8 @@ FftDisplayPlot::FftDisplayPlot(int nplots, QWidget *parent) : d_leftHandlesArea->setBottomPadding(55); d_leftHandlesArea->setMinimumHeight(this->minimumHeight()); - enableAxis(QwtPlot::xBottom, false); - enableAxis(QwtPlot::yLeft, false); + setAxisVisible(QwtAxis::XBottom, false); + setAxisVisible(QwtAxis::YLeft, false); d_formatter = static_cast(new MetricPrefixFormatter); setupReadouts(); @@ -212,26 +213,41 @@ FftDisplayPlot::~FftDisplayPlot() canvas()->removeEventFilter(d_symbolCtrl); } +void FftDisplayPlot::initChannelMeasurement(int nplots) { + Q_EMIT channelAdded(nplots); +} + void FftDisplayPlot::replot() { if (!d_leftHandlesArea || !d_bottomHandlesArea) { return; } - d_leftHandlesArea->repaint(); - d_bottomHandlesArea->repaint(); + d_leftHandlesArea->update(); + d_bottomHandlesArea->update(); + + BasicPlot::replot(); +} + +bool FftDisplayPlot::isReferenceWaveform(unsigned int chnIdx) +{ + QwtPlotCurve *curve = Curve(chnIdx); + return d_ref_curves.values().contains(curve); +} - QwtPlot::replot(); +size_t FftDisplayPlot::getCurveSize(unsigned int chnIdx) +{ + return Curve(chnIdx)->data()->size(); } QString FftDisplayPlot::formatXValue(double value, int precision) const { - return d_formatter->format(value, "Hz", precision); + return d_formatter->format(value, d_xAxisUnit, precision); } QString FftDisplayPlot::formatYValue(double value, int precision) const { - return d_formatter->format(value, "dB", precision); + return d_formatter->format(value, d_yAxisUnit, precision); } void FftDisplayPlot::setupReadouts() @@ -252,7 +268,7 @@ void FftDisplayPlot::setupReadouts() void FftDisplayPlot::updateHandleAreaPadding() { - d_leftHandlesArea->repaint(); + d_leftHandlesArea->update(); d_bottomHandlesArea->setLeftPadding(d_leftHandlesArea->width()); d_bottomHandlesArea->setRightPadding(50); @@ -407,8 +423,8 @@ void FftDisplayPlot::setSelectedChannel(int id) void FftDisplayPlot::setZoomerEnabled() { - enableAxis(QwtPlot::xBottom, true); - enableAxis(QwtPlot::yLeft, true); + setAxisVisible(QwtAxis::XBottom, true); + setAxisVisible(QwtAxis::YLeft, true); if(!d_zoomer[0]) { d_zoomer[0] = new FftDisplayZoomer(canvas()); @@ -477,7 +493,6 @@ void FftDisplayPlot::registerReferenceWaveform(QString name, QVector xDa d_ref_curves.insert(name, curve); d_plot_curve.push_back(curve); - n_ref_curves++; d_num_markers.push_back(0); d_markers.push_back(QList()); @@ -494,6 +509,9 @@ void FftDisplayPlot::registerReferenceWaveform(QString name, QVector xDa findPeaks(d_plot_curve.size() - 1); + Q_EMIT channelAdded(y_data.size() + n_ref_curves); + n_ref_curves++; + replot(); } @@ -543,23 +561,23 @@ void FftDisplayPlot::useLogScaleY(bool log_scale) if (log_scale) { setPlotYLogaritmic(true); QwtLogScaleEngine *scaleEngine = new QwtLogScaleEngine(); - setAxisScaleEngine(QwtPlot::yLeft, (QwtScaleEngine *)scaleEngine); + setAxisScaleEngine(QwtAxis::YLeft, (QwtScaleEngine *)scaleEngine); // OscScaleDraw *yScaleDraw = new OscScaleDraw(&dBFormatter, "V/√Hz"); // yScaleDraw->enableComponent(QwtAbstractScaleDraw::Ticks, true); // yScaleDraw->setFloatPrecision(2); -// setAxisScaleDraw(QwtPlot::yLeft, yScaleDraw); +// setAxisScaleDraw(QwtAxis::YLeft, yScaleDraw); replot(); - auto div = axisScaleDiv(QwtPlot::yLeft); + auto div = axisScaleDiv(QwtAxis::YLeft); setYaxisMajorTicksPos(div.ticks(2)); } else { setPlotYLogaritmic(false); OscScaleEngine *scaleEngine = new OscScaleEngine(); - this->setAxisScaleEngine(QwtPlot::yLeft, (QwtScaleEngine *)scaleEngine); + this->setAxisScaleEngine(QwtAxis::YLeft, (QwtScaleEngine *)scaleEngine); // OscScaleDraw *yScaleDraw = new OscScaleDraw(&dBFormatter, ""); // yScaleDraw->setFloatPrecision(2); -// setAxisScaleDraw(QwtPlot::yLeft, yScaleDraw); +// setAxisScaleDraw(QwtAxis::YLeft, yScaleDraw); replot(); - auto div = axisScaleDiv(QwtPlot::yLeft); + auto div = axisScaleDiv(QwtAxis::YLeft); setYaxisNumDiv((div.ticks(2)).size()); } @@ -570,22 +588,43 @@ void FftDisplayPlot::useLogFreq(bool use_log_freq) { if (use_log_freq) { setPlotLogaritmic(true); - setAxisScaleEngine(QwtPlot::xBottom, new QwtLogScaleEngine); + setAxisScaleEngine(QwtAxis::XBottom, new QwtLogScaleEngine); replot(); - auto div = axisScaleDiv(QwtPlot::xBottom); + auto div = axisScaleDiv(QwtAxis::XBottom); setXaxisMajorTicksPos(div.ticks(2)); } else { setPlotLogaritmic(false); OscScaleEngine *scaleEngine = new OscScaleEngine(); - this->setAxisScaleEngine(QwtPlot::xBottom, (QwtScaleEngine *)scaleEngine); + this->setAxisScaleEngine(QwtAxis::XBottom, (QwtScaleEngine *)scaleEngine); replot(); - auto div = axisScaleDiv(QwtPlot::xBottom); + auto div = axisScaleDiv(QwtAxis::XBottom); setXaxisNumDiv((div.ticks(2)).size() - 1); } d_logScaleEnabled = use_log_freq; replot(); } +std::vector FftDisplayPlot::getOrginal_data() { + return y_original_data; +} + +int64_t FftDisplayPlot::getYdata_size() { + return y_data.size(); +} + +std::vector FftDisplayPlot::getRef_data() { + return d_refYdata; +} + +std::vector FftDisplayPlot::getScaleFactor() { + return y_scale_factor; +} + +int64_t FftDisplayPlot::getNumPoints() +{ + return d_numPoints; +} + void FftDisplayPlot::plotData(const std::vector &pts, uint64_t num_points) { @@ -996,23 +1035,32 @@ FftDisplayPlot::average_sptr FftDisplayPlot::getNewAvgObject( } } -QString FftDisplayPlot::leftVerAxisUnit() const +QString FftDisplayPlot::leftVerAxisUnit() const { return d_yAxisUnit; } + +void FftDisplayPlot::setLeftVertAxisUnit(const QString& unit) { - QString unit; - auto scale_draw = dynamic_cast( - axisScaleDraw(QwtPlot::yLeft)); - if (scale_draw) - unit = scale_draw->getUnitType(); + if (d_yAxisUnit != unit) { + d_yAxisUnit = unit; - return unit; + auto scale_draw = dynamic_cast( + axisScaleDraw(QwtAxis::YLeft)); + if (scale_draw) { + scale_draw->setUnitType(unit); + } + } } -void FftDisplayPlot::setLeftVertAxisUnit(const QString& unit) +QString FftDisplayPlot::btmHorAxisUnit() const { return d_xAxisUnit; } + +void FftDisplayPlot::setBtmHorAxisUnit(const QString &unit) { - auto scale_draw = dynamic_cast( - axisScaleDraw(QwtPlot::yLeft)); - if (scale_draw) - scale_draw->setUnitType(unit); + if (d_xAxisUnit != unit) { + d_xAxisUnit = unit; + + auto scale_draw = dynamic_cast(axisScaleDraw(QwtAxis::XBottom)); + if (scale_draw) + scale_draw->setUnitType(unit); + } } void FftDisplayPlot::findPeaks(int chn) @@ -1307,7 +1355,7 @@ void FftDisplayPlot:: setMarkerEnabled(uint chIdx, uint mkIdx, bool en) if (en) { auto data_sp = std::make_shared(); data_sp->x = 0; - data_sp->y = axisScaleDiv(QwtPlot::yLeft).lowerBound(); + data_sp->y = axisScaleDiv(QwtAxis::YLeft).lowerBound(); data_sp->bin = 0; data_sp->update_ui = true; @@ -1395,7 +1443,7 @@ void FftDisplayPlot::setMarkerAtFreq(uint chIdx, uint mkIdx, double freq) if (ydata) { y = ydata[pos]; } else { - y = axisScaleDiv(QwtPlot::yLeft).lowerBound(); + y = axisScaleDiv(QwtAxis::YLeft).lowerBound(); } if (d_markers[chIdx][mkIdx].data->type != 0) { @@ -1485,7 +1533,7 @@ void FftDisplayPlot::setStartStop(double start, double stop) { m_sweepStart = start; m_sweepStop = stop; - auto div = axisScaleDiv(QwtPlot::xBottom); + auto div = axisScaleDiv(QwtAxis::XBottom); setXaxisNumDiv((div.ticks(2)).size() - 1); setXaxisMajorTicksPos(div.ticks(2)); } @@ -1592,7 +1640,7 @@ void FftDisplayPlot::onMrkCtrlMarkerPosChanged(std::shared_ptr & y = ydata[bin]; } else { qDebug() << "problem"; - y = axisScaleDiv(QwtPlot::yLeft).upperBound(); + y = axisScaleDiv(QwtAxis::YLeft).upperBound(); } marker_data->type = 0; // Fixed marker diff --git a/src/FftDisplayPlot.h b/src/FftDisplayPlot.h index ce22535760..d713c19352 100644 --- a/src/FftDisplayPlot.h +++ b/src/FftDisplayPlot.h @@ -26,7 +26,7 @@ #include "symbol_controller.h" #include "plot_line_handle.h" #include "handles_area.hpp" -#include "cursor_readouts.h" +#include "gui/cursor_readouts.h" #include namespace adiscope { @@ -179,6 +179,16 @@ namespace adiscope { explicit FftDisplayPlot(int nplots, QWidget *parent = nullptr); ~FftDisplayPlot(); + void initChannelMeasurement(int nplots); + std::vector getOrginal_data(); + std::vector getRef_data(); + int64_t getYdata_size(); + std::vector getScaleFactor(); + int64_t getNumPoints(); + + bool isReferenceWaveform(unsigned int chnIdx); + size_t getCurveSize(unsigned int chnIdx); + // Scaling factors for plot samples (one per channel) double channelScaleFactor(int chIdx) const; void setScaleFactor(int chIdx, double scale); @@ -187,6 +197,9 @@ namespace adiscope { QString leftVerAxisUnit() const; void setLeftVertAxisUnit(const QString& unit); + QString btmHorAxisUnit() const; + void setBtmHorAxisUnit(const QString& unit); + enum MagnitudeType magnitudeType() const; void setMagnitudeType(enum MagnitudeType); @@ -249,6 +262,7 @@ namespace adiscope { QString formatYValue(double value, int precision) const; Q_SIGNALS: + void channelAdded(int); void newData(); void sampleRateUpdated(double); void sampleCountUpdated(uint); diff --git a/src/HistogramDisplayPlot.cc b/src/HistogramDisplayPlot.cc index 4b5024f5aa..9aaec608c9 100644 --- a/src/HistogramDisplayPlot.cc +++ b/src/HistogramDisplayPlot.cc @@ -242,18 +242,18 @@ HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent) d_autoscale_state = false; d_autoscalex_state = false; - setAxesCount(QwtPlot::xBottom, 2); + setAxesCount(QwtAxis::XBottom, 2); horizAxes.resize(2); d_pf = new MetricPrefixFormatter(); d_pf->setTwoDecimalMode(true); for (int i = 0; i < 2; ++i) { - horizAxes[i] = new PlotAxisConfiguration(QwtPlot::xBottom, i, this); - configureAxis(QwtPlot::xBottom, i); - setAxisVisible(QwtAxisId(QwtPlot::xBottom, i), + horizAxes[i] = new PlotAxisConfiguration(QwtAxis::XBottom, i, this); + configureAxis(QwtAxis::XBottom, i); + setAxisVisible(QwtAxisId(QwtAxis::XBottom, i), d_usingLeftAxisScales); connect(axisWidget(horizAxes[i]->axis()), SIGNAL(scaleDivChanged()), this, SLOT(_onXbottomAxisWidgetScaleDivChanged())); - QwtScaleWidget *scaleWidget = axisWidget(QwtAxisId(QwtPlot::xBottom, i)); + QwtScaleWidget *scaleWidget = axisWidget(QwtAxisId(QwtAxis::XBottom, i)); OscScaleDraw* osd = dynamic_cast(scaleWidget->scaleDraw()); osd->setFormatter(d_pf); osd->setUnitType("V"); @@ -265,7 +265,7 @@ HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent) for (int i = 0; i < 2; ++i) { HistogramScaleDraw *hsd = new HistogramScaleDraw(); hsd->setColor(d_CurveColors[i]); - setAxisScaleDraw(QwtAxisId(QwtPlot::yLeft, i), hsd); + setAxisScaleDraw(QwtAxisId(QwtAxis::YLeft, i), hsd); } this->_updateXScales(100); @@ -277,8 +277,8 @@ HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent) memset(d_ydata[i], 0, d_bins*sizeof(double)); d_histograms.push_back(new Histogram(QString("Data %1").arg(i), d_CurveColors[i])); - d_histograms[i]->setXAxis(QwtAxisId(QwtPlot::xBottom, i)); - d_histograms[i]->setYAxis(QwtAxisId(QwtPlot::yLeft, i)); + d_histograms[i]->setXAxis(QwtAxisId(QwtAxis::XBottom, i)); + d_histograms[i]->setYAxis(QwtAxisId(QwtAxis::YLeft, i)); d_histograms[i]->setOrientation(Qt::Horizontal); d_histograms[i]->attach(this); @@ -309,8 +309,8 @@ HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent) for (unsigned int i = 0; i < d_histograms.size(); ++i) { d_zoomer.push_back(new HistogramDisplayZoomer(canvas(), 0, getLineColor(i))); - d_zoomer[i]->setAxes(QwtAxisId(QwtPlot::xBottom, i), - QwtAxisId(QwtPlot::yLeft, i)); + d_zoomer[i]->setAxes(QwtAxisId(QwtAxis::XBottom, i), + QwtAxisId(QwtAxis::YLeft, i)); connect(d_zoomer[i], SIGNAL(zoomed(QRectF)), this, SLOT(_onZoom(QRectF))); @@ -320,14 +320,14 @@ HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent) _resetXAxisPoints(-1, 1); for (unsigned int i = 0; i < d_histograms.size(); ++i) { - setAxisScale(QwtAxisId(QwtPlot::xBottom, i), 0, 100); - setAxisScale(QwtAxisId(QwtPlot::yLeft, i), -10, 10); + setAxisScale(QwtAxisId(QwtAxis::XBottom, i), 0, 100); + setAxisScale(QwtAxisId(QwtAxis::YLeft, i), -10, 10); } - setAxisVisible(QwtAxisId(QwtPlot::yLeft, 0), false); - setAxisVisible(QwtAxisId(QwtPlot::yLeft, 1), false); - setAxisVisible(QwtAxisId(QwtPlot::xBottom, 0), false); - setAxisVisible(QwtAxisId(QwtPlot::xBottom, 1), false); + setAxisVisible(QwtAxisId(QwtAxis::YLeft, 0), false); + setAxisVisible(QwtAxisId(QwtAxis::YLeft, 1), false); + setAxisVisible(QwtAxisId(QwtAxis::XBottom, 0), false); + setAxisVisible(QwtAxisId(QwtAxis::XBottom, 1), false); insertLegend(nullptr); @@ -363,29 +363,29 @@ void HistogramDisplayPlot::setOrientation(Qt::Orientation orientation) } } - QwtInterval xInt = axisInterval(QwtPlot::xBottom); - QwtInterval yInt = axisInterval(QwtPlot::yLeft); - QwtInterval xInt2 = axisInterval(QwtAxisId(QwtPlot::xBottom, 1)); - QwtInterval yInt2 = axisInterval(QwtAxisId(QwtPlot::yLeft, 1)); + QwtInterval xInt = axisInterval(QwtAxis::XBottom); + QwtInterval yInt = axisInterval(QwtAxis::YLeft); + QwtInterval xInt2 = axisInterval(QwtAxisId(QwtAxis::XBottom, 1)); + QwtInterval yInt2 = axisInterval(QwtAxisId(QwtAxis::YLeft, 1)); if (orientation == Qt::Vertical) { - setAxisScale(QwtAxisId(QwtPlot::xBottom, 0), yInt.minValue(), yInt.maxValue()); - setAxisScale(QwtAxisId(QwtPlot::yLeft, 0), xInt.maxValue(), -xInt.minValue()); - setAxisScale(QwtAxisId(QwtPlot::xBottom, 1), yInt2.minValue(), yInt2.maxValue()); - setAxisScale(QwtAxisId(QwtPlot::yLeft, 1), xInt2.maxValue(), -xInt2.minValue()); + setAxisScale(QwtAxisId(QwtAxis::XBottom, 0), yInt.minValue(), yInt.maxValue()); + setAxisScale(QwtAxisId(QwtAxis::YLeft, 0), xInt.maxValue(), -xInt.minValue()); + setAxisScale(QwtAxisId(QwtAxis::XBottom, 1), yInt2.minValue(), yInt2.maxValue()); + setAxisScale(QwtAxisId(QwtAxis::YLeft, 1), xInt2.maxValue(), -xInt2.minValue()); - setAxisVisible(QwtAxisId(QwtPlot::yLeft, d_selected_channel), true); - setAxisVisible(QwtAxisId(QwtPlot::xBottom, d_selected_channel), true); + setAxisVisible(QwtAxisId(QwtAxis::YLeft, d_selected_channel), true); + setAxisVisible(QwtAxisId(QwtAxis::XBottom, d_selected_channel), true); } else { - setAxisScale(QwtPlot::xBottom, 0, yInt.maxValue()); - setAxisScale(QwtAxisId(QwtPlot::yLeft, 0), xInt.minValue(), xInt.maxValue()); - setAxisScale(QwtAxisId(QwtPlot::yLeft, 1), xInt.minValue(), xInt.maxValue()); - - setAxisVisible(QwtAxisId(QwtPlot::yLeft, 0), false); - setAxisVisible(QwtAxisId(QwtPlot::yLeft, 1), false); - setAxisVisible(QwtAxisId(QwtPlot::xBottom, 0), false); - setAxisVisible(QwtAxisId(QwtPlot::xBottom, 1), false); + setAxisScale(QwtAxis::XBottom, 0, yInt.maxValue()); + setAxisScale(QwtAxisId(QwtAxis::YLeft, 0), xInt.minValue(), xInt.maxValue()); + setAxisScale(QwtAxisId(QwtAxis::YLeft, 1), xInt.minValue(), xInt.maxValue()); + + setAxisVisible(QwtAxisId(QwtAxis::YLeft, 0), false); + setAxisVisible(QwtAxisId(QwtAxis::YLeft, 1), false); + setAxisVisible(QwtAxisId(QwtAxis::XBottom, 0), false); + setAxisVisible(QwtAxisId(QwtAxis::XBottom, 1), false); } _orientationChanged(); @@ -437,18 +437,13 @@ void HistogramDisplayPlot::setYaxisSpan(unsigned int chIdx, double bot, double t return; } - _resetZoom(); if (d_orientation == Qt::Vertical) { - setAxisScale(QwtAxisId(QwtPlot::xBottom, chIdx), bot, top); - replot(); - zoomBaseUpdate(); + setAxisScale(QwtAxisId(QwtAxis::XBottom, chIdx), bot, top); return; } - setAxisScale(QwtAxisId(QwtPlot::yLeft, chIdx), bot, top); + setAxisScale(QwtAxisId(QwtAxis::YLeft, chIdx), bot, top); - replot(); - zoomBaseUpdate(); } void HistogramDisplayPlot::setXaxisSpan(double start, double stop) @@ -458,7 +453,7 @@ void HistogramDisplayPlot::setXaxisSpan(double start, double stop) } for (int i = 0; i < d_histograms.size(); ++i) { - setAxisScale(QwtAxisId(QwtPlot::xBottom, i), start, stop); + setAxisScale(QwtAxisId(QwtAxis::XBottom, i), start, stop); } } @@ -471,7 +466,7 @@ void HistogramDisplayPlot::setDataInterval(int min, int max) void HistogramDisplayPlot::replot() { - QwtPlot::replot(); + BasicPlot::replot(); } void @@ -560,8 +555,8 @@ HistogramDisplayPlot::plotNewData(const std::vector dataPoints, } double pr = h * 0.15; - if (abs(h - axisInterval(QwtAxisId(QwtPlot::yLeft, i)).maxValue()) > pr) { - setAxisScale(QwtAxisId(QwtPlot::yLeft, i), 0, h); + if (abs(h - axisInterval(QwtAxisId(QwtAxis::YLeft, i)).maxValue()) > pr) { + setAxisScale(QwtAxisId(QwtAxis::YLeft, i), 0, h); } } } @@ -629,10 +624,10 @@ HistogramDisplayPlot::_resetXAxisPoints(double left, double right) d_xdata[loc] = d_left + loc*d_width; } #if QWT_VERSION < 0x060100 - axisScaleDiv(QwtPlot::xBottom)->setInterval(d_left, d_right); + axisScaleDiv(QwtAxis::XBottom)->setInterval(d_left, d_right); #else /* QWT_VERSION < 0x060100 */ QwtScaleDiv scalediv(d_left, d_right); - setAxisScaleDiv(QwtPlot::xBottom, scalediv); + setAxisScaleDiv(QwtAxis::XBottom, scalediv); #endif /* QWT_VERSION < 0x060100 */ // Set up zoomer base for maximum unzoom x-axis @@ -640,11 +635,11 @@ HistogramDisplayPlot::_resetXAxisPoints(double left, double right) QRectF zbase = d_zoomer[0]->zoomBase(); if(d_semilogx) { - setAxisScale(QwtPlot::xBottom, 1e-1, d_right); + setAxisScale(QwtAxis::XBottom, 1e-1, d_right); zbase.setLeft(1e-1); } else { - setAxisScale(QwtPlot::xBottom, d_left, d_right); + setAxisScale(QwtAxis::XBottom, d_left, d_right); zbase.setLeft(d_left); } @@ -677,7 +672,7 @@ void HistogramDisplayPlot::_updateXScales(unsigned int totalSamples) { for (int i = 0; i < d_histograms.size(); ++i) { HistogramScaleDraw *hsd = dynamic_cast( - axisWidget(QwtAxisId(QwtPlot::yLeft, i))->scaleDraw()); + axisWidget(QwtAxisId(QwtAxis::YLeft, i))->scaleDraw()); if (hsd) { hsd->setTotalSamples(totalSamples); hsd->invalidateCache(); @@ -693,7 +688,7 @@ void HistogramDisplayPlot::_orientationChanged() min_h = std::min(min_h, d_histograms[i]->getMaxHeight()); } for (int i = 0; i < d_histograms.size(); ++i) { - setAxisScale(QwtAxisId(QwtPlot::xBottom, i), -min_h, 0); + setAxisScale(QwtAxisId(QwtAxis::XBottom, i), -min_h, 0); } } else { @@ -701,11 +696,10 @@ void HistogramDisplayPlot::_orientationChanged() for (int i = 0; i < d_histograms.size(); ++i) { int h = d_histograms[i]->getMaxHeight(); h += h * 0.2; - setAxisScale(QwtAxisId(QwtPlot::yLeft, i), 0, h); + setAxisScale(QwtAxisId(QwtAxis::YLeft, i), 0, h); } } - zoomBaseUpdate(); for (int i = 0; i < d_zoomer.size(); ++i) { d_zoomer[i]->setEnabled(d_orientation == Qt::Horizontal ? false : true); @@ -740,8 +734,8 @@ void HistogramDisplayPlot::setSelectedChannel(unsigned int value) } for (int i = 0; i < d_histograms.size(); ++i) { - setAxisVisible(QwtAxisId(QwtPlot::yLeft, i), value == i); - setAxisVisible(QwtAxisId(QwtPlot::xBottom, i), value == i); + setAxisVisible(QwtAxisId(QwtAxis::YLeft, i), value == i); + setAxisVisible(QwtAxisId(QwtAxis::XBottom, i), value == i); } } @@ -764,13 +758,13 @@ HistogramDisplayPlot::setSemilogx(bool en) { d_semilogx = en; if(!d_semilogx) { - setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); + setAxisScaleEngine(QwtAxis::XBottom, new QwtLinearScaleEngine); } else { #if QWT_VERSION < 0x060100 - setAxisScaleEngine(QwtPlot::xBottom, new QwtLog10ScaleEngine); + setAxisScaleEngine(QwtAxis::XBottom, new QwtLog10ScaleEngine); #else /* QWT_VERSION < 0x060100 */ - setAxisScaleEngine(QwtPlot::xBottom, new QwtLogScaleEngine); + setAxisScaleEngine(QwtAxis::XBottom, new QwtLogScaleEngine); #endif /* QWT_VERSION < 0x060100 */ } } @@ -782,20 +776,20 @@ HistogramDisplayPlot::setSemilogy(bool en) d_semilogy = en; #if QWT_VERSION < 0x060100 - double max = axisScaleDiv(QwtPlot::yLeft)->upperBound(); + double max = axisScaleDiv(QwtAxis::YLeft)->upperBound(); #else /* QWT_VERSION < 0x060100 */ - double max = axisScaleDiv(QwtPlot::yLeft).upperBound(); + double max = axisScaleDiv(QwtAxis::YLeft).upperBound(); #endif /* QWT_VERSION < 0x060100 */ if(!d_semilogy) { - setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); + setAxisScaleEngine(QwtAxis::YLeft, new QwtLinearScaleEngine); setYaxis(-pow(10.0, max/10.0), pow(10.0, max/10.0)); } else { #if QWT_VERSION < 0x060100 - setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine); + setAxisScaleEngine(QwtAxis::YLeft, new QwtLog10ScaleEngine); #else /* QWT_VERSION < 0x060100 */ - setAxisScaleEngine(QwtPlot::yLeft, new QwtLogScaleEngine); + setAxisScaleEngine(QwtAxis::YLeft, new QwtLogScaleEngine); #endif /* QWT_VERSION < 0x060100 */ setYaxis(1e-10, 10.0*log10(100*max)); } diff --git a/src/TimeDomainDisplayPlot.cc b/src/TimeDomainDisplayPlot.cc index 0f030cdfe8..ffcf9afed6 100644 --- a/src/TimeDomainDisplayPlot.cc +++ b/src/TimeDomainDisplayPlot.cc @@ -171,7 +171,8 @@ int SinkManager::sinkFirstChannelPos(const std::string& name) /*********************************************************************** * Main Time domain plotter widget **********************************************************************/ -TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent, bool isdBgraph, unsigned int xNumDivs, unsigned int yNumDivs) +TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent, bool isdBgraph, unsigned int xNumDivs, unsigned int yNumDivs, + PrefixFormatter* pfXaxis, PrefixFormatter* pfYaxis) : DisplayPlot(0, parent, isdBgraph, xNumDivs, yNumDivs) { d_tag_text_color = Qt::black; @@ -188,9 +189,10 @@ TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent, bool isdBgraph, un d_autoscale_state = false; // Reconfigure the bottom horizontal axis that was created by the base class - configureAxis(QwtPlot::xBottom, 0); - configureAxis(QwtPlot::yLeft, 0); + configureAxis(QwtAxis::XBottom, 0, pfXaxis); + configureAxis(QwtAxis::YLeft, 0, pfYaxis); + d_xAxisUnit = ""; d_yAxisUnit = ""; //d_zoomer = new TimeDomainDisplayZoomer(canvas()); @@ -217,8 +219,15 @@ TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent, bool isdBgraph, un d_semilogy = false; d_autoscale_shot = false; - d_metricFormatter.setTwoDecimalMode(true); - d_timeFormatter.setTwoDecimalMode(true); + if (d_xAxisFormatter) { + d_xAxisFormatter->setTwoDecimalMode(true); + d_xAxisFormatter->setTrimZeroes(true); + } + + if (d_yAxisFormatter) { + d_yAxisFormatter->setTwoDecimalMode(true); + d_yAxisFormatter->setTrimZeroes(true); + } d_tag_markers.resize(d_nplots); d_tag_markers_en = std::vector(d_nplots, true); @@ -265,7 +274,7 @@ TimeDomainDisplayPlot::~TimeDomainDisplayPlot() void TimeDomainDisplayPlot::replot() { - QwtPlot::replot(); + BasicPlot::replot(); } void @@ -302,8 +311,8 @@ TimeDomainDisplayPlot::plotNewData(const std::string &sender, _resetXAxisPoints(d_xdata[sinkIndex], numDataPoints, d_sample_rate); } else if (reset_x_axis_points) { - _resetXAxisPoints(d_xdata[sinkIndex], numDataPoints, d_sample_rate); - reset_x_axis_points = false; + _resetXAxisPoints(d_xdata[sinkIndex], numDataPoints, d_sample_rate); + reset_x_axis_points = false; } for(int i = 0; i < sinkNumChannels; i++) { @@ -514,10 +523,10 @@ TimeDomainDisplayPlot::legendEntryChecked(QwtPlotItem* plotItem, bool on) for(int n = 0; n < d_nplots; n++) { if(plotItem == d_plot_curve[n]) { for(size_t i = 0; i < d_tag_markers[n].size(); i++) { - if(!(!on && d_tag_markers_en[n])) - d_tag_markers[n][i]->hide(); - else - d_tag_markers[n][i]->show(); + if(!(!on && d_tag_markers_en[n])) + d_tag_markers[n][i]->hide(); + else + d_tag_markers[n][i]->show(); } } } @@ -549,11 +558,11 @@ TimeDomainDisplayPlot::_resetXAxisPoints(double*& xAxis, unsigned long long numP // QRectF zbase = d_zoomer->zoomBase(); // if(d_semilogx) { -// setAxisScale(QwtPlot::xBottom, 1e-1, d_numPoints*delt); +// setAxisScale(QwtAxis::XBottom, 1e-1, d_numPoints*delt); // zbase.setLeft(1e-1); // } // else { -// setAxisScale(QwtPlot::xBottom, 0, d_numPoints*delt); +// setAxisScale(QwtAxis::XBottom, 0, d_numPoints*delt); // zbase.setLeft(0); // } @@ -612,7 +621,7 @@ TimeDomainDisplayPlot::addZoomer(unsigned int zoomerIdx) d_zoomer[zoomerIdx]->setTrackerPen(getLineColor(zoomerIdx)); d_zoomer[zoomerIdx]->setEnabled(true); - d_zoomer[zoomerIdx]->setAxes(QwtAxisId(QwtPlot::xBottom, 0), QwtAxisId(QwtPlot::yLeft, zoomerIdx)); + d_zoomer[zoomerIdx]->setAxes(QwtAxisId(QwtAxis::XBottom, 0), QwtAxisId(QwtAxis::YLeft, zoomerIdx)); } void @@ -637,7 +646,7 @@ TimeDomainDisplayPlot::removeZoomer(unsigned int zoomerIdx) for (int i = 0; i < d_zoomer.size(); ++i) { if (d_zoomer[i]->isEnabled()) { - d_zoomer[i]->setAxes(QwtAxisId(QwtPlot::xBottom, 0), QwtAxisId(QwtPlot::yLeft, i)); + d_zoomer[i]->setAxes(QwtAxisId(QwtAxis::XBottom, 0), QwtAxisId(QwtAxis::YLeft, i)); d_zoomer[i]->setTrackerPen(getLineColor(i)); } } @@ -710,7 +719,7 @@ void TimeDomainDisplayPlot::setYaxisUnit(QString unitType) if (d_yAxisUnit != unitType) { d_yAxisUnit = unitType; - OscScaleDraw *scaleDraw = static_cast(this->axisScaleDraw(QwtPlot::yLeft)); + OscScaleDraw *scaleDraw = static_cast(this->axisScaleDraw(QwtAxis::YLeft)); if (scaleDraw) scaleDraw->setUnitType(d_yAxisUnit); } @@ -721,8 +730,21 @@ QString TimeDomainDisplayPlot::yAxisUnit(void) return d_yAxisUnit; } -void -TimeDomainDisplayPlot::stemPlot(bool en) +void TimeDomainDisplayPlot::setXaxisUnit(QString unitType) +{ + if (d_xAxisUnit != unitType) { + d_xAxisUnit = unitType; + + OscScaleDraw* scaleDraw = static_cast(this->axisScaleDraw(QwtAxis::XBottom)); + if (scaleDraw) + scaleDraw->setUnitType(d_xAxisUnit); + } +} + +QString TimeDomainDisplayPlot::xAxisUnit() { return d_xAxisUnit; } + + +void TimeDomainDisplayPlot::stemPlot(bool en) { if(en) { for(int i = 0; i < d_nplots; i++) { @@ -808,13 +830,13 @@ TimeDomainDisplayPlot::setSemilogx(bool en) { d_semilogx = en; if(!d_semilogx) { - setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); + setAxisScaleEngine(QwtAxis::XBottom, new QwtLinearScaleEngine); } else { #if QWT_VERSION < 0x060100 - setAxisScaleEngine(QwtPlot::xBottom, new QwtLog10ScaleEngine); + setAxisScaleEngine(QwtAxis::XBottom, new QwtLog10ScaleEngine); #else /* QWT_VERSION < 0x060100 */ - setAxisScaleEngine(QwtPlot::xBottom, new QwtLogScaleEngine); + setAxisScaleEngine(QwtAxis::XBottom, new QwtLogScaleEngine); #endif /*QWT_VERSION < 0x060100 */ } for (unsigned int i = 0; i < d_sinkManager.sinkListLength(); i++) @@ -828,20 +850,20 @@ TimeDomainDisplayPlot::setSemilogy(bool en) d_semilogy = en; #if QWT_VERSION < 0x060100 - double max = axisScaleDiv(QwtPlot::yLeft)->upperBound(); + double max = axisScaleDiv(QwtAxis::YLeft)->upperBound(); #else /* QWT_VERSION < 0x060100 */ - double max = axisScaleDiv(QwtPlot::yLeft).upperBound(); + double max = axisScaleDiv(QwtAxis::YLeft).upperBound(); #endif /* QWT_VERSION < 0x060100 */ if(!d_semilogy) { - setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); + setAxisScaleEngine(QwtAxis::YLeft, new QwtLinearScaleEngine); setYaxis(-pow(10.0, max/10.0), pow(10.0, max/10.0)); } else { #if QWT_VERSION < 0x060100 - setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine); + setAxisScaleEngine(QwtAxis::YLeft, new QwtLog10ScaleEngine); #else /* QWT_VERSION < 0x060100 */ - setAxisScaleEngine(QwtPlot::yLeft, new QwtLogScaleEngine); + setAxisScaleEngine(QwtAxis::YLeft, new QwtLogScaleEngine); #endif /*QWT_VERSION < 0x060100 */ setYaxis(1e-10, 10.0*log10(max)); } @@ -908,7 +930,7 @@ bool TimeDomainDisplayPlot::isZoomerEnabled() void TimeDomainDisplayPlot::setZoomerVertAxis(int index) { - if (index < -1 || index >= axesCount(QwtPlot::yLeft)) + if (index < -1 || index >= axesCount(QwtAxis::YLeft)) return; for (unsigned int i = 0; i < d_zoomer.size(); ++i) @@ -919,37 +941,37 @@ void TimeDomainDisplayPlot::setZoomerVertAxis(int index) QString TimeDomainDisplayPlot::timeScaleValueFormat(double value, int precision) const { - return d_timeFormatter.format(value, "", precision); + return d_yAxisFormatter->format(value, "", precision); } QString TimeDomainDisplayPlot::timeScaleValueFormat(double value) { - OscScaleDraw *scale = static_cast(this->axisScaleDraw(QwtPlot::xBottom)); + OscScaleDraw *scale = static_cast(this->axisScaleDraw(QwtAxis::XBottom)); - return d_timeFormatter.format(value, "", scale->getFloatPrecison()); + return d_yAxisFormatter->format(value, "", scale->getFloatPrecison()); } QString TimeDomainDisplayPlot::yAxisScaleValueFormat(double value, int precision) const { value *= d_displayScale; - return d_metricFormatter.format(value, d_yAxisUnit, precision); + return d_xAxisFormatter->format(value, d_yAxisUnit, precision); } QString TimeDomainDisplayPlot::yAxisScaleValueFormat(double value) { - OscScaleDraw *scale = static_cast(this->axisScaleDraw(QwtPlot::yLeft)); + OscScaleDraw *scale = static_cast(this->axisScaleDraw(QwtAxis::YLeft)); - return d_metricFormatter.format(value, d_yAxisUnit, scale->getFloatPrecison()); + return d_xAxisFormatter->format(value, d_yAxisUnit, scale->getFloatPrecison()); } void TimeDomainDisplayPlot::setYLabel(const std::string &label, - const std::string &unit) + const std::string &unit) { std::string l = label; if(unit.length() > 0) l += " (" + unit + ")"; - setAxisTitle(QwtPlot::yLeft, QString(l.c_str())); + setAxisTitle(QwtAxis::YLeft, QString(l.c_str())); } void @@ -1351,21 +1373,20 @@ bool TimeDomainDisplayPlot::unregisterSink(std::string sinkName) return ret; } -void TimeDomainDisplayPlot::configureAxis(int axisPos, int axisIdx) +void TimeDomainDisplayPlot::configureAxis(int axisPos, int axisIdx, PrefixFormatter* prefixFormatter) { QwtAxisId axis(axisPos, axisIdx); - PrefixFormatter *prefixFormatter; QString unit; unsigned int floatPrecision; unsigned int numDivs; - if (axisPos == QwtPlot::yLeft) { - prefixFormatter = &d_metricFormatter; + if (axisPos == QwtAxis::YLeft) { + d_xAxisFormatter = prefixFormatter; unit = d_yAxisUnit; floatPrecision = 2; numDivs = yAxisNumDiv(); } else { - prefixFormatter = &d_timeFormatter; + d_yAxisFormatter = prefixFormatter; unit = d_xAxisUnit; floatPrecision = 2; numDivs = xAxisNumDiv(); @@ -1380,7 +1401,7 @@ void TimeDomainDisplayPlot::configureAxis(int axisPos, int axisIdx) OscScaleDraw *scaleDraw = new OscScaleDraw(prefixFormatter, unit); scaleDraw->setFloatPrecision(floatPrecision); this->setAxisScaleDraw(axis, scaleDraw); - if (axisPos == QwtPlot::yLeft) { + if (axisPos == QwtAxis::YLeft) { //yLeft 0 has a different position than the rest, so we //give it a bigger minimum extent in order to align it with //the other yLeft axes. diff --git a/src/TimeDomainDisplayPlot.h b/src/TimeDomainDisplayPlot.h index 02eb47c228..67e862482a 100644 --- a/src/TimeDomainDisplayPlot.h +++ b/src/TimeDomainDisplayPlot.h @@ -100,7 +100,8 @@ class TimeDomainDisplayPlot: public DisplayPlot Q_PROPERTY ( Qt::BrushStyle tag_background_style READ getTagBackgroundStyle WRITE setTagBackgroundStyle ) public: - TimeDomainDisplayPlot(QWidget*, bool isdBgraph = false, unsigned int xNumDivs = 10, unsigned int yNumDivs = 10); + TimeDomainDisplayPlot(QWidget*, bool isdBgraph = false, unsigned int xNumDivs = 10, unsigned int yNumDivs = 10, + PrefixFormatter* pfXaxis = nullptr, PrefixFormatter* pfYaxis = nullptr); virtual ~TimeDomainDisplayPlot(); void plotNewData(const std::string &sender, @@ -120,6 +121,9 @@ class TimeDomainDisplayPlot: public DisplayPlot void setYaxisUnit(QString unitType); QString yAxisUnit(void); + void setXaxisUnit(QString unitType); + QString xAxisUnit(void); + const QColor getTagTextColor(); const QColor getTagBackgroundColor(); const Qt::BrushStyle getTagBackgroundStyle(); @@ -203,7 +207,7 @@ public Q_SLOTS: void updatePreview(double reftimebase, double timebase, double timeposition); protected: - virtual void configureAxis(int axisPos, int axisIdx); + virtual void configureAxis(int axisPos, int axisIdx, PrefixFormatter* prefixFormatter); virtual void cleanUpJustBeforeChannelRemoval(int chnIdx); private Q_SLOTS: @@ -237,8 +241,8 @@ private Q_SLOTS: std::vector< std::vector > d_tag_markers; std::vector d_tag_markers_en; - MetricPrefixFormatter d_metricFormatter; - TimePrefixFormatter d_timeFormatter; + PrefixFormatter* d_xAxisFormatter; + PrefixFormatter* d_yAxisFormatter; QColor d_tag_text_color; QColor d_tag_background_color; diff --git a/src/application_restarter.cpp b/src/application_restarter.cpp index aa51d98690..e5d206c9a9 100644 --- a/src/application_restarter.cpp +++ b/src/application_restarter.cpp @@ -4,6 +4,10 @@ #include #include +#ifdef __ANDROID__ + #include +#endif + using namespace adiscope; ApplicationRestarter::ApplicationRestarter(const QString &executable) @@ -25,15 +29,20 @@ QStringList ApplicationRestarter::getArguments() const int ApplicationRestarter::restart(int exitCode) { - if (qApp->property("restart").toBool()) { - QProcess::startDetached(m_executable, m_arguments, m_currentPath); - } - - return exitCode; + if (qApp->property("restart").toBool()) { +#ifdef __ANDROID__ + QAndroidJniObject activity = QtAndroid::androidActivity(); + activity.callMethod("restart"); +#else + QProcess::startDetached(m_executable, m_arguments, m_currentPath); +#endif + } + + return exitCode; } void ApplicationRestarter::triggerRestart() { - qApp->setProperty("restart", QVariant(true)); + qApp->setProperty("restart", QVariant(true)); qApp->exit(); } diff --git a/src/dbgraph.cpp b/src/dbgraph.cpp index fed6611956..9f7f4cd9d2 100644 --- a/src/dbgraph.cpp +++ b/src/dbgraph.cpp @@ -43,17 +43,17 @@ void dBgraph::setupVerticalBars() d_frequencyBar->setPen(frequencyLinePen); d_frequencyBar->setVisible(true); - d_frequencyBar->setMobileAxis(QwtPlot::xTop); + d_frequencyBar->setMobileAxis(QwtAxis::XTop); d_frequencyBar->setPixelPosition(0); d_plotBar->setPen(plotLinePen); - d_plotBar->setMobileAxis(QwtPlot::xTop); + d_plotBar->setMobileAxis(QwtAxis::XTop); connect(d_frequencyBar, &VertBar::pixelPositionChanged, this, &dBgraph::frequencyBarPositionChanged); - d_vBar1->setMobileAxis(QwtPlot::xTop); - d_vBar2->setMobileAxis(QwtPlot::xTop); + d_vBar1->setMobileAxis(QwtAxis::XTop); + d_vBar2->setMobileAxis(QwtAxis::XTop); } void dBgraph::setupReadouts() @@ -85,11 +85,11 @@ dBgraph::dBgraph(QWidget *parent, bool isdBgraph) delta_label(false), d_plotBarEnabled(true) { - enableAxis(QwtPlot::xBottom, false); - enableAxis(QwtPlot::xTop, true); + setAxisVisible(QwtAxis::XBottom, false); + setAxisVisible(QwtAxis::XTop, true); - setAxisAutoScale(QwtPlot::yLeft, false); - setAxisAutoScale(QwtPlot::xTop, false); + setAxisAutoScale(QwtAxis::YLeft, false); + setAxisAutoScale(QwtAxis::XTop, false); QColor plotColor; if (QIcon::themeName() == "scopy-default") { @@ -101,19 +101,19 @@ dBgraph::dBgraph(QWidget *parent, bool isdBgraph) EdgelessPlotGrid *grid = new EdgelessPlotGrid; grid->setMajorPen(plotColor, 1.0, Qt::DashLine); - grid->setXAxis(QwtPlot::xTop); + grid->setXAxis(QwtAxis::XTop); grid->attach(this); plotLayout()->setAlignCanvasToScales(true); curve.attach(this); curve.setRenderHint(QwtPlotItem::RenderAntialiased); - curve.setXAxis(QwtPlot::xTop); - curve.setYAxis(QwtPlot::yLeft); + curve.setXAxis(QwtAxis::XTop); + curve.setYAxis(QwtAxis::YLeft); reference.setRenderHint(QwtPlotItem::RenderAntialiased); - reference.setXAxis(QwtPlot::xTop); - reference.setYAxis(QwtPlot::yLeft); + reference.setXAxis(QwtAxis::XTop); + reference.setYAxis(QwtAxis::YLeft); reference.setPen(Qt::red, 1.5); thickness = 1; @@ -123,7 +123,7 @@ dBgraph::dBgraph(QWidget *parent, bool isdBgraph) OscScaleEngine *scaleLeft = new OscScaleEngine; setYaxisNumDiv(7); scaleLeft->setMajorTicksCount(7); - this->setAxisScaleEngine(QwtPlot::yLeft, + this->setAxisScaleEngine(QwtAxis::YLeft, static_cast(scaleLeft)); /* draw_x / draw_y: Outmost X / Y scales. Only draw the labels */ @@ -131,14 +131,14 @@ dBgraph::dBgraph(QWidget *parent, bool isdBgraph) draw_x->setFloatPrecision(2); draw_x->enableComponent(QwtAbstractScaleDraw::Ticks, false); draw_x->enableComponent(QwtAbstractScaleDraw::Backbone, false); - setAxisScaleDraw(QwtPlot::xTop, draw_x); + setAxisScaleDraw(QwtAxis::XTop, draw_x); draw_y = new OscScaleDraw("dB"); draw_y->setFloatPrecision(2); draw_y->enableComponent(QwtAbstractScaleDraw::Ticks, false); draw_y->enableComponent(QwtAbstractScaleDraw::Backbone, false); draw_y->setMinimumExtent(50); - setAxisScaleDraw(QwtPlot::yLeft, draw_y); + setAxisScaleDraw(QwtAxis::YLeft, draw_y); d_leftHandlesArea->setMinimumWidth(60); d_leftHandlesArea->setTopPadding(10); @@ -162,9 +162,9 @@ dBgraph::dBgraph(QWidget *parent, bool isdBgraph) /* Top/bottom scales must be sync'd to xTop; left/right scales * must be sync'd to yLeft */ if (i < 2) { - scaleItem->setXAxis(QwtPlot::xTop); + scaleItem->setXAxis(QwtAxis::XTop); } else { - scaleItem->setYAxis(QwtPlot::yLeft); + scaleItem->setYAxis(QwtAxis::YLeft); } scaleItem->scaleDraw()->enableComponent( @@ -194,18 +194,18 @@ dBgraph::dBgraph(QWidget *parent, bool isdBgraph) margins.setBottom(0); setContentsMargins(margins); - enableAxis(QwtPlot::yLeft, false); - enableAxis(QwtPlot::xTop, false); + setAxisVisible(QwtAxis::YLeft, false); + setAxisVisible(QwtAxis::XTop, false); - QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::xTop); + QwtScaleWidget *scaleWidget = axisWidget(QwtAxis::XTop); const int fmw = QFontMetrics(scaleWidget->font()).width("-XXXX.XX XX"); scaleWidget->setMinBorderDist(fmw / 2, fmw / 2); setupVerticalBars(); setupReadouts(); - markerIntersection1->setAxes(QwtPlot::xTop, QwtPlot::yLeft); - markerIntersection2->setAxes(QwtPlot::xTop, QwtPlot::yLeft); + markerIntersection1->setAxes(QwtAxis::XTop, QwtAxis::YLeft); + markerIntersection2->setAxes(QwtAxis::XTop, QwtAxis::YLeft); } dBgraph::~dBgraph() @@ -224,7 +224,7 @@ void dBgraph::replot() d_leftHandlesArea->repaint(); d_topHandlesArea->repaint(); - QwtPlot::replot(); + BasicPlot::replot(); } void dBgraph::enableXaxisLabels() @@ -249,8 +249,8 @@ void dBgraph::parametersOverrange(bool enable) void dBgraph::setAxesScales(double xmin, double xmax, double ymin, double ymax) { - setAxisScale(QwtPlot::xTop, xmin, xmax); - setAxisScale(QwtPlot::yLeft, ymin, ymax); + setAxisScale(QwtAxis::XTop, xmin, xmax); + setAxisScale(QwtAxis::YLeft, ymin, ymax); } void dBgraph::setAxesTitles(const QString& x, const QString& y) @@ -258,13 +258,13 @@ void dBgraph::setAxesTitles(const QString& x, const QString& y) QwtText xTitle(x); QwtText yTitle(y); - QFont font = axisTitle(QwtPlot::xTop).font(); + QFont font = axisTitle(QwtAxis::XTop).font(); font.setWeight(QFont::Normal); xTitle.setFont(font); yTitle.setFont(font); - setAxisTitle(QwtPlot::xTop, xTitle); - setAxisTitle(QwtPlot::yLeft, yTitle); + setAxisTitle(QwtAxis::XTop, xTitle); + setAxisTitle(QwtAxis::YLeft, yTitle); } void dBgraph::plot(double x, double y) @@ -347,7 +347,7 @@ void dBgraph::setShowZero(bool en) scaleLeft->setMajorTicksCount(7); scaleLeft->showZero(en); - this->setAxisScaleEngine(QwtPlot::yLeft, + this->setAxisScaleEngine(QwtAxis::YLeft, static_cast(scaleLeft)); replot(); @@ -404,32 +404,32 @@ double dBgraph::getThickness() QString dBgraph::xTitle() const { - return axisTitle(QwtPlot::xTop).text(); + return axisTitle(QwtAxis::XTop).text(); } QString dBgraph::yTitle() const { - return axisTitle(QwtPlot::yLeft).text(); + return axisTitle(QwtAxis::YLeft).text(); } void dBgraph::setXTitle(const QString& title) { QwtText xTitle(title); - QFont font = axisTitle(QwtPlot::xTop).font(); + QFont font = axisTitle(QwtAxis::XTop).font(); font.setWeight(QFont::Normal); xTitle.setFont(font); - setAxisTitle(QwtPlot::xTop, xTitle); + setAxisTitle(QwtAxis::XTop, xTitle); } void dBgraph::setYTitle(const QString& title) { QwtText yTitle(title); - QFont font = axisTitle(QwtPlot::xTop).font(); + QFont font = axisTitle(QwtAxis::XTop).font(); font.setWeight(QFont::Normal); yTitle.setFont(font); - setAxisTitle(QwtPlot::yLeft, yTitle); + setAxisTitle(QwtAxis::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)+" = "); @@ -438,13 +438,13 @@ void dBgraph::setYTitle(const QString& title) void dBgraph::setXMin(double val) { zoomer->resetZoom(); - setAxisScale(QwtPlot::xTop, val, xmax); + setAxisScale(QwtAxis::XTop, val, xmax); xmin = val; draw_x->invalidateCache(); zoomer->setZoomBase(); replot(); - auto div = axisScaleDiv(QwtPlot::xTop); + auto div = axisScaleDiv(QwtAxis::XTop); setXaxisNumDiv((div.ticks(2)).size() - 1); setXaxisMajorTicksPos(div.ticks(2)); } @@ -452,20 +452,20 @@ void dBgraph::setXMin(double val) void dBgraph::setXMax(double val) { zoomer->resetZoom(); - setAxisScale(QwtPlot::xTop, xmin, val); + setAxisScale(QwtAxis::XTop, xmin, val); xmax = val; draw_x->invalidateCache(); zoomer->setZoomBase(); replot(); - auto div = axisScaleDiv(QwtPlot::xTop); + auto div = axisScaleDiv(QwtAxis::XTop); setXaxisNumDiv((div.ticks(2)).size() - 1); setXaxisMajorTicksPos(div.ticks(2)); } void dBgraph::setYMin(double val) { - setAxisScale(QwtPlot::yLeft, val, ymax); + setAxisScale(QwtAxis::YLeft, val, ymax); ymin = val; replot(); d_leftHandlesArea->repaint(); @@ -478,7 +478,7 @@ void dBgraph::setYMin(double val) void dBgraph::setYMax(double val) { - setAxisScale(QwtPlot::yLeft, ymin, val); + setAxisScale(QwtAxis::YLeft, ymin, val); ymax = val; replot(); @@ -511,9 +511,9 @@ void dBgraph::useLogFreq(bool use_log_freq) { if (use_log_freq) { setPlotLogaritmic(true); - this->setAxisScaleEngine(QwtPlot::xTop, new QwtLogScaleEngine); + this->setAxisScaleEngine(QwtAxis::XTop, new QwtLogScaleEngine); replot(); - auto div = axisScaleDiv(QwtPlot::xTop); + auto div = axisScaleDiv(QwtAxis::XTop); setXaxisNumDiv((div.ticks(2)).size() - 1); setXaxisMajorTicksPos(div.ticks(2)); } else { @@ -521,7 +521,7 @@ void dBgraph::useLogFreq(bool use_log_freq) auto scaleTop = new OscScaleEngine; scaleTop->setMajorTicksCount(9); setXaxisNumDiv(8); - this->setAxisScaleEngine(QwtPlot::xTop, scaleTop); + this->setAxisScaleEngine(QwtAxis::XTop, scaleTop); } this->log_freq = use_log_freq; @@ -533,7 +533,7 @@ void dBgraph::useLogFreq(bool use_log_freq) // Use delta only when log scale is disabled and delta // label mode is enabled - auto sw = axisWidget(QwtPlot::xTop); + auto sw = axisWidget(QwtAxis::XTop); auto *sd = dynamic_cast(sw->scaleDraw()); sd->enableDeltaLabel(delta_label & (!use_log_freq)); sw->repaint(); @@ -547,7 +547,7 @@ void dBgraph::useDeltaLabel(bool use_delta) delta_label = use_delta; if (!log_freq) { - auto sw = axisWidget(QwtPlot::xTop); + auto sw = axisWidget(QwtAxis::XTop); auto *sd = dynamic_cast(sw->scaleDraw()); sd->enableDeltaLabel(use_delta); sw->repaint(); @@ -752,8 +752,8 @@ void dBgraph::setYAxisInterval(double min, double max, double correction) void dBgraph::scaleDivChanged() { QwtPlot *plt = static_cast((sender())->parent()); - QwtInterval intv = plt->axisInterval(QwtPlot::xTop); - this->setAxisScale(QwtPlot::xTop, intv.minValue(), intv.maxValue()); + QwtInterval intv = plt->axisInterval(QwtAxis::XTop); + this->setAxisScale(QwtAxis::XTop, intv.minValue(), intv.maxValue()); this->replot(); onVCursor1Moved(d_vBar1->plotCoord().x()); @@ -764,6 +764,11 @@ void dBgraph::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::RightButton) { Q_EMIT resetZoom(); +#ifdef __ANDROID__ + } else if (event->type() == QEvent::MouseButtonDblClick) { + zoomer->popZoom(); + Q_EMIT zoomOut(); +#endif } } @@ -772,11 +777,18 @@ void dBgraph::onResetZoom() zoomer->resetZoom(); } +#ifdef __ANDROID__ +void dBgraph::onZoomOut() +{ + zoomer->popZoom(); +} +#endif + void dBgraph::showEvent(QShowEvent *event) { d_hCursorHandle1->updatePosition(); d_hCursorHandle2->updatePosition(); - auto sw = axisWidget(QwtPlot::xTop); + auto sw = axisWidget(QwtAxis::XTop); sw->scaleDraw()->invalidateCache(); sw->repaint(); } diff --git a/src/dbgraph.hpp b/src/dbgraph.hpp index 42a5a8602c..faf97a47b4 100644 --- a/src/dbgraph.hpp +++ b/src/dbgraph.hpp @@ -28,7 +28,7 @@ #include "customFifo.hpp" #include "symbol_controller.h" #include "plot_line_handle.h" -#include "cursor_readouts.h" +#include "gui/cursor_readouts.h" #include "DisplayPlot.h" namespace adiscope { @@ -110,6 +110,10 @@ class dBgraph : public DisplayPlot void frequencySelected(double); void frequencyBarPositionChanged(int); +#ifdef __ANDROID__ + void zoomOut(); +#endif + public Q_SLOTS: void plot(double x, double y); void reset(); @@ -137,6 +141,10 @@ public Q_SLOTS: void mousePressEvent(QMouseEvent *event); void onResetZoom(); +#ifdef __ANDROID__ + void onZoomOut(); +#endif + void onFrequencyCursorPositionChanged(int pos); void onFrequencyBarMoved(double frequency); diff --git a/src/debugger.h b/src/debugger.h index 9a02b49bb3..cbf2a1040a 100644 --- a/src/debugger.h +++ b/src/debugger.h @@ -28,11 +28,11 @@ /* Local includes */ #include "debug.h" -#include "bitfieldwidget.h" -#include "registerwidget.h" +#include "gui/bitfieldwidget.h" +#include "gui/registerwidget.h" #include "filter.hpp" #include "tool.hpp" -#include "detachedWindow.hpp" +#include "gui/detachedWindow.hpp" #include "tool_launcher.hpp" class QJSEngine; diff --git a/src/device_widget.cpp b/src/device_widget.cpp index ccdcbaec4c..afa6c5f278 100644 --- a/src/device_widget.cpp +++ b/src/device_widget.cpp @@ -19,8 +19,8 @@ */ #include "device_widget.hpp" -#include "dynamicWidget.hpp" -#include "info_page.hpp" +#include "gui/dynamicWidget.hpp" +#include "gui/info_page.hpp" #include "tool_launcher.hpp" #include "ui_device.h" diff --git a/src/digitalio.cpp b/src/digitalio.cpp index 42985394a0..6415132b61 100644 --- a/src/digitalio.cpp +++ b/src/digitalio.cpp @@ -31,7 +31,7 @@ #include "logging_categories.h" #include "digitalio.hpp" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include "digitalio_api.hpp" // Generated UI diff --git a/src/dmm.cpp b/src/dmm.cpp index 442fe01039..f892ea573b 100644 --- a/src/dmm.cpp +++ b/src/dmm.cpp @@ -19,7 +19,7 @@ */ #include "dmm.hpp" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include "ui_dmm.h" #include #include "utils.h" @@ -517,6 +517,7 @@ void DMM::toggleTimer(bool start) { enableDataLogging(start); if (start) { + manager->set_kernel_buffer_count(4); writeAllSettingsToHardware(); manager->start(id_ch1); manager->start(id_ch2); @@ -529,6 +530,7 @@ void DMM::toggleTimer(bool start) manager->stop(id_ch1); manager->stop(id_ch2); + manager->set_kernel_buffer_count(); } setDynamicProperty(ui->run_button, "running", start); diff --git a/src/dmm.hpp b/src/dmm.hpp index 4b0375dae5..e4ecffea86 100644 --- a/src/dmm.hpp +++ b/src/dmm.hpp @@ -32,7 +32,7 @@ #include "tool.hpp" #include "scroll_filter.hpp" #include -#include "spinbox_a.hpp" +#include "gui/spinbox_a.hpp" #include #include #include diff --git a/src/extendingplotzoomer.cpp b/src/extendingplotzoomer.cpp index ece6d8f5bc..fa56c91acc 100644 --- a/src/extendingplotzoomer.cpp +++ b/src/extendingplotzoomer.cpp @@ -77,7 +77,6 @@ QPolygon ExtendingPlotZoomer::adjustedPoints(const QPolygon &points) const cornerMarkers[1]->detach(); cornerMarkers[2]->detach(); cornerMarkers[3]->detach(); - static_cast((QwtPlot*)plot())->replot(); return points; } @@ -114,7 +113,7 @@ QPolygon ExtendingPlotZoomer::adjustedPoints(const QPolygon &points) const adjusted += topLeft; adjusted += bottomRight; - if (yAxis() == QwtAxisId(QwtPlot::yLeft, 0)) { + if (yAxis() == QwtAxisId(QwtAxis::YLeft, 0)) { cornerMarkers[0]->detach(); cornerMarkers[1]->detach(); cornerMarkers[2]->detach(); @@ -158,7 +157,7 @@ QPolygon ExtendingPlotZoomer::adjustedPoints(const QPolygon &points) const adjusted += topLeft; adjusted += bottomRight; - if (yAxis() == QwtAxisId(QwtPlot::yLeft, 0)) { + if (yAxis() == QwtAxisId(QwtAxis::YLeft, 0)) { cornerMarkers[0]->detach(); cornerMarkers[1]->detach(); cornerMarkers[2]->detach(); @@ -197,7 +196,7 @@ QPolygon ExtendingPlotZoomer::adjustedPoints(const QPolygon &points) const } - if (yAxis() == QwtAxisId(QwtPlot::yLeft, 0)) { + if (yAxis() == QwtAxisId(QwtAxis::YLeft, 0)) { extendMarkers[0]->detach(); extendMarkers[1]->detach(); diff --git a/src/ComboBoxLineEdit.cpp b/src/gui/ComboBoxLineEdit.cpp similarity index 100% rename from src/ComboBoxLineEdit.cpp rename to src/gui/ComboBoxLineEdit.cpp diff --git a/src/ComboBoxLineEdit.h b/src/gui/ComboBoxLineEdit.h similarity index 100% rename from src/ComboBoxLineEdit.h rename to src/gui/ComboBoxLineEdit.h diff --git a/src/animationmanager.cpp b/src/gui/animationmanager.cpp similarity index 100% rename from src/animationmanager.cpp rename to src/gui/animationmanager.cpp diff --git a/src/animationmanager.h b/src/gui/animationmanager.h similarity index 97% rename from src/animationmanager.h rename to src/gui/animationmanager.h index 7a533337a7..33bebc7a39 100644 --- a/src/animationmanager.h +++ b/src/gui/animationmanager.h @@ -21,7 +21,7 @@ #ifndef ANIMATIONMANAGER_H #define ANIMATIONMANAGER_H -#include +#include #include namespace adiscope { diff --git a/src/basemenu.cpp b/src/gui/basemenu.cpp similarity index 100% rename from src/basemenu.cpp rename to src/gui/basemenu.cpp diff --git a/src/basemenu.h b/src/gui/basemenu.h similarity index 100% rename from src/basemenu.h rename to src/gui/basemenu.h diff --git a/src/basemenuitem.cpp b/src/gui/basemenuitem.cpp similarity index 100% rename from src/basemenuitem.cpp rename to src/gui/basemenuitem.cpp diff --git a/src/basemenuitem.h b/src/gui/basemenuitem.h similarity index 100% rename from src/basemenuitem.h rename to src/gui/basemenuitem.h diff --git a/src/bitfieldwidget.cpp b/src/gui/bitfieldwidget.cpp similarity index 100% rename from src/bitfieldwidget.cpp rename to src/gui/bitfieldwidget.cpp diff --git a/src/bitfieldwidget.h b/src/gui/bitfieldwidget.h similarity index 100% rename from src/bitfieldwidget.h rename to src/gui/bitfieldwidget.h diff --git a/src/gui/channel_manager.cpp b/src/gui/channel_manager.cpp new file mode 100644 index 0000000000..2818787a6a --- /dev/null +++ b/src/gui/channel_manager.cpp @@ -0,0 +1,195 @@ +#include "dynamicWidget.hpp" + +#include + +#include "channel_manager.hpp" + +using namespace adiscope; +using namespace adiscope::gui; + +ChannelManager::ChannelManager(ChannelsPositionEnum position, QWidget* parent) + : QWidget(parent) + , m_scrollArea(new QScrollArea(parent)) + , m_channelsWidget(new QWidget(m_scrollArea)) + , m_switchBtn(new QPushButton(m_scrollArea)) + , m_hasAddBtn(false) + , m_position(position) +{ + if (m_position == ChannelsPositionEnum::VERTICAL) { + m_channelsWidget->setLayout(new QVBoxLayout(m_channelsWidget)); + + m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + } else { + m_channelsWidget->setLayout(new QHBoxLayout(m_channelsWidget)); + + m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + } + + m_channelsWidget->layout()->setSpacing(0); + m_channelsWidget->layout()->setMargin(0); + m_channelsWidget->layout()->setSizeConstraint(QLayout::SetMinAndMaxSize); + + m_scrollArea->setWidget(m_channelsWidget); + + m_scrollArea->setStyleSheet("background-color:orange"); + m_channelsWidget->setStyleSheet("background-color:red"); +} + +ChannelManager::~ChannelManager() +{ + delete m_channelsWidget; + + if (m_addChannelBtn) { + delete m_addChannelBtn; + } + + delete m_switchBtn; + delete m_parent; +} + +void ChannelManager::build(QWidget* parent) +{ + m_parent = parent; + + // Experimental - change orientation at runtime + setDynamicProperty(m_switchBtn, "blue_button", true); + m_switchBtn->setCheckable(true); + m_switchBtn->setFlat(true); + m_switchBtn->setText("Switch"); + connect(m_switchBtn, &QPushButton::toggled, [=]() { + if (m_position == ChannelsPositionEnum::VERTICAL) { + m_position = ChannelsPositionEnum::HORIZONTAL; + } else { + m_position = ChannelsPositionEnum::VERTICAL; + } + Q_EMIT positionChanged(m_position); + }); + + m_parent->layout()->addWidget(m_switchBtn); + m_parent->layout()->addWidget(m_scrollArea); +} + +ChannelWidget* ChannelManager::buildNewChannel(int chId, bool deletable, bool simplefied, QColor color, + const QString& fullName, const QString& shortName) +{ + ChannelWidget* ch = new ChannelWidget(chId, deletable, simplefied, color); + + m_channelsWidget->layout()->addWidget(ch); + ch->setFullName(fullName + QString(" %1").arg(chId + 1)); + ch->setShortName(shortName + QString(" %1").arg(chId + 1)); + ch->nameButton()->setText(ch->shortName()); + + m_channelsList.append(ch); + + if (m_position == ChannelsPositionEnum::VERTICAL) { + m_channelsWidget->setMinimumHeight(m_channelsList.size() * m_channelsList.first()->height()); + m_channelsWidget->setMaximumHeight(m_channelsList.size() * m_channelsList.first()->height()); + + m_channelsWidget->setMinimumWidth(m_channelsList.last()->width()); + m_channelsWidget->setMaximumWidth(m_channelsList.last()->width()); + } else { + m_channelsWidget->setMinimumWidth(m_channelsList.size() * m_channelsList.first()->width()); + m_channelsWidget->setMaximumWidth(m_channelsList.size() * m_channelsList.first()->width()); + + m_channelsWidget->setMinimumHeight(m_channelsList.first()->height()); + m_channelsWidget->setMaximumHeight(m_channelsList.first()->height()); + } + + return ch; +} + +void ChannelManager::removeChannel(ChannelWidget* ch) +{ + m_channelsList.removeOne(ch); + m_channelsWidget->layout()->removeWidget(ch); + delete ch; +} + +CustomPushButton* ChannelManager::getAddChannelBtn() +{ + if (m_hasAddBtn) { + return m_addChannelBtn; + } else { + return nullptr; + } +} + +QList ChannelManager::getChannelsList() { return m_channelsList; } + +void ChannelManager::changeParent(QWidget* newParent) +{ + delete m_channelsWidget->layout(); + + if (m_position == ChannelsPositionEnum::VERTICAL) { + m_channelsWidget->setLayout(new QVBoxLayout(m_channelsWidget)); + + m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + } else { + m_channelsWidget->setLayout(new QHBoxLayout(m_channelsWidget)); + + m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + } + + m_channelsWidget->layout()->setSizeConstraint(QLayout::SetMinAndMaxSize); + m_channelsWidget->layout()->setSpacing(0); + m_channelsWidget->layout()->setMargin(0); + + for (ChannelWidget* channel : m_channelsList) { + m_channelsWidget->layout()->addWidget(channel); + } + + if (m_position == ChannelsPositionEnum::VERTICAL) { + m_channelsWidget->setMinimumHeight(m_channelsList.size() * m_channelsList.first()->height()); + m_channelsWidget->setMaximumHeight(m_channelsList.size() * m_channelsList.first()->height()); + + m_channelsWidget->setMinimumWidth(m_channelsList.last()->width() + 25); + m_channelsWidget->setMaximumWidth(m_channelsList.last()->width() + 25); + } else { + m_channelsWidget->setMinimumWidth(m_channelsList.size() * m_channelsList.first()->width()); + m_channelsWidget->setMaximumWidth(m_channelsList.size() * m_channelsList.first()->width()); + + m_channelsWidget->setMinimumHeight(m_channelsList.first()->height()); + m_channelsWidget->setMaximumHeight(m_channelsList.first()->height()); + } + + m_parent = newParent; + m_parent->layout()->addWidget(m_switchBtn); + m_parent->layout()->addWidget(m_scrollArea); + m_parent->layout()->addWidget(m_addChannelBtn); +} + +QList ChannelManager::getEnabledChannels() +{ + QList lst; + + for (auto widget : m_channelsWidget->children()) { + ChannelWidget* channel = qobject_cast(widget); + if (channel->enableButton()->isChecked()) { + lst.append(channel); + } + } + + return lst; +} + +void ChannelManager::insertAddBtn(QWidget* menu, bool dockable) +{ + + m_hasAddBtn = true; + m_addChannelBtn = new CustomPushButton(m_scrollArea); + + // TO DO: center + btn when position is vertical + m_addChannelBtn->setCheckable(true); + m_addChannelBtn->setFlat(true); + m_addChannelBtn->setIcon(QIcon(":/menu/add.svg")); + m_addChannelBtn->setIconSize(QSize(16, 16)); + m_addChannelBtn->setMaximumSize(25, 25); + + m_parent->layout()->addWidget(m_addChannelBtn); + + Q_EMIT(configureAddBtn(menu, dockable)); +} diff --git a/src/gui/channel_manager.hpp b/src/gui/channel_manager.hpp new file mode 100644 index 0000000000..974fbe1246 --- /dev/null +++ b/src/gui/channel_manager.hpp @@ -0,0 +1,63 @@ +#ifndef CHANNEL_MANAGER_HPP +#define CHANNEL_MANAGER_HPP + +#include +#include +#include + +#include "channel_widget.hpp" +#include "customPushButton.hpp" + +namespace adiscope { +namespace gui { + +enum class ChannelsPositionEnum +{ + VERTICAL, + HORIZONTAL +}; + +class ChannelManager : public QWidget +{ + Q_OBJECT + +public: + explicit ChannelManager(ChannelsPositionEnum position = ChannelsPositionEnum::HORIZONTAL, + QWidget* parent = nullptr); + ~ChannelManager(); + + void build(QWidget* parent); + void insertAddBtn(QWidget* menu, bool dockable); + + ChannelWidget* buildNewChannel(int chId, bool deletable, bool simplefied, QColor color, const QString& fullName, + const QString& shortName); + void removeChannel(ChannelWidget* ch); + QList getEnabledChannels(); + + CustomPushButton* getAddChannelBtn(); + QList getChannelsList(); + +public Q_SLOTS: + void changeParent(QWidget* newParent); + +Q_SIGNALS: + void configureAddBtn(QWidget* menu, bool dockable); + void positionChanged(ChannelsPositionEnum position); + +private: + QWidget* m_parent; + QScrollArea* m_scrollArea; + QWidget* m_channelsWidget; + QPushButton* m_switchBtn; + + bool m_hasAddBtn; + CustomPushButton* m_addChannelBtn; + + ChannelsPositionEnum m_position; + + QList m_channelsList; +}; +} // namespace gui +} // namespace scopy + +#endif // CHANNEL_MANAGER_HPP diff --git a/src/channel_widget.cpp b/src/gui/channel_widget.cpp similarity index 98% rename from src/channel_widget.cpp rename to src/gui/channel_widget.cpp index cebf28b855..4b226f613e 100644 --- a/src/channel_widget.cpp +++ b/src/gui/channel_widget.cpp @@ -198,6 +198,8 @@ void ChannelWidget::setReferenceChannel(const bool &ref) m_ref = ref; } +void ChannelWidget::setMenuFloating(bool floating) { m_floatingMenu = floating; } + bool ChannelWidget::eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::MouseButtonPress) { diff --git a/src/channel_widget.hpp b/src/gui/channel_widget.hpp similarity index 97% rename from src/channel_widget.hpp rename to src/gui/channel_widget.hpp index 2b30d38579..babeb17ce7 100644 --- a/src/channel_widget.hpp +++ b/src/gui/channel_widget.hpp @@ -64,9 +64,15 @@ class ChannelWidget: public QWidget bool isReferenceChannel() const; void setReferenceChannel(const bool&); + void setMenuFloating(bool floating); + protected: bool eventFilter(QObject *object, QEvent *event) override; +private: + void init(); + void setButtonNoGroup(QAbstractButton *btn); + Q_SIGNALS: void enabled(bool en); void selected(bool on); @@ -94,8 +100,7 @@ private Q_SLOTS: QString m_function; bool m_ref; - void init(); - void setButtonNoGroup(QAbstractButton *btn); + bool m_floatingMenu; }; } /* namespace adiscope */ diff --git a/src/checkbox_delegate.cpp b/src/gui/checkbox_delegate.cpp similarity index 100% rename from src/checkbox_delegate.cpp rename to src/gui/checkbox_delegate.cpp diff --git a/src/checkbox_delegate.h b/src/gui/checkbox_delegate.h similarity index 100% rename from src/checkbox_delegate.h rename to src/gui/checkbox_delegate.h diff --git a/src/coloredQWidget.cpp b/src/gui/coloredQWidget.cpp similarity index 100% rename from src/coloredQWidget.cpp rename to src/gui/coloredQWidget.cpp diff --git a/src/coloredQWidget.hpp b/src/gui/coloredQWidget.hpp similarity index 100% rename from src/coloredQWidget.hpp rename to src/gui/coloredQWidget.hpp diff --git a/src/completion_circle.cpp b/src/gui/completion_circle.cpp similarity index 100% rename from src/completion_circle.cpp rename to src/gui/completion_circle.cpp diff --git a/src/completion_circle.h b/src/gui/completion_circle.h similarity index 100% rename from src/completion_circle.h rename to src/gui/completion_circle.h diff --git a/src/connectDialog.cpp b/src/gui/connectDialog.cpp similarity index 89% rename from src/connectDialog.cpp rename to src/gui/connectDialog.cpp index bf811760cb..803700b6b3 100644 --- a/src/connectDialog.cpp +++ b/src/gui/connectDialog.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include using namespace adiscope; @@ -102,33 +104,46 @@ void ConnectDialog::enableDemoBtn() QProcess killProcess; #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) killProcess.start("taskkill /im iio-emu /f"); +#else +#ifdef __ANDROID__ + killProcess.start("killall -9 iio-emu.so"); #else killProcess.start("pkill iio-emu"); +#endif #endif killProcess.waitForFinished(); // iio-emu found in system - QString dirPath = QCoreApplication::applicationDirPath(); - QString program = dirPath + "/iio-emu"; + QString program = qgetenv("IIOEMU_BIN"); + if(program.isEmpty()) { + // Env Var not found, try local folder + QString dirPath = QCoreApplication::applicationDirPath(); + program = dirPath + "/iio-emu"; + QFileInfo fi(program); + if(!fi.exists() || fi.isDir()) { + // iio-emu is built in-tree + // development build + program = dirPath + "/iio-emu/iio-emu"; + } + } + QStringList arguments; arguments.append(ui->demoDevicesComboBox->currentText()); process->setProgram(program); process->setArguments(arguments); process->start(); + auto started = process->waitForStarted(); + qDebug()<<"path"<readAllStandardOutput()); + qDebug()<<"stderr:"<readAllStandardError()); + if (!started) { - // retry to start the process - // path for iio-emu when Scopy is built manually - program = dirPath + "/iio-emu/iio-emu"; - process->setProgram(program); - process->start(); - started = process->waitForStarted(); - if (!started) { ui->description->setText("Server failed to start"); qDebug() << "Process failed to start"; return; - } } + qDebug()<<"Process " << program << "started"; ui->enableDemoBtn->setChecked(true); ui->enableDemoBtn->setText("Disable Demo"); diff --git a/src/connectDialog.hpp b/src/gui/connectDialog.hpp similarity index 100% rename from src/connectDialog.hpp rename to src/gui/connectDialog.hpp diff --git a/src/cursor_readouts.cpp b/src/gui/cursor_readouts.cpp similarity index 99% rename from src/cursor_readouts.cpp rename to src/gui/cursor_readouts.cpp index e9945679b7..352b59608d 100644 --- a/src/cursor_readouts.cpp +++ b/src/gui/cursor_readouts.cpp @@ -39,8 +39,8 @@ CursorReadouts::CursorReadouts(QwtPlot *plot): freq_delta_visible(true), d_topLeft(QPoint(0, 0)), currentPosition(CustomPlotPositionButton::topLeft), - hAxis(QwtPlot::xBottom), - vAxis(QwtPlot::yLeft) + hAxis(QwtAxis::XBottom), + vAxis(QwtAxis::YLeft) { ui->setupUi(this); ui->TimeCursors->setParent(plot->canvas()); diff --git a/src/cursor_readouts.h b/src/gui/cursor_readouts.h similarity index 99% rename from src/cursor_readouts.h rename to src/gui/cursor_readouts.h index c462a2ca52..8f64a10e52 100644 --- a/src/cursor_readouts.h +++ b/src/gui/cursor_readouts.h @@ -22,7 +22,7 @@ #define CURSOR_READOUTS_H #include -#include "customanimation.h" +#include "gui/customanimation.h" #include #include #include "customplotpositionbutton.h" diff --git a/src/customPushButton.cpp b/src/gui/customPushButton.cpp similarity index 100% rename from src/customPushButton.cpp rename to src/gui/customPushButton.cpp diff --git a/src/customPushButton.hpp b/src/gui/customPushButton.hpp similarity index 100% rename from src/customPushButton.hpp rename to src/gui/customPushButton.hpp diff --git a/src/customSwitch.cpp b/src/gui/customSwitch.cpp similarity index 100% rename from src/customSwitch.cpp rename to src/gui/customSwitch.cpp diff --git a/src/customSwitch.hpp b/src/gui/customSwitch.hpp similarity index 97% rename from src/customSwitch.hpp rename to src/gui/customSwitch.hpp index 4a419b2dff..1a3721502d 100644 --- a/src/customSwitch.hpp +++ b/src/gui/customSwitch.hpp @@ -22,7 +22,7 @@ #define CUSTOM_SWITCH_HPP #include -#include "customanimation.h" +#include "gui/customanimation.h" #include #include diff --git a/src/gui/custom_menu_button.cpp b/src/gui/custom_menu_button.cpp new file mode 100644 index 0000000000..1d4885b165 --- /dev/null +++ b/src/gui/custom_menu_button.cpp @@ -0,0 +1,54 @@ +#include "ui_custom_menu_button.h" + +#include "custom_menu_button.hpp" + +using namespace adiscope::gui; + +CustomMenuButton::CustomMenuButton(QString labelText, bool checkboxVisible, bool checkBoxChecked, QWidget* parent) + : CustomMenuButton(parent) +{ + + m_ui->lblCustomMenuButton->setText(labelText); + m_ui->checkBoxCustomMenuButton->setVisible(checkboxVisible); + + if (checkboxVisible) { + checkBoxToggled(checkBoxChecked); + m_ui->checkBoxCustomMenuButton->setChecked(checkBoxChecked); + } +} + +CustomMenuButton::CustomMenuButton(QWidget* parent) + : QWidget(parent) + , m_ui(new Ui::CustomMenuButton) + , m_floatingMenu(false) +{ + m_ui->setupUi(this); + connect(m_ui->checkBoxCustomMenuButton, &QCheckBox::toggled, this, &CustomMenuButton::checkBoxToggled); +} + +CustomMenuButton::~CustomMenuButton() { delete m_ui; } + +void CustomMenuButton::setLabel(const QString& text) { m_ui->lblCustomMenuButton->setText(text); } + +void CustomMenuButton::setCheckboxVisible(bool visible) { m_ui->checkBoxCustomMenuButton->setVisible(visible); } + +CustomPushButton* CustomMenuButton::getBtn() { return m_ui->btnCustomMenuButton; } + +QCheckBox* CustomMenuButton::getCheckBox() { return m_ui->checkBoxCustomMenuButton; } + +bool CustomMenuButton::getCheckBoxState() { return getCheckBox()->isChecked(); } + +void CustomMenuButton::setCheckBoxState(bool checked) { m_ui->checkBoxCustomMenuButton->setChecked(checked); } + +void CustomMenuButton::setMenuFloating(bool floating) { m_floatingMenu = floating; } + +void CustomMenuButton::checkBoxToggled(bool toggled) +{ + if (!toggled) { + m_ui->btnCustomMenuButton->setChecked(false); + } + + if (!m_floatingMenu) { + m_ui->btnCustomMenuButton->setEnabled(toggled); + } +} diff --git a/src/gui/custom_menu_button.hpp b/src/gui/custom_menu_button.hpp new file mode 100644 index 0000000000..80636f3696 --- /dev/null +++ b/src/gui/custom_menu_button.hpp @@ -0,0 +1,49 @@ +#ifndef CUSTOMMENUBUTTON_H +#define CUSTOMMENUBUTTON_H + +#include +#include +#include + +#include "customPushButton.hpp" + +using namespace adiscope; + +namespace Ui { +class CustomMenuButton; +} + +namespace adiscope { +namespace gui { + +class CustomMenuButton : public QWidget +{ + Q_OBJECT + +public: + explicit CustomMenuButton(QString labelText = nullptr, bool checkboxVisible = false, + bool checkBoxChecked = false, QWidget* parent = nullptr); + explicit CustomMenuButton(QWidget* parent = nullptr); + ~CustomMenuButton(); + + void setLabel(const QString& text); + void setCheckboxVisible(bool visible); + + CustomPushButton* getBtn(); + QCheckBox* getCheckBox(); + bool getCheckBoxState(); + void setCheckBoxState(bool checked); + void setMenuFloating(bool floating); + +public Q_SLOTS: + void checkBoxToggled(bool toggled); + +private: + Ui::CustomMenuButton* m_ui; + + bool m_floatingMenu; +}; +} // namespace gui +} // namespace scopy + +#endif // CUSTOMMENUBUTTON_H diff --git a/src/customanimation.cpp b/src/gui/customanimation.cpp similarity index 97% rename from src/customanimation.cpp rename to src/gui/customanimation.cpp index 9eb830eaa6..25b0d369ff 100644 --- a/src/customanimation.cpp +++ b/src/gui/customanimation.cpp @@ -19,7 +19,7 @@ */ #include "customanimation.h" -#include +#include using namespace adiscope; diff --git a/src/customanimation.h b/src/gui/customanimation.h similarity index 100% rename from src/customanimation.h rename to src/gui/customanimation.h diff --git a/src/customplotpositionbutton.cpp b/src/gui/customplotpositionbutton.cpp similarity index 100% rename from src/customplotpositionbutton.cpp rename to src/gui/customplotpositionbutton.cpp diff --git a/src/customplotpositionbutton.h b/src/gui/customplotpositionbutton.h similarity index 97% rename from src/customplotpositionbutton.h rename to src/gui/customplotpositionbutton.h index 999221de22..66af71601f 100644 --- a/src/customplotpositionbutton.h +++ b/src/gui/customplotpositionbutton.h @@ -21,7 +21,7 @@ #define CUSTOMPLOTPOSITIONBUTTON_H #include -#include "coloredQWidget.hpp" +#include "gui/coloredQWidget.hpp" #include namespace Ui { diff --git a/src/db_click_buttons.cpp b/src/gui/db_click_buttons.cpp similarity index 100% rename from src/db_click_buttons.cpp rename to src/gui/db_click_buttons.cpp diff --git a/src/db_click_buttons.hpp b/src/gui/db_click_buttons.hpp similarity index 100% rename from src/db_click_buttons.hpp rename to src/gui/db_click_buttons.hpp diff --git a/src/detachdragzone.cpp b/src/gui/detachdragzone.cpp similarity index 98% rename from src/detachdragzone.cpp rename to src/gui/detachdragzone.cpp index 58c5bccc25..6121da74be 100644 --- a/src/detachdragzone.cpp +++ b/src/gui/detachdragzone.cpp @@ -21,7 +21,7 @@ #include "tool_launcher.hpp" #include -#include "basemenuitem.h" +#include "gui/basemenuitem.h" using namespace adiscope; diff --git a/src/detachdragzone.h b/src/gui/detachdragzone.h similarity index 97% rename from src/detachdragzone.h rename to src/gui/detachdragzone.h index 338cd5e0d5..31260839f7 100644 --- a/src/detachdragzone.h +++ b/src/gui/detachdragzone.h @@ -26,7 +26,7 @@ #include #include -#include "coloredQWidget.hpp" +#include "gui/coloredQWidget.hpp" namespace adiscope { class DetachDragZone : public ColoredQWidget diff --git a/src/detachedWindow.cpp b/src/gui/detachedWindow.cpp similarity index 100% rename from src/detachedWindow.cpp rename to src/gui/detachedWindow.cpp diff --git a/src/detachedWindow.hpp b/src/gui/detachedWindow.hpp similarity index 100% rename from src/detachedWindow.hpp rename to src/gui/detachedWindow.hpp diff --git a/src/detachedwindowsmanager.cpp b/src/gui/detachedwindowsmanager.cpp similarity index 100% rename from src/detachedwindowsmanager.cpp rename to src/gui/detachedwindowsmanager.cpp diff --git a/src/detachedwindowsmanager.h b/src/gui/detachedwindowsmanager.h similarity index 100% rename from src/detachedwindowsmanager.h rename to src/gui/detachedwindowsmanager.h diff --git a/src/dragzone.cpp b/src/gui/dragzone.cpp similarity index 100% rename from src/dragzone.cpp rename to src/gui/dragzone.cpp diff --git a/src/dragzone.h b/src/gui/dragzone.h similarity index 100% rename from src/dragzone.h rename to src/gui/dragzone.h diff --git a/src/dropdown_switch_list.cpp b/src/gui/dropdown_switch_list.cpp similarity index 99% rename from src/dropdown_switch_list.cpp rename to src/gui/dropdown_switch_list.cpp index 05f8affad8..cd59290577 100644 --- a/src/dropdown_switch_list.cpp +++ b/src/gui/dropdown_switch_list.cpp @@ -19,7 +19,7 @@ */ #include "dropdown_switch_list.h" -#include "checkbox_delegate.h" +#include "gui/checkbox_delegate.h" #include #include diff --git a/src/dropdown_switch_list.h b/src/gui/dropdown_switch_list.h similarity index 98% rename from src/dropdown_switch_list.h rename to src/gui/dropdown_switch_list.h index 469b1ed808..f0a5451a38 100644 --- a/src/dropdown_switch_list.h +++ b/src/gui/dropdown_switch_list.h @@ -22,7 +22,7 @@ #define DROPDOWN_SWITCH_LIST_H #include -#include "ComboBoxLineEdit.h" +#include "gui/ComboBoxLineEdit.h" class QStandardItemModel; class QTreeView; diff --git a/src/dynamicWidget.cpp b/src/gui/dynamicWidget.cpp similarity index 100% rename from src/dynamicWidget.cpp rename to src/gui/dynamicWidget.cpp diff --git a/src/dynamicWidget.hpp b/src/gui/dynamicWidget.hpp similarity index 100% rename from src/dynamicWidget.hpp rename to src/gui/dynamicWidget.hpp diff --git a/src/gui/externalloadlineedit.cpp b/src/gui/externalloadlineedit.cpp new file mode 100644 index 0000000000..48e3a44b2c --- /dev/null +++ b/src/gui/externalloadlineedit.cpp @@ -0,0 +1,39 @@ +#include + +constexpr double ExternalLoadLineEdit::MAX_EXTERNAL_LOAD; +constexpr double ExternalLoadLineEdit::MIN_EXTERNAL_LOAD; +constexpr double ExternalLoadLineEdit::OUTPUT_AWG_RESISTANCE; + +ExternalLoadLineEdit::ExternalLoadLineEdit(QWidget *parent) : QLineEdit(parent) { + value = MAX_EXTERNAL_LOAD; + connect(this,SIGNAL(editingFinished()),this,SLOT(setValue())); +} + +ExternalLoadLineEdit::~ExternalLoadLineEdit() { + +}; + +double ExternalLoadLineEdit::getValue() { + return value; +} + +void ExternalLoadLineEdit::setValue() { + setValue(text().toDouble()); +} + +void ExternalLoadLineEdit::setValue(QString val) { + setValue(val.toDouble()); +} +void ExternalLoadLineEdit::setValue(double val) { + QString textVal; + val = std::max(val, MIN_EXTERNAL_LOAD); + if(val >= MAX_EXTERNAL_LOAD) { + textVal = "inf"; + val = MAX_EXTERNAL_LOAD; + } else { + textVal = QString::number(val); + } + setText(textVal); + value = val; + Q_EMIT valueChanged(value); +} diff --git a/src/gui/externalloadlineedit.h b/src/gui/externalloadlineedit.h new file mode 100644 index 0000000000..021aae3ade --- /dev/null +++ b/src/gui/externalloadlineedit.h @@ -0,0 +1,32 @@ +#ifndef EXTERNALLOADLINEEDIT_H +#define EXTERNALLOADLINEEDIT_H + +#include + +class ExternalLoadLineEdit : public QLineEdit +{ + Q_OBJECT +public: + static constexpr double MAX_EXTERNAL_LOAD = 100000.0; + static constexpr double MIN_EXTERNAL_LOAD = 50.0; + static constexpr double OUTPUT_AWG_RESISTANCE = 50.0; + + ExternalLoadLineEdit(QWidget *parent = nullptr); + ~ExternalLoadLineEdit(); + + Q_PROPERTY(double value READ getValue WRITE setValue); + + double getValue(); +public Q_SLOTS: + void setValue(); + void setValue(double val); + void setValue(QString val); + +Q_SIGNALS: + void valueChanged(double); +protected: + double value; + +}; + +#endif // EXTERNALLOADLINEEDIT diff --git a/src/gui/generic_menu.cpp b/src/gui/generic_menu.cpp new file mode 100644 index 0000000000..f5568874bf --- /dev/null +++ b/src/gui/generic_menu.cpp @@ -0,0 +1,49 @@ +#include + +#include "generic_menu.hpp" + +using namespace adiscope::gui; + +GenericMenu::GenericMenu(QWidget* parent) + : QWidget(parent) + , m_menuHeader(new MenuHeader(parent)) + , m_menu(new BaseMenu(parent)) + , m_lastOpenPosition(0) +{} + +GenericMenu::~GenericMenu() +{ + delete m_menuHeader; + delete m_menu; +} + +void GenericMenu::initInteractiveMenu() +{ + this->setStyleSheet(".QWidget { background-color: none; }"); + + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setSpacing(10); + layout->setContentsMargins(18, 20, 18, 9); + + layout->addWidget(m_menuHeader); + layout->addWidget(m_menu); + + this->setLayout(layout); +} + +void GenericMenu::setMenuHeader(const QString& title, const QColor* lineColor, bool hasEnableBtn) +{ + m_menuHeader->setLabel(title); + m_menuHeader->setLineColor(lineColor); + m_menuHeader->setEnabledBtnState(hasEnableBtn); +} + +void GenericMenu::insertSection(SubsectionSeparator* section) +{ + BaseMenuItem* item = new BaseMenuItem(this); + item->setWidget(section); + + m_menu->insertMenuItem(item, m_lastOpenPosition); + + m_lastOpenPosition++; +} diff --git a/src/gui/generic_menu.hpp b/src/gui/generic_menu.hpp new file mode 100644 index 0000000000..fd8fefb957 --- /dev/null +++ b/src/gui/generic_menu.hpp @@ -0,0 +1,41 @@ +#ifndef GENERICMENU_HPP +#define GENERICMENU_HPP + +#include + +#include "basemenu.h" +#include "menu_header.hpp" +#include "subsection_separator.hpp" + +using namespace adiscope; + +namespace adiscope { +namespace gui { + +class GenericMenu : public QWidget +{ + Q_OBJECT + +public: + explicit GenericMenu(QWidget* parent = nullptr); + ~GenericMenu(); + + virtual void setMenuButton(bool toggled){}; + + void initInteractiveMenu(); + void setMenuHeader(const QString& title, const QColor* lineColor, bool hasEnableBtn); + void insertSection(SubsectionSeparator* section); + +Q_SIGNALS: + void enableBtnToggled(bool toggled); + +private: + MenuHeader* m_menuHeader; + BaseMenu* m_menu; + + int m_lastOpenPosition; +}; +} // namespace gui +} // namespace scopy + +#endif // GENERICMENU_HPP diff --git a/src/homepage_controls.cpp b/src/gui/homepage_controls.cpp similarity index 100% rename from src/homepage_controls.cpp rename to src/gui/homepage_controls.cpp diff --git a/src/homepage_controls.h b/src/gui/homepage_controls.h similarity index 100% rename from src/homepage_controls.h rename to src/gui/homepage_controls.h diff --git a/src/info_page.cpp b/src/gui/info_page.cpp similarity index 96% rename from src/info_page.cpp rename to src/gui/info_page.cpp index 23d6e5511d..bc34ef75b7 100644 --- a/src/info_page.cpp +++ b/src/gui/info_page.cpp @@ -23,8 +23,9 @@ #include "preferences.h" #include #include +#include #include "libm2k/analog/dmm.hpp" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include #include #include @@ -70,6 +71,14 @@ InfoPage::InfoPage(QString uri, Preferences *pref, PhoneHome* phoneHome, setStatusLabel(ui->lblCalibrationStatus); setStatusLabel(ui->lblConnectionStatus); setStatusLabel(ui->lblIdentifyStatus); + +#ifdef __ANDROID__ + ui->btnCalibrate->setMinimumWidth(150); + ui->btnConnect->setMinimumWidth(150); + ui->btnForget->setMinimumWidth(150); + ui->btnIdentify->setMinimumWidth(150); + ui->btnRegister->setMinimumWidth(150); +#endif } void InfoPage::readPreferences() { @@ -486,7 +495,6 @@ void M2kInfoPage::getDeviceInfo() void M2kInfoPage::refreshTemperature() { - libm2k::context::M2k *temp_m2k = nullptr; if(!m_ctx) { temp_m2k = libm2k::context::m2kOpen(m_uri.toLocal8Bit().constData()); @@ -495,10 +503,15 @@ void M2kInfoPage::refreshTemperature() } if(temp_m2k) { - auto dmm = temp_m2k->getDMM("ad9963"); - auto ch = dmm->readChannel("temp0"); - auto val = ch.value; - m_info_params["Temperature"] = QString::number(val); + try { + auto dmm = temp_m2k->getDMM("ad9963"); + auto ch = dmm->readChannel("temp0"); + auto val = ch.value; + m_info_params["Temperature"] = QString::number(val); + + } catch (libm2k::m2k_exception &e) { + qDebug() << e.what(); + } } if(!m_ctx) { diff --git a/src/info_page.hpp b/src/gui/info_page.hpp similarity index 100% rename from src/info_page.hpp rename to src/gui/info_page.hpp diff --git a/src/info_widget.cpp b/src/gui/info_widget.cpp similarity index 100% rename from src/info_widget.cpp rename to src/gui/info_widget.cpp diff --git a/src/info_widget.h b/src/gui/info_widget.h similarity index 100% rename from src/info_widget.h rename to src/gui/info_widget.h diff --git a/src/instrumentnotes.cpp b/src/gui/instrumentnotes.cpp similarity index 100% rename from src/instrumentnotes.cpp rename to src/gui/instrumentnotes.cpp diff --git a/src/instrumentnotes.h b/src/gui/instrumentnotes.h similarity index 100% rename from src/instrumentnotes.h rename to src/gui/instrumentnotes.h diff --git a/src/linked_button.cpp b/src/gui/linked_button.cpp similarity index 94% rename from src/linked_button.cpp rename to src/gui/linked_button.cpp index 344884d7ef..424111f4be 100644 --- a/src/linked_button.cpp +++ b/src/gui/linked_button.cpp @@ -1,5 +1,5 @@ #include "linked_button.hpp" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include #include diff --git a/src/linked_button.hpp b/src/gui/linked_button.hpp similarity index 100% rename from src/linked_button.hpp rename to src/gui/linked_button.hpp diff --git a/src/measure.cpp b/src/gui/measure.cpp similarity index 58% rename from src/measure.cpp rename to src/gui/measure.cpp index f70d6c413a..2fa5e6316d 100644 --- a/src/measure.cpp +++ b/src/gui/measure.cpp @@ -347,10 +347,378 @@ namespace adiscope { QString m_name; }; + + class SpectralDetection { + public: + SpectralDetection(double *data, ssize_t data_length, int harmonics_number): + m_data(data), + m_data_length(data_length), + m_harmonics_number(harmonics_number) + { + } + + void calculateSpectralDetectionParameters(double &spur, double &harm_dist, double &noise, + double &average_noise, double &signal) { + struct harmonic_tuple { + double harm_value; + int harm_bin; + }; + + findHarmonics(m_harmonics_number); + + int spur_bw; + findSpur(spur, spur_bw, false, m_harmonic_bins[0]); + + if(m_mask.empty()) + m_mask = calculateAutoMask(); + int noise_bins; + maskedSumOfSquares(noise_bins, noise, m_mask); + + noise_bins = noise_bins > 1 ? noise_bins : 1; + noise = average_noise * (m_data_length - 1); + + std::map harmonic; + for(int i = 0; i < m_harmonics_number; i++) + { + struct harmonic_tuple harm; + harm.harm_bin = m_harmonic_bins[i]; + harm.harm_value = m_harmonics[i]; + harm.harm_value -= average_noise * m_harmonic_bw[i]; + harmonic[i+1] = harm; + } + + spur -= average_noise * spur_bw; + signal = harmonic[1].harm_value; + + harm_dist = harmonic[2].harm_value + harmonic[3].harm_value + + harmonic[4].harm_value + harmonic[5].harm_value; + + } + + private: + + std::vector calculateAutoMask() { + const int BANDWIDTH_DIVIDER = 80; + const int NUM_INITAL_NOISE_HARMS = 5; + + int bw = int(m_data_length / BANDWIDTH_DIVIDER); + std::vector mask; + mask.resize(m_data_length, 1); + for (int i = 0; i < NUM_INITAL_NOISE_HARMS; i++) + clearMask(mask, m_harmonic_bins[i] - bw, m_harmonic_bins[i] + bw); + mask[0] = 0; + + double noise_est; + int noise_bins; + maskedSum(noise_bins, noise_est, mask); + noise_est /= noise_bins; + + std::fill(mask.begin(), mask.end(), 1); + //clear mask la dc. + clearMask(mask, 0, 1); + int j; + int low, high; + + double sum; + + for(int i = 0; i < m_harmonic_bins.size(); i++) + { + int h = m_harmonic_bins.at(i); + if(mask[h] == 0) + continue; + j = 1; + sum = 0.0F; + for(int s = h-j; s < h-j+3; s++) + { + sum += m_data[s]; + } + sum /= 3; + while ( h - j > 0 && mask[h-j] == 1 && + sum > noise_est ) { + j++; + sum = 0.0F; + for(int s = h-j; s < h-j+3; s++) + { + sum += m_data[s]; + } + sum /= 3; + } + low = h - j + 1; + + j = 1; + sum = 0.0F; + for(int s = h+j-2; s < h+j+1; s++) + { + sum += m_data[s]; + } + sum /= 3; + while ( h + j < m_data_length && mask[h+j] == 1 && + sum > noise_est ) { + j++; + sum = 0.0F; + for(int s = h+j-2; s < h+j+1; s++) + { + sum += m_data[s]; + } + sum /= 3; + } + high = h + j - 1; + clearMask(mask, low, high); + } + + return mask; + } + + void setMask(std::vector &mask, int start, int end, int value) + { + int nyq = mask.size(); + int n = 2 * (nyq - 1); + std::vector indices; + for(int i = start; i <= end; i++) + { + int index_value = (i + n) % n; + if (index_value > nyq) + index_value = n - index_value; + indices.push_back(index_value); + } + + for(std::vector::iterator it = indices.begin(); it != indices.end(); ++it) + { + mask.at(*it) = value; + } + } + + void clearMask(std::vector &mask, int start, int end) + { + setMask(mask, start, end, 0); + } + + void maskedSubset(std::vector &indices, std::vector &new_mask, std::vector mask, int start, int end) + { + int nyq = mask.size(); + int n = 2 * (nyq - 1); + std::vector mapped_subset; + for(int i = start; i < end; i++) + { + int index_value = (i + n) % n; + if (index_value > nyq) + index_value = n - index_value; + mapped_subset.push_back(index_value); + } + + for(int i = 0; i < mapped_subset.size(); i++) + { + if(mask.at(mapped_subset.at(i)) == 1) + { + indices.push_back(mapped_subset.at(i)); + new_mask.push_back(mask.at(mapped_subset.at(i))); + } + + } + } + + void maskedSumOfSquares(int &index, double &value, std::vector mask, int start = 0, int end = 0) + { + if(end == 0 || end >= m_data_length) + end = m_data_length - 1; + + std::vector indices; + std::vector new_mask; + maskedSubset(indices, new_mask, mask, start, end); + double sum = 0; + + + for(std::vector::iterator it = indices.begin(); it != indices.end(); ++it) + { + sum = sum + (m_data[*it] * m_data[*it]); + } + + index = indices.size(); + value = sum; + } + + void maskedSum(int &index, double &value, std::vector mask, int start = 0, int end = 0) + { + if(end == 0 || end >= m_data_length) + end = m_data_length - 1; + + std::vector indices; + std::vector new_mask; + maskedSubset(indices, new_mask, mask, start, end); + double sum = 0; + + + for(std::vector::iterator it = indices.begin(); it != indices.end(); ++it) + { + sum = sum + (m_data[*it]); + } + + index = indices.size(); + value = sum; + } + + void maskedMax(int &index, double &value, std::vector mask, int start = 0, int end = 0) + { + if(end == 0) + end = m_data_length - 1; + double *data_at_index = new double[end](); + double data_at_index_size; + int i = 0; + + std::vector indices; + std::vector new_mask; + maskedSubset(indices, new_mask, mask, start, end); + + for(int i=0; i value) + { + index = i; + value = data[i]; + } + } + } + + void findHarmonics(int max_harmonics) + { + m_harmonic_bins.resize(max_harmonics); + m_harmonic_bw.resize(max_harmonics); + m_harmonics.resize(max_harmonics); + + std::fill(m_harmonic_bins.begin(), m_harmonic_bins.end(), 0); + std::fill(m_harmonic_bw.begin(), m_harmonic_bw.end(), 0); + std::fill(m_harmonics.begin(), m_harmonics.end(), 0.0); + + //find the fundamental bin (max value) from the data + int fund_bin = 0; + double max = 0; + getMax(m_data, m_data_length, fund_bin, max); + + m_harmonic_bins.at(0) = fund_bin; + + for(int h = 1; h < max_harmonics + 1; h++) + { + std::vector mask; + mask.resize(m_data_length, 0); + + int nominal_bin = h * fund_bin; + int h_2 = static_cast(h / 2); + if(h > 1) + { + setMask(mask, nominal_bin - h_2, nominal_bin + h_2, 1); + for(int i = 0; i < h - 1; i++) + { + clearMask(mask, m_harmonic_bins.at(i), m_harmonic_bins.at(i)); + } + int index; + double value; + maskedMax(index, value, mask); + m_harmonic_bins.at(h-1) = index; + } + clearMask(mask, nominal_bin - h_2, nominal_bin + h_2); + setMask(mask, m_harmonic_bins.at(h-1) - BW, m_harmonic_bins.at(h-1) + BW, 1); + for(int i = 0; i < h - 1; i++) + { + clearMask(mask, m_harmonic_bins.at(i) - BW, m_harmonic_bins.at(i) + BW); + } + double val_harm; + int val_hbws; + maskedSumOfSquares(val_hbws, val_harm, mask); + m_harmonics[h-1] = val_harm; + m_harmonic_bw[h-1] = val_hbws; + + } + + } + + void findSpur(double &spur, int& spur_bw, bool find_in_harmonics, int fund_bin) { + if(find_in_harmonics == true) { + int index = std::max_element(m_harmonics.begin() + 1, m_harmonics.end()) - m_harmonics.begin(); + spur = *std::max_element(m_harmonics.begin() + 1, m_harmonics.end()); + spur_bw = m_harmonic_bw[index + 1]; + } + else + { + findSpurInData(spur, spur_bw, fund_bin); + } + } + + void findSpurInData(double &spur, int& spur_bw, int fund_bin) { + std::vector mask; + mask.resize(m_data_length, 1); + //clear mask la dc. + clearMask(mask, 0, 1); + clearMask(mask, fund_bin - BW, fund_bin + BW); + int index = 0; + for(int i = 0; i < mask.size(); i++) + { + if(mask.at(i) == 1) + { + index = i; + break; + } + } + double max_value; + int max_index; + maskedSumOfSquares(max_index, max_value, mask, index - BW, index + BW); + max_index = index; + int masked_index = 0; + + double value; + while(index < m_data_length) + { + if(mask.at(index) == 1) + { + maskedSumOfSquares(masked_index, value, mask, index - BW, index + BW); + if(value > max_value) + { + max_value = value; + max_index = index; + } + } + index++; + } + + int spur_bin; + double spur_value; + maskedMax(spur_bin, spur_value, mask, max_index - BW, max_index + BW); + maskedSumOfSquares(spur_bw, spur, mask, spur_bin - BW, spur_bin + BW); + } + + private: + double *m_data; + ssize_t m_data_length; + + const int BW = 3; + std::vector m_harmonic_bins; + std::vector m_harmonic_bw; + std::vector m_harmonics; + int m_harmonics_number; + std::vector m_mask; + + }; } Measure::Measure(int channel, double *buffer, size_t length, - const std::function &conversion_fct): + const std::function &conversion_fct, bool isTimeDomain): m_channel(channel), m_buffer(buffer), m_buf_length(length), @@ -361,58 +729,77 @@ Measure::Measure(int channel, double *buffer, size_t length, m_histogram(nullptr), m_cross_detect(nullptr), m_gatingEnabled(false), - m_conversion_function(conversion_fct) + m_conversion_function(conversion_fct), + m_isTimeDomain(isTimeDomain), + m_harmonics_number(5) { - // Create a set of measurements - m_measurements.push_back(std::make_shared(QObject::tr("Period"), - MeasurementData::HORIZONTAL, "s", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Frequency"), - MeasurementData::HORIZONTAL, "Hz", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Min"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Max"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Peak-peak"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Mean"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Cycle Mean"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("RMS"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Cycle RMS"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("AC RMS"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Area"), - MeasurementData::VERTICAL, "Vs", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Cycle Area"), - MeasurementData::VERTICAL, "Vs", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Low"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("High"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Amplitude"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Middle"), - MeasurementData::VERTICAL, "V", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("+Over"), - MeasurementData::VERTICAL, "%", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("-Over"), - MeasurementData::VERTICAL, "%", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Rise"), - MeasurementData::HORIZONTAL, "s", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("Fall"), - MeasurementData::HORIZONTAL, "s", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("+Width"), - MeasurementData::HORIZONTAL, "s", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("-Width"), - MeasurementData::HORIZONTAL, "s", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("+Duty"), - MeasurementData::HORIZONTAL, "%", channel)); - m_measurements.push_back(std::make_shared(QObject::tr("-Duty"), - MeasurementData::HORIZONTAL, "%", channel)); + if(m_isTimeDomain) { + + // Create a set of measurements + m_measurements.push_back(std::make_shared(QObject::tr("Period"), + MeasurementData::HORIZONTAL, "s", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Frequency"), + MeasurementData::HORIZONTAL, "Hz", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Min"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Max"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Peak-peak"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Mean"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Cycle Mean"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("RMS"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Cycle RMS"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("AC RMS"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Area"), + MeasurementData::VERTICAL, "Vs", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Cycle Area"), + MeasurementData::VERTICAL, "Vs", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Low"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("High"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Amplitude"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Middle"), + MeasurementData::VERTICAL, "V", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("+Over"), + MeasurementData::VERTICAL, "%", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("-Over"), + MeasurementData::VERTICAL, "%", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Rise"), + MeasurementData::HORIZONTAL, "s", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("Fall"), + MeasurementData::HORIZONTAL, "s", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("+Width"), + MeasurementData::HORIZONTAL, "s", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("-Width"), + MeasurementData::HORIZONTAL, "s", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("+Duty"), + MeasurementData::HORIZONTAL, "%", channel)); + m_measurements.push_back(std::make_shared(QObject::tr("-Duty"), + MeasurementData::HORIZONTAL, "%", channel)); + } else { + //Spectral Measurements + m_measurements.push_back(std::make_shared("Noise_Floor", + MeasurementData::HORIZONTAL_F, "dB", channel)); + m_measurements.push_back(std::make_shared("SINAD", + MeasurementData::HORIZONTAL_F, "dB", channel)); + m_measurements.push_back(std::make_shared("SNR", + MeasurementData::HORIZONTAL_F, "dB", channel)); + m_measurements.push_back(std::make_shared("THD", + MeasurementData::HORIZONTAL_F, "dB", channel)); + m_measurements.push_back(std::make_shared("THDN", + MeasurementData::HORIZONTAL_F, "dB", channel)); + m_measurements.push_back(std::make_shared("SFDR", + MeasurementData::VERTICAL_F, "dBc", channel)); + } } @@ -486,6 +873,15 @@ void Measure::measure() if (!m_buffer || m_buf_length == 0) return; + if(m_isTimeDomain) { + measureTimeDomain(); + } else { + measureSpectral(); + } +} + +void Measure::measureTimeDomain() +{ double period; double frequency; double rise_time; @@ -803,6 +1199,36 @@ void Measure::measure() } +void Measure::measureSpectral() { + + //TODO - reconsider computation of measurements + double spur, harm_dist, noise, average_noise = 0, signal; + + SpectralDetection detection(m_buffer, m_buf_length, m_harmonics_number); + + detection.calculateSpectralDetectionParameters(spur, harm_dist, noise, average_noise, signal); + + double noise_floor, snr, thd, thdn, sinad, sfdr; + noise_floor = 10 * log10(average_noise / signal); + m_measurements[NOISE_FLOOR]->setValue(noise_floor); + + snr = 10 * log10(signal / noise); + m_measurements[SNR]->setValue(snr); + + thd = harm_dist > 0 ? 10 * log10(harm_dist / signal) : 0; + m_measurements[THD]->setValue(thd); + + sinad = 10 * log10(signal / (harm_dist + noise)); + m_measurements[SINAD]->setValue(sinad); + + thdn = harm_dist > 0 ? 10 * log10((harm_dist + noise) / signal) : 0; + m_measurements[THDN]->setValue(thdn); + + sfdr = spur > 0 ? 10 * log10(signal / spur) : 0; + m_measurements[SFDR]->setValue(sfdr); +} + + double Measure::sampleRate() { return m_sample_rate; @@ -872,6 +1298,31 @@ void Measure::setGatingEnabled(bool enable){ m_gatingEnabled = enable; } +std::vector Measure::LoadMaskfromFile(std::string file_name) +{ + std::vector mask; + std::ifstream mask_file(file_name.c_str()); + if(!mask_file.is_open()) throw std::runtime_error("Could not open freq file"); + + std::string line = ""; + while(std::getline(mask_file, line)) { + + int val = std::atoi(line.c_str()); + mask.push_back(val); + } + return mask; +} + +void Measure::setHarmonicNumber(int harmonics_number) +{ + m_harmonics_number = harmonics_number; +} + +void Measure::setMask(std::vector mask) +{ + std::vector m_mask = mask; +} + QList> Measure::measurments() { return m_measurements; @@ -914,6 +1365,10 @@ MeasurementData::MeasurementData(const QString& name, axisType axis, m_unitType = PERCENTAGE; else if (unit.toLower() == "s" || unit.toLower() == "seconds") m_unitType = TIME; + else if ((unit.toLower() == "db" || unit.toLower() == "decibels")) + m_unitType = DECIBELS; + else if ((unit.toLower() == "dbc" || unit.toLower() == "decibels_to_carrier")) + m_unitType = DECIBELS_TO_CARRIER; else m_unitType = METRIC; } diff --git a/src/measure.h b/src/gui/measure.h similarity index 86% rename from src/measure.h rename to src/gui/measure.h index 0fc3480eb0..2882eca52a 100644 --- a/src/measure.h +++ b/src/gui/measure.h @@ -35,12 +35,16 @@ namespace adiscope { METRIC, TIME, PERCENTAGE, - DIMENSIONLESS + DIMENSIONLESS, + DECIBELS, + DECIBELS_TO_CARRIER }; enum axisType { HORIZONTAL, - VERTICAL + VERTICAL, + HORIZONTAL_F, + VERTICAL_F }; MeasurementData(const QString& name, axisType axis, @@ -101,11 +105,25 @@ namespace adiscope { DEFAULT_MEASUREMENT_COUNT }; + enum defaultSpectralMeasurements { + NOISE_FLOOR = 0, + SINAD, + SNR, + THD, + THDN, + SFDR, + DEFAULT_SPECTRAL_MEASUREMENT_COUNT + }; + Measure(int channel, double *buffer = NULL, size_t length = 0, - const std::function &conversion = nullptr); + const std::function &conversion = nullptr, bool isTimeDomain = true); void setDataSource(double *buffer, size_t length); void measure(); + + void measureTimeDomain(); + void measureSpectral(); + double sampleRate(); void setSampleRate(double); unsigned int adcBitCount(); @@ -120,11 +138,17 @@ namespace adiscope { void setEndIndex(int); void setGatingEnabled(bool); + void setHarmonicNumber(int harmonics_number); + void setMask(std::vector mask); + QList> measurments(); std::shared_ptr measurement(int id); int activeMeasurementsCount() const; void setConversionFunction(const std::function &fp); + + std::vector LoadMaskfromFile(std::string file_name); + private: bool highLowFromHistogram(double &low, double &high, double min, double max); @@ -144,6 +168,10 @@ namespace adiscope { int *m_histogram; CrossingDetection *m_cross_detect; + int m_harmonics_number; + std::vector m_mask; + bool m_isTimeDomain; + QList> m_measurements; std::function m_conversion_function; }; diff --git a/src/measure_settings.cpp b/src/gui/measure_settings.cpp similarity index 63% rename from src/measure_settings.cpp rename to src/gui/measure_settings.cpp index 588eafbf0d..88c7d7b9ce 100644 --- a/src/measure_settings.cpp +++ b/src/gui/measure_settings.cpp @@ -19,7 +19,7 @@ */ #include "measure_settings.h" #include "oscilloscope_plot.hpp" -#include "dropdown_switch_list.h" +#include "gui/dropdown_switch_list.h" #include "ui_measure_settings.h" #include @@ -55,25 +55,41 @@ static const std::map icons_lut = { {Measure::N_DUTY, "://icons/measurements/n_duty.svg"}, }; -MeasureSettings::MeasureSettings(CapturePlot *plot, QWidget *parent) : - QWidget(parent), - m_ui(new Ui::MeasureSettings), - m_channelName(""), - m_chnUnderlineColor(), - m_horizMeasurements(new DropdownSwitchList(2, this)), - m_vertMeasurements(new DropdownSwitchList(2, this)), - m_emitActivated(true), - m_emitStatsChanged(true), - m_emitStatsDeleteAll(true), - m_emitDeleteAll(true), - m_are_dropdowns_filled(false), - m_plot(plot), - m_selectedChannel(-1), - m_enableDisplayAll(false) -{ - QTreeView *treeView; - - m_ui->setupUi(this); +static const std::map icons_spect = { + {Measure::NOISE_FLOOR, "://icons/measurements/period.svg"}, + {Measure::SINAD, "://icons/measurements/frequency.svg"}, + {Measure::SNR, "://icons/measurements/frequency.svg"}, + {Measure::THD, "://icons/measurements/frequency.svg"}, + {Measure::THDN, "://icons/measurements/frequency.svg"}, + {Measure::SFDR, "://icons/measurements/frequency.svg"}, +}; + +MeasureSettings::MeasureSettings( QList* measures_list, QWidget *parent, bool is_time_domain) : + QWidget(parent), + m_ui(new Ui::MeasureSettings), + m_channelName(""), + m_chnUnderlineColor(), + m_horizMeasurements(nullptr), + m_vertMeasurements(nullptr), + m_is_time_domain(is_time_domain), + m_emitActivated(true), + m_emitStatsChanged(true), + m_emitStatsDeleteAll(true), + m_emitDeleteAll(true), + m_are_dropdowns_filled(false), + m_measures_list(measures_list), + m_selectedChannel(-1), + m_enableDisplayAll(false) +{ + QTreeView *treeView; + + m_ui->setupUi(this); + hide_measure_settings(m_is_time_domain); + + if(m_is_time_domain) + { + m_horizMeasurements = new DropdownSwitchList(2, this); + m_vertMeasurements = new DropdownSwitchList(2, this); m_ui->hLayout_hMeasurements->addWidget(m_horizMeasurements); m_ui->hLayout_vMeasurements->addWidget(m_vertMeasurements); @@ -87,8 +103,8 @@ MeasureSettings::MeasureSettings(CapturePlot *plot, QWidget *parent) : treeView->setIconSize(QSize(30, 20)); connect(m_horizMeasurements->model(), - SIGNAL(itemChanged(QStandardItem*)), - SLOT(onMeasurementPropertyChanged(QStandardItem*))); + SIGNAL(itemChanged(QStandardItem*)), + SLOT(onMeasurementPropertyChanged(QStandardItem*))); m_vertMeasurements->setTitle(tr("Vertical")); m_vertMeasurements->setColumnTitle(0, tr("Name")); @@ -100,8 +116,45 @@ MeasureSettings::MeasureSettings(CapturePlot *plot, QWidget *parent) : treeView->setIconSize(QSize(30, 20)); connect(m_vertMeasurements->model(), - SIGNAL(itemChanged(QStandardItem*)), - SLOT(onMeasurementPropertyChanged(QStandardItem*))); + SIGNAL(itemChanged(QStandardItem*)), + SLOT(onMeasurementPropertyChanged(QStandardItem*))); + } + else + { + m_horizMeasurements = new DropdownSwitchList(1, this); + m_vertMeasurements = new DropdownSwitchList(1, this); + + connect(m_ui->comboBox_harm, SIGNAL(currentIndexChanged(int)), + SLOT(onharmValueChanged(int))); + + m_ui->hLayout_hMeasurements->addWidget(m_horizMeasurements); + m_ui->hLayout_vMeasurements->addWidget(m_vertMeasurements); + + m_horizMeasurements->setTitle(tr("Horizontals")); + m_horizMeasurements->setColumnTitle(0, tr("Name")); + m_horizMeasurements->setColumnTitle(1, tr("Measure")); + m_horizMeasurements->setMaxVisibleItems(4); + treeView = static_cast(m_horizMeasurements->view()); + treeView->header()->resizeSection(0, 150); + treeView->setIconSize(QSize(30, 20)); + + connect(m_horizMeasurements->model(), + SIGNAL(itemChanged(QStandardItem*)), + SLOT(onMeasurementPropertyChanged(QStandardItem*))); + + m_vertMeasurements->setTitle(tr("Verticals")); + m_vertMeasurements->setColumnTitle(0, tr("Name")); + m_vertMeasurements->setColumnTitle(1, tr("Measure")); + + m_vertMeasurements->setMaxVisibleItems(4); + treeView = static_cast(m_vertMeasurements->view()); + treeView->header()->resizeSection(0, 150); + treeView->setIconSize(QSize(30, 20)); + + connect(m_vertMeasurements->model(), + SIGNAL(itemChanged(QStandardItem*)), + SLOT(onMeasurementPropertyChanged(QStandardItem*))); + } } MeasureSettings::~MeasureSettings() @@ -109,6 +162,50 @@ MeasureSettings::~MeasureSettings() delete m_ui; } +void MeasureSettings::onharmValueChanged(int id) +{ + Measure *measure = measureOfChannel(m_selectedChannel); + measure->setHarmonicNumber(id + 1); +} + +void MeasureSettings::hide_measure_settings(bool is_time_domain) { + if(is_time_domain) + { + m_ui->comboBox_harm->hide(); + m_ui->label_9->hide(); + m_ui->line_6->hide(); + m_ui->label_10->hide(); + } + else + { + m_ui->label_7->hide(); + m_ui->line_3->hide(); + m_ui->verticalSpacer_6->changeSize(0,0); + m_ui->verticalSpacer_7->changeSize(0,0); + + m_ui->button_StatisticsEn->hide(); + m_ui->button_statsDeleteAll->hide(); + m_ui->button_StatisticsReset->hide(); + + m_ui->button_GatingEnable->hide(); + m_ui->label_4->hide(); + m_ui->label_5->hide(); + m_ui->line_5->hide(); + + m_ui->comboBox_harm->addItem("1"); + m_ui->comboBox_harm->addItem("2"); + m_ui->comboBox_harm->addItem("3"); + m_ui->comboBox_harm->addItem("4"); + m_ui->comboBox_harm->addItem("5"); + m_ui->comboBox_harm->addItem("6"); + m_ui->comboBox_harm->addItem("7"); + m_ui->comboBox_harm->addItem("8"); + m_ui->comboBox_harm->addItem("9"); + + m_ui->comboBox_harm->setCurrentIndex(6); + } +} + QString MeasureSettings::channelName() const { return m_channelName; @@ -224,34 +321,68 @@ void MeasureSettings::on_button_measDeleteAll_toggled(bool checked) } } +Measure* MeasureSettings::measureOfChannel(int chnIdx) const +{ + Measure *measure = nullptr; + + auto it = std::find_if(m_measures_list->begin(), m_measures_list->end(), + [&](Measure *m) { return m->channel() == chnIdx; }); + if (it != m_measures_list->end()) + measure = *it; + + return measure; +} + void MeasureSettings::onChannelAdded(int chnIdx) { - // Use the measurements of the 1st channel to construct the dropdowns. - // All channels have the same set of measurements. - if (m_are_dropdowns_filled) - return; + // Use the measurements of the 1st channel to construct the dropdowns. + // All channels have the same set of measurements. + if (m_are_dropdowns_filled) + return; - auto measurements = m_plot->measurements(chnIdx); - int h = 0; - int v = 0; + Measure *measure = measureOfChannel(chnIdx); + auto measurements = QList>(); + if (measure) + measurements = measure->measurments(); + int h = 0; + int v = 0; + if(m_is_time_domain) + { for (int i = 0; i < measurements.size(); i++) { - enum MeasurementData::axisType axis = measurements[i]->axis(); - - if (axis == MeasurementData::HORIZONTAL) { - m_horizMeasurements->addDropdownElement( - QIcon(icons_lut.at(i)), - measurements[i]->name(), QVariant(i)); - m_measurePosInDropdowns.append(h++); - } else if (axis == MeasurementData::VERTICAL) { - m_vertMeasurements->addDropdownElement( - QIcon(icons_lut.at(i)), - measurements[i]->name(), QVariant(i)); - m_measurePosInDropdowns.append(v++); - } + enum MeasurementData::axisType axis = measurements[i]->axis(); + + if (axis == MeasurementData::HORIZONTAL) { + m_horizMeasurements->addDropdownElement( + QIcon(icons_lut.at(i)), + measurements[i]->name(), QVariant(i)); + m_measurePosInDropdowns.append(h++); + } else if (axis == MeasurementData::VERTICAL) { + m_vertMeasurements->addDropdownElement( + QIcon(icons_lut.at(i)), + measurements[i]->name(), QVariant(i)); + m_measurePosInDropdowns.append(v++); + } } + } + else + { + for (int i = 0; i < measurements.size(); i++) { + enum MeasurementData::axisType axis = measurements[i]->axis(); + + if (axis == MeasurementData::HORIZONTAL_F) { + m_horizMeasurements->addDropdownElement( + QIcon(icons_spect.at(i)), + measurements[i]->name(), QVariant(i)); + } else if (axis == MeasurementData::VERTICAL_F) { + m_vertMeasurements->addDropdownElement( + QIcon(icons_spect.at(i)), + measurements[i]->name(), QVariant(i)); + } + } + } - m_are_dropdowns_filled = true; + m_are_dropdowns_filled = true; } void MeasureSettings::onChannelRemoved(int chnIdx) @@ -284,31 +415,53 @@ void MeasureSettings::setSelectedChannel(int chnIdx) void MeasureSettings::loadMeasurementStatesFromData() { - auto measurements = m_plot->measurements(m_selectedChannel); - int h_idx = 0; - int v_idx = 0; + Measure *measure = measureOfChannel(m_selectedChannel); + auto measurements = QList>(); + if (measure) + measurements = measure->measurments(); + + int h_idx = 0; + int v_idx = 0; - QStandardItemModel *horiz_model = + QStandardItemModel *horiz_model = static_cast(m_horizMeasurements->model()); - QStandardItemModel *vert_model = + QStandardItemModel *vert_model = static_cast(m_vertMeasurements->model()); - setEmitActivated(false); + setEmitActivated(false); - for (int i = 0; i < measurements.size(); i++) { - int axis = measurements[i]->axis(); - int state = measurements[i]->enabled(); + if(m_is_time_domain) + { + for (int i = 0; i < measurements.size(); i++) { + int axis = measurements[i]->axis(); + int state = measurements[i]->enabled(); - if (axis == MeasurementData::HORIZONTAL) { + if (axis == MeasurementData::HORIZONTAL) { horiz_model->item(h_idx++, 1)->setData( - QVariant((int) state), Qt::EditRole); - } else if (axis == MeasurementData::VERTICAL) { + QVariant((int) state), Qt::EditRole); + } else if (axis == MeasurementData::VERTICAL) { vert_model->item(v_idx++, 1)->setData( - QVariant((int) state), Qt::EditRole); + QVariant((int) state), Qt::EditRole); + } } - } + } + else + { + for (int i = 0; i < measurements.size(); i++) { + enum MeasurementData::axisType axis = measurements[i]->axis(); + int state = measurements[i]->enabled(); + + if (axis == MeasurementData::HORIZONTAL_F) { + horiz_model->item(h_idx++, 1)->setData( + QVariant((int) state), Qt::EditRole); + } else if (axis == MeasurementData::VERTICAL_F) { + vert_model->item(v_idx++, 1)->setData( + QVariant((int) state), Qt::EditRole); + } + } + } - setEmitActivated(true); + setEmitActivated(true); } void MeasureSettings::deleteAllMeasurements() @@ -331,7 +484,12 @@ void MeasureSettings::displayAllMeasurements() { m_displayAllBackup = m_selectedMeasurements; m_selectedMeasurements.clear(); - auto measurements = m_plot->measurements(m_selectedChannel); + + Measure *measure = measureOfChannel(m_selectedChannel); + auto measurements = QList>(); + if (measure) + measurements = measure->measurments(); + for (int i = 0; i < measurements.size(); i++) { MeasurementItem item(i, measurements[i]->channel()); m_selectedMeasurements.push_back(MeasurementItem(item)); @@ -352,7 +510,11 @@ void MeasureSettings::onMeasurementActivated(int chnIdx, int id, bool en) if (chnIdx < 0) return; - auto measurements = m_plot->measurements(chnIdx); + Measure *measure = measureOfChannel(chnIdx); + auto measurements = QList>(); + if (measure) + measurements = measure->measurments(); + MeasurementItem mItem(id, measurements[id]->channel()); if (en) { m_selectedMeasurements.push_back(mItem); @@ -380,28 +542,31 @@ void MeasureSettings::onStatisticActivated(DropdownSwitchList *dropdown, void MeasureSettings::loadStatisticStatesForChannel(int chnIdx) { - const int stats_col = 2; + // makes sense only for the oscilloscope + if (m_is_time_domain) { + const int stats_col = 2; - setEmitStatsChanged(false); + setEmitStatsChanged(false); - // Start with all selections cleared - setAllMeasurements(stats_col, false); + // Start with all selections cleared + setAllMeasurements(stats_col, false); - // Restore selections that are present in the selected statistics list - for (int i = 0; i < m_selectedStatistics.size(); i++) { - if (m_selectedStatistics[i].measurementItem.channel_id() != - chnIdx) { - continue; - } - QStandardItemModel *model = static_cast - (m_selectedStatistics[i].dropdown->model()); + // Restore selections that are present in the selected statistics list + for (int i = 0; i < m_selectedStatistics.size(); i++) { + if (m_selectedStatistics[i].measurementItem.channel_id() != + chnIdx) { + continue; + } + QStandardItemModel *model = static_cast + (m_selectedStatistics[i].dropdown->model()); - int measId = m_selectedStatistics[i].measurementItem.id(); + int measId = m_selectedStatistics[i].measurementItem.id(); - model->item(m_measurePosInDropdowns[measId], stats_col)-> - setData(QVariant(1), Qt::EditRole); + model->item(m_measurePosInDropdowns[measId], stats_col)-> + setData(QVariant(1), Qt::EditRole); + } + setEmitStatsChanged(true); } - setEmitStatsChanged(true); } void MeasureSettings::on_button_StatisticsEn_toggled(bool checked) @@ -544,7 +709,11 @@ void MeasureSettings::recoverAllStatistics() void MeasureSettings::addStatistic(int measure_id, int ch_id) { - auto measurements = m_plot->measurements(ch_id); + Measure *measure = measureOfChannel(ch_id); + auto measurements = QList>(); + if (measure) + measurements = measure->measurments(); + MeasurementData::axisType axis = measurements[measure_id]->axis(); struct StatisticSelection selection; diff --git a/src/measure_settings.h b/src/gui/measure_settings.h similarity index 92% rename from src/measure_settings.h rename to src/gui/measure_settings.h index 43199e704d..5253b9ba10 100644 --- a/src/measure_settings.h +++ b/src/gui/measure_settings.h @@ -22,6 +22,7 @@ #include #include +#include "measure.h" namespace Ui { class MeasureSettings; @@ -72,11 +73,12 @@ struct StatisticSelection { class MeasureSettings : public QWidget { friend class Oscilloscope_API; + friend class SpectrumAnalyzer_API; Q_OBJECT public: - explicit MeasureSettings(CapturePlot *plot, QWidget *parent = 0); + explicit MeasureSettings(QList* measures_list, QWidget *parent = 0, bool is_time_domain = true); ~MeasureSettings(); QString channelName() const; @@ -119,6 +121,7 @@ public Q_SLOTS: void onChannelRemoved(int); void setSelectedChannel(int); void onMeasurementActivated(int chnIdx, int id, bool en); + void onharmValueChanged(int id); private Q_SLOTS: void onMeasurementPropertyChanged(QStandardItem *item); void on_button_measDisplayAll_toggled(bool checked); @@ -131,7 +134,9 @@ private Q_SLOTS: void on_button_GatingEnable_toggled(bool checked); private: + void hide_measure_settings(bool is_time_domain); void deleteAllMeasurements(); + Measure* measureOfChannel(int chnIdx) const; void recoverAllMeasurements(); void displayAllMeasurements(); void disableDisplayAllMeasurements(); @@ -161,8 +166,10 @@ private Q_SLOTS: bool m_emitStatsDeleteAll; bool m_are_dropdowns_filled; bool m_enableDisplayAll; + bool m_is_time_domain; + + QList* m_measures_list; - CapturePlot* m_plot; int m_selectedChannel; QList m_selectedMeasurements; QList m_deleteAllBackup; diff --git a/src/menu_anim.cpp b/src/gui/menu_anim.cpp similarity index 81% rename from src/menu_anim.cpp rename to src/gui/menu_anim.cpp index 27b5b603f2..b64b15e41e 100644 --- a/src/menu_anim.cpp +++ b/src/gui/menu_anim.cpp @@ -31,18 +31,19 @@ MenuAnim::MenuAnim(QWidget *parent) : ColoredQWidget(parent), close_anim_max(this, "maximumWidth"), close_anim_min(this, "minimumWidth"), min_width(-1), - animInProg(false) + animInProg(false), + animationDuration(200) { - open_anim_max.setDuration(500); + open_anim_max.setDuration(animationDuration); open_anim_max.setEasingCurve(QEasingCurve::InOutExpo); - open_anim_min.setDuration(500); + open_anim_min.setDuration(animationDuration); open_anim_min.setEasingCurve(QEasingCurve::InOutExpo); - close_anim_max.setDuration(500); + close_anim_max.setDuration(animationDuration); close_anim_max.setEasingCurve(QEasingCurve::InOutExpo); - close_anim_min.setDuration(500); + close_anim_min.setDuration(animationDuration); close_anim_min.setEasingCurve(QEasingCurve::InOutExpo); connect(&open_anim_max, SIGNAL(finished()), @@ -116,3 +117,17 @@ void MenuAnim::openAnimFinished() animInProg = false; Q_EMIT finished(true); } + +int MenuAnim::getAnimationDuration() const +{ + return animationDuration; +} + +void MenuAnim::setAnimationDuration(int newAnimationDuration) +{ + animationDuration = newAnimationDuration; + open_anim_max.setDuration(animationDuration); + open_anim_min.setDuration(animationDuration); + close_anim_max.setDuration(animationDuration); + close_anim_min.setDuration(animationDuration); +} diff --git a/src/menu_anim.hpp b/src/gui/menu_anim.hpp similarity index 88% rename from src/menu_anim.hpp rename to src/gui/menu_anim.hpp index 6b5e3f2adf..c4c72941be 100644 --- a/src/menu_anim.hpp +++ b/src/gui/menu_anim.hpp @@ -21,9 +21,9 @@ #ifndef MENU_ANIM_HPP #define MENU_ANIM_HPP -#include "coloredQWidget.hpp" +#include "gui/coloredQWidget.hpp" -#include "customanimation.h" +#include "gui/customanimation.h" #include #include @@ -39,6 +39,9 @@ namespace adiscope { void setMinimumSize(QSize size); bool animInProgress() const; + int getAnimationDuration() const; + void setAnimationDuration(int newAnimationDuration); + Q_SIGNALS: void finished(bool opened); @@ -53,6 +56,7 @@ namespace adiscope { CustomAnimation close_anim_max, close_anim_min, open_anim_max, open_anim_min; int min_width; + int animationDuration; bool animInProg; }; } diff --git a/src/gui/menu_header.cpp b/src/gui/menu_header.cpp new file mode 100644 index 0000000000..20d3e61464 --- /dev/null +++ b/src/gui/menu_header.cpp @@ -0,0 +1,40 @@ +#include "ui_menu_header.h" + +#include +#include + +#include "menu_header.hpp" + +using namespace adiscope::gui; + +MenuHeader::MenuHeader(QWidget* parent) + : QWidget(parent) + , m_ui(new Ui::MenuHeader) +{ + m_ui->setupUi(this); + + this->setEnableBtnVisible(false); +} + +MenuHeader::MenuHeader(const QString& label, const QColor* color, bool enableBtnVisible, QWidget* parent) + : MenuHeader(parent) +{ + this->setLabel(label); + this->setLineColor(color); + this->setEnableBtnVisible(enableBtnVisible); +} + +MenuHeader::~MenuHeader() { delete m_ui; } + +void MenuHeader::setEnabledBtnState(bool state) { m_ui->btnEnabled->setChecked(state); } + +void MenuHeader::setLabel(const QString& text) { m_ui->lblTitle->setText(text); } + +void MenuHeader::setLineColor(const QColor* color) +{ + m_ui->lineSeparator->setStyleSheet("border: 2px solid " + color->name()); +} + +void MenuHeader::setEnableBtnVisible(bool visible) { m_ui->btnEnabled->setVisible(visible); } + +QPushButton* MenuHeader::getEnableBtn() { return m_ui->btnEnabled; } diff --git a/src/gui/menu_header.hpp b/src/gui/menu_header.hpp new file mode 100644 index 0000000000..ffe3fee2e0 --- /dev/null +++ b/src/gui/menu_header.hpp @@ -0,0 +1,43 @@ +#ifndef MENU_HEADER_HPP +#define MENU_HEADER_HPP + +#include +#include + +namespace Ui { +class MenuHeader; +} + +namespace adiscope { +namespace gui { + +class MenuHeader : public QWidget +{ + Q_OBJECT + +public: + explicit MenuHeader(QWidget* parent = nullptr); + explicit MenuHeader(const QString& label = nullptr, const QColor* color = new QColor("#4A64FF"), + bool enableBtnVisible = false, QWidget* parent = nullptr); + ~MenuHeader(); + +private: + Ui::MenuHeader* m_ui; + +public Q_SLOTS: + void setEnabledBtnState(bool state); + +Q_SIGNALS: + void enableBtnToggled(bool state); + +public: + void setLabel(const QString& text); + void setLineColor(const QColor* color); + void setEnableBtnVisible(bool visible); + + QPushButton* getEnableBtn(); +}; +} // namespace gui +} // namespace scopy + +#endif // MENU_HEADER_HPP diff --git a/src/osc_custom_scroll.cpp b/src/gui/osc_custom_scroll.cpp similarity index 100% rename from src/osc_custom_scroll.cpp rename to src/gui/osc_custom_scroll.cpp diff --git a/src/osc_custom_scroll.h b/src/gui/osc_custom_scroll.h similarity index 100% rename from src/osc_custom_scroll.h rename to src/gui/osc_custom_scroll.h diff --git a/src/osc_export_settings.cpp b/src/gui/osc_export_settings.cpp similarity index 100% rename from src/osc_export_settings.cpp rename to src/gui/osc_export_settings.cpp diff --git a/src/osc_export_settings.h b/src/gui/osc_export_settings.h similarity index 97% rename from src/osc_export_settings.h rename to src/gui/osc_export_settings.h index 6e470aa56d..fd5a4476d7 100644 --- a/src/osc_export_settings.h +++ b/src/gui/osc_export_settings.h @@ -28,7 +28,7 @@ #include /* Local includes */ -#include "dropdown_switch_list.h" +#include "gui/dropdown_switch_list.h" namespace Ui { class ExportSettings; diff --git a/src/osc_import_settings.cpp b/src/gui/osc_import_settings.cpp similarity index 100% rename from src/osc_import_settings.cpp rename to src/gui/osc_import_settings.cpp diff --git a/src/osc_import_settings.h b/src/gui/osc_import_settings.h similarity index 100% rename from src/osc_import_settings.h rename to src/gui/osc_import_settings.h diff --git a/src/registerwidget.cpp b/src/gui/registerwidget.cpp similarity index 100% rename from src/registerwidget.cpp rename to src/gui/registerwidget.cpp diff --git a/src/registerwidget.h b/src/gui/registerwidget.h similarity index 98% rename from src/registerwidget.h rename to src/gui/registerwidget.h index 8f2a4e015f..caf2a8e0cd 100644 --- a/src/registerwidget.h +++ b/src/gui/registerwidget.h @@ -25,7 +25,7 @@ #include #include "regmapparser.h" -#include "bitfieldwidget.h" +#include "gui/bitfieldwidget.h" #include "debug.h" namespace Ui { diff --git a/src/runsinglewidget.cpp b/src/gui/runsinglewidget.cpp similarity index 94% rename from src/runsinglewidget.cpp rename to src/gui/runsinglewidget.cpp index 6178672001..df51ead675 100644 --- a/src/runsinglewidget.cpp +++ b/src/gui/runsinglewidget.cpp @@ -22,8 +22,8 @@ #include "ui_runsinglewidget.h" #include "utils.h" -#include "dynamicWidget.hpp" -#include "customPushButton.hpp" +#include "gui/dynamicWidget.hpp" +#include "gui/customPushButton.hpp" using namespace adiscope; @@ -84,6 +84,10 @@ bool RunSingleWidget::runButtonChecked() const return d_ui->runButton->isChecked(); } +QPushButton* RunSingleWidget::getRunButton() { return d_ui->runButton; } + +QPushButton* RunSingleWidget::getSingleButton() { return d_ui->singleButton; } + void RunSingleWidget::toggle(bool checked) { if (!checked) { diff --git a/src/runsinglewidget.h b/src/gui/runsinglewidget.h similarity index 94% rename from src/runsinglewidget.h rename to src/gui/runsinglewidget.h index b0cf92eae0..7cedef11b3 100644 --- a/src/runsinglewidget.h +++ b/src/gui/runsinglewidget.h @@ -21,6 +21,7 @@ #ifndef RUNSINGLEWIDGET_H #define RUNSINGLEWIDGET_H +#include #include namespace Ui { @@ -45,6 +46,9 @@ class RunSingleWidget : public QWidget bool singleButtonChecked() const; bool runButtonChecked() const; + QPushButton* getRunButton(); + QPushButton* getSingleButton(); + public Q_SLOTS: void toggle(bool); void single(); diff --git a/src/gui/settings_pair_widget.cpp b/src/gui/settings_pair_widget.cpp new file mode 100644 index 0000000000..e39e86e31f --- /dev/null +++ b/src/gui/settings_pair_widget.cpp @@ -0,0 +1,18 @@ +#include "ui_settings_pair_widget.h" + +#include "settings_pair_widget.hpp" + +using namespace adiscope::gui; + +SettingsPairWidget::SettingsPairWidget(QWidget* parent) + : QWidget(parent) + , m_ui(new Ui::SettingsPairWidget) +{ + m_ui->setupUi(this); +} + +SettingsPairWidget::~SettingsPairWidget() { delete m_ui; } + +CustomPushButton* SettingsPairWidget::getGeneralSettingsBtn() { return m_ui->btnGenSettings; } + +QPushButton* SettingsPairWidget::getSettingsBtn() { return m_ui->btnSettings; } diff --git a/src/gui/settings_pair_widget.hpp b/src/gui/settings_pair_widget.hpp new file mode 100644 index 0000000000..de3dc90cf2 --- /dev/null +++ b/src/gui/settings_pair_widget.hpp @@ -0,0 +1,34 @@ +#ifndef SETTINGSCUSTOMWIDGET_H +#define SETTINGSCUSTOMWIDGET_H + +#include +#include + +#include "customPushButton.hpp" + +using namespace adiscope; + +namespace Ui { +class SettingsPairWidget; +} + +namespace adiscope { +namespace gui { +class SettingsPairWidget : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsPairWidget(QWidget* parent = nullptr); + ~SettingsPairWidget(); + + CustomPushButton* getGeneralSettingsBtn(); + QPushButton* getSettingsBtn(); + +private: + Ui::SettingsPairWidget* m_ui; +}; +} // namespace gui +} // namespace scopy + +#endif // SETTINGSPAIRWIDGET_H diff --git a/src/smallOnOffSwitch.cpp b/src/gui/smallOnOffSwitch.cpp similarity index 99% rename from src/smallOnOffSwitch.cpp rename to src/gui/smallOnOffSwitch.cpp index ac993cee20..9d3692b280 100644 --- a/src/smallOnOffSwitch.cpp +++ b/src/gui/smallOnOffSwitch.cpp @@ -19,7 +19,7 @@ */ #include "smallOnOffSwitch.hpp" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include #include diff --git a/src/smallOnOffSwitch.hpp b/src/gui/smallOnOffSwitch.hpp similarity index 98% rename from src/smallOnOffSwitch.hpp rename to src/gui/smallOnOffSwitch.hpp index 1ea0cbc088..1338603d4f 100644 --- a/src/smallOnOffSwitch.hpp +++ b/src/gui/smallOnOffSwitch.hpp @@ -22,7 +22,7 @@ #define SMALL_ON_OFF_SWITCH_HPP #include -#include "customanimation.h" +#include "gui/customanimation.h" #include #include #include diff --git a/src/spinbox_a.cpp b/src/gui/spinbox_a.cpp similarity index 99% rename from src/spinbox_a.cpp rename to src/gui/spinbox_a.cpp index 307f6324e4..f4ff7d4d56 100644 --- a/src/spinbox_a.cpp +++ b/src/gui/spinbox_a.cpp @@ -19,7 +19,7 @@ */ #include "spinbox_a.hpp" -#include "completion_circle.h" +#include "gui/completion_circle.h" #include "apiobjectmanager.h" #include "singletone_wrapper.h" diff --git a/src/spinbox_a.hpp b/src/gui/spinbox_a.hpp similarity index 100% rename from src/spinbox_a.hpp rename to src/gui/spinbox_a.hpp diff --git a/src/stacked_homepage.cpp b/src/gui/stacked_homepage.cpp similarity index 99% rename from src/stacked_homepage.cpp rename to src/gui/stacked_homepage.cpp index 1bb4aeef62..b8a86b0e2c 100644 --- a/src/stacked_homepage.cpp +++ b/src/gui/stacked_homepage.cpp @@ -21,7 +21,7 @@ #include "stacked_homepage.h" #include -#include "customanimation.h" +#include "gui/customanimation.h" #include #include #include @@ -36,7 +36,7 @@ StackedHomepage::StackedHomepage(QWidget *parent) : connect(s_hc, &HomepageControls::goRight, this, &StackedHomepage::moveRight); connect(s_hc, &HomepageControls::openFile, this, &StackedHomepage::openFile); - s_speed = 500; + s_speed = 200; s_animationType = QEasingCurve::InOutCubic; s_wrap = false; s_active = false; diff --git a/src/stacked_homepage.h b/src/gui/stacked_homepage.h similarity index 98% rename from src/stacked_homepage.h rename to src/gui/stacked_homepage.h index ad3ddc7a75..060a1736d3 100644 --- a/src/stacked_homepage.h +++ b/src/gui/stacked_homepage.h @@ -25,7 +25,7 @@ #include #include -#include "homepage_controls.h" +#include "gui/homepage_controls.h" namespace Ui { class StackedHomepage; diff --git a/src/startstoprangewidget.cpp b/src/gui/startstoprangewidget.cpp similarity index 100% rename from src/startstoprangewidget.cpp rename to src/gui/startstoprangewidget.cpp diff --git a/src/startstoprangewidget.h b/src/gui/startstoprangewidget.h similarity index 100% rename from src/startstoprangewidget.h rename to src/gui/startstoprangewidget.h diff --git a/src/gui/subsection_separator.cpp b/src/gui/subsection_separator.cpp new file mode 100644 index 0000000000..dcf3fff9c2 --- /dev/null +++ b/src/gui/subsection_separator.cpp @@ -0,0 +1,48 @@ +#include "ui_subsection_separator.h" + +#include + +#include "subsection_separator.hpp" + +using namespace adiscope::gui; + +SubsectionSeparator::SubsectionSeparator(QWidget* parent) + : QWidget(parent) + , m_ui(new Ui::SubsectionSeparator) +{ + m_ui->setupUi(this); + + m_ui->widgetSubsectionContent->setVisible(false); + connect(m_ui->btnSubsectionSeparator, &QPushButton::toggled, + [=](bool toggled) { m_ui->widgetSubsectionContent->setVisible(toggled); }); +} + +SubsectionSeparator::SubsectionSeparator(const QString& text, const bool buttonVisible, QWidget* parent) + : SubsectionSeparator(parent) +{ + setLabel(text); + setButtonVisible(buttonVisible); +} + +SubsectionSeparator::~SubsectionSeparator() { delete m_ui; } + +QPushButton* SubsectionSeparator::getButton() { return m_ui->btnSubsectionSeparator; } + +void SubsectionSeparator::setButtonVisible(bool buttonVisible) +{ + m_ui->btnSubsectionSeparator->setVisible(buttonVisible); +} + +bool SubsectionSeparator::getButtonChecked() { return m_ui->btnSubsectionSeparator->isChecked(); } + +void SubsectionSeparator::setButtonChecked(bool checked) { m_ui->btnSubsectionSeparator->setChecked(checked); } + +QLabel* SubsectionSeparator::getLabel() { return m_ui->lblSubsectionSeparator; } + +void SubsectionSeparator::setLabel(const QString& text) { m_ui->lblSubsectionSeparator->setText(text); } + +void SubsectionSeparator::setLabelVisible(bool visible) { m_ui->lblSubsectionSeparator->setVisible(visible); } + +void SubsectionSeparator::setLineVisible(bool visible) { m_ui->lineSubsectionSeparator->setVisible(visible); } + +void SubsectionSeparator::setContent(QWidget* content) { m_ui->vLayoutContent->addWidget(content); } diff --git a/src/gui/subsection_separator.hpp b/src/gui/subsection_separator.hpp new file mode 100644 index 0000000000..dd6abe83da --- /dev/null +++ b/src/gui/subsection_separator.hpp @@ -0,0 +1,44 @@ +#ifndef SUBSECTIONSEPARATOR_H +#define SUBSECTIONSEPARATOR_H + +#include +#include +#include + +namespace Ui { +class SubsectionSeparator; +} + +namespace adiscope { +namespace gui { +class SubsectionSeparator : public QWidget +{ + Q_OBJECT + +public: + explicit SubsectionSeparator(QWidget* parent = nullptr); + explicit SubsectionSeparator(const QString& text, const bool buttonVisible = false, QWidget* parent = nullptr); + ~SubsectionSeparator(); + +private: + Ui::SubsectionSeparator* m_ui; + +public: + QPushButton* getButton(); + void setButtonVisible(bool buttonVisible); + + bool getButtonChecked(); + void setButtonChecked(bool checked); + + QLabel* getLabel(); + void setLabel(const QString& text); + + void setLabelVisible(bool visible); + void setLineVisible(bool visible); + + void setContent(QWidget* content); +}; +} // namespace gui +} // namespace scopy + +#endif // SUBSECTIONSEPARATOR_H diff --git a/src/gui/theme_manager.cpp b/src/gui/theme_manager.cpp new file mode 100644 index 0000000000..727e4876ce --- /dev/null +++ b/src/gui/theme_manager.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include "theme_manager.hpp" +#include "utils.h" + +using namespace adiscope::gui; + +ThemeManager::ThemeManager() + : m_app(nullptr) +{ + m_availableThemes.append("default"); + m_availableThemes.append("light"); +} + +ThemeManager& ThemeManager::getInstance() +{ + static ThemeManager INSTANCE; + return INSTANCE; +} + +void ThemeManager::setApplication(QApplication* app) { m_app = app; } + +void ThemeManager::setCurrentTheme(const QString& theme) +{ + m_currentTheme = theme; + + Util util; + QString stylesheet = util.loadStylesheetFromFile(":/stylesheets/themes/" + theme + ".qss"); + + if (m_app) { + m_app->setStyleSheet(stylesheet); + } + + QIcon::setThemeName(theme); +} + +QString ThemeManager::getCurrentTheme() const { return m_currentTheme; } + +const QStringList ThemeManager::getAvailableThemes() { return m_availableThemes; } diff --git a/src/gui/theme_manager.hpp b/src/gui/theme_manager.hpp new file mode 100644 index 0000000000..a54ce96628 --- /dev/null +++ b/src/gui/theme_manager.hpp @@ -0,0 +1,33 @@ +#ifndef THEMEMANAGER_HPP +#define THEMEMANAGER_HPP + +#include + +namespace adiscope { +namespace gui { + +class ThemeManager +{ +public: + static ThemeManager& getInstance(); + + ThemeManager(const ThemeManager&) = delete; + ThemeManager& operator=(const ThemeManager&) = delete; + + void setApplication(QApplication* app); + const QStringList getAvailableThemes(); + + void setCurrentTheme(const QString& theme); + QString getCurrentTheme() const; + +private: + ThemeManager(); + + QApplication* m_app; + QString m_currentTheme; + QStringList m_availableThemes; +}; +} // namespace gui +} // namespace scopy + +#endif // THEMEMANAGER_HPP diff --git a/src/gui/tool_view.cpp b/src/gui/tool_view.cpp new file mode 100644 index 0000000000..6fd5fd2fdd --- /dev/null +++ b/src/gui/tool_view.cpp @@ -0,0 +1,481 @@ +#include "ui_tool_view.h" + +#include +#include "channel_widget.hpp" +#include "menu_header.hpp" +#include "tool_view.hpp" +#include "utils.h" +#include + +using namespace adiscope::gui; + +ToolView::ToolView(QWidget* parent) + : QWidget(parent) + , m_ui(new Ui::ToolView) +{ + m_ui->setupUi(this); + + m_centralMainWindow = new QMainWindow(m_ui->widgetCentral); + m_centralMainWindow->setCentralWidget(0); + m_centralMainWindow->setWindowFlags(Qt::Widget); + m_ui->widgetCentral->layout()->addWidget(m_centralMainWindow); + + m_ui->widgetRunSingleBtns->enableRunButton(false); + m_ui->widgetRunSingleBtns->enableSingleButton(false); + m_ui->widgetSettingsPairBtns->setVisible(false); + m_ui->btnHelp->setVisible(false); + m_ui->btnPrint->setVisible(false); + + m_ui->widgetInstrumentNotes->setVisible(false); + m_ui->widgetVerticalChannels->setVisible(false); + m_ui->widgetFooter->setVisible(false); + m_ui->widgetMenuBtns->setVisible(false); + + m_ui->widgetMenuAnim->setMaximumWidth(0); + + connect(m_ui->widgetMenuAnim, &MenuAnim::finished, this, &ToolView::rightMenuFinished); +} + +ToolView::~ToolView() { delete m_ui; } + +void ToolView::configureLastOpenedMenu() +{ + QPushButton* settingsBtn = m_ui->widgetSettingsPairBtns->getSettingsBtn(); + + connect(settingsBtn, &QPushButton::clicked, this, [=](bool checked) { + if (!m_menuOrder.isEmpty()) { + CustomPushButton* btn = nullptr; + + if (checked) { + btn = m_menuOrder.back(); + m_menuOrder.pop_back(); + } else { + btn = static_cast(m_group.checkedButton()); + } + + btn->setChecked(checked); + } else { + getSettingsBtn()->setChecked(false); + } + }); +} + +void ToolView::rightMenuFinished(bool opened) +{ + Q_UNUSED(opened) + + // At the end of each animation, check if there are other button check + // actions that might have happened while animating and execute all + // these queued actions + while (m_menuButtonActions.size()) { + auto pair = m_menuButtonActions.dequeue(); + toggleRightMenu(pair.first, pair.second); + } +} + +void ToolView::triggerRightMenuToggle(bool checked) +{ + // Queue the action, if right menu animation is in progress. This way + // the action will be remembered and performed right after the animation + // finishes + CustomPushButton* btn = static_cast(QObject::sender()); + if (m_ui->widgetMenuAnim->animInProgress()) { + m_menuButtonActions.enqueue(QPair(btn, checked)); + } else { + toggleRightMenu(btn, checked); + } +} + +void ToolView::toggleRightMenu(CustomPushButton* btn, bool checked) +{ + int id = btn->property("id").toInt(); + + if (id != -m_generalSettingsMenuId) { + if (!m_menuOrder.contains(btn)) { + m_menuOrder.push_back(btn); + } else { + m_menuOrder.removeOne(btn); + m_menuOrder.push_back(btn); + } + } + + if (checked) { + settingsPanelUpdate(id); + } + + m_ui->widgetMenuAnim->toggleMenu(checked); +} + +void ToolView::settingsPanelUpdate(int id) +{ + if (id >= 0) { + m_ui->stackedWidget->setCurrentIndex(0); + } else { + m_ui->stackedWidget->setCurrentIndex(-id); + } + + for (int i = 0; i < m_ui->stackedWidget->count(); i++) { + QSizePolicy::Policy policy = QSizePolicy::Ignored; + + if (i == m_ui->stackedWidget->currentIndex()) { + policy = QSizePolicy::Expanding; + } + QWidget* widget = m_ui->stackedWidget->widget(i); + widget->setSizePolicy(policy, policy); + } + m_ui->stackedWidget->adjustSize(); +} + +void ToolView::buildChannelsContainer(ChannelManager* cm, ChannelsPositionEnum position) +{ + connect(cm, &ChannelManager::configureAddBtn, this, &ToolView::configureAddMathBtn); + + connect(this, &ToolView::changeParent, cm, &ChannelManager::changeParent); + connect(cm, &ChannelManager::positionChanged, this, [=](ChannelsPositionEnum position) { + if (position == ChannelsPositionEnum::VERTICAL) { + m_ui->widgetHorizontalChannels->setVisible(false); + m_ui->widgetVerticalChannels->setVisible(true); + + if (!m_ui->widgetMenuBtns->isVisible()) { + m_ui->widgetFooter->setVisible(false); + } + + Q_EMIT changeParent(m_ui->widgetVerticalChannelsContainer); + } else { + m_ui->widgetVerticalChannels->setVisible(false); + m_ui->widgetFooter->setVisible(true); + m_ui->widgetHorizontalChannels->setVisible(true); + + Q_EMIT changeParent(m_ui->widgetHorizontalChannelsContainer); + } + }); + + if (position == ChannelsPositionEnum::HORIZONTAL) { + m_ui->widgetFooter->setVisible(true); + cm->build(m_ui->widgetHorizontalChannelsContainer); + } else { + m_ui->widgetVerticalChannels->setVisible(true); + cm->build(m_ui->widgetVerticalChannelsContainer); + } +} + +QDockWidget* ToolView::createDetachableMenu(QWidget* menu, int& id) +{ + QMainWindow* subWindow = new QMainWindow(this); + QDockWidget* docker = new QDockWidget(subWindow); + docker->setFeatures(docker->features() & ~QDockWidget::DockWidgetClosable); + docker->setAllowedAreas(Qt::DockWidgetArea::NoDockWidgetArea); + subWindow->addDockWidget(Qt::RightDockWidgetArea, docker); + docker->setWidget(menu); + +#ifdef SETTINGS_MENU_BAR_ENABLED + DockerUtils::configureTopBar(docker); +#endif + + id = m_ui->stackedWidget->addWidget(subWindow); + + return docker; +} + +QDockWidget *ToolView::createDockableWidget(QWidget *widget, const QString& dockerName) +{ + QDockWidget* docker = new QDockWidget(m_centralMainWindow); + docker->setWindowTitle(dockerName); + docker->setFeatures(docker->features() & ~QDockWidget::DockWidgetClosable); + docker->setAllowedAreas(Qt::DockWidgetArea::AllDockWidgetAreas); + docker->setWidget(widget); + + // workaround, allows dockWidgets movement + widget->setMinimumHeight(50); + widget->setMinimumWidth(50); + +#ifdef PLOT_MENU_BAR_ENABLED + DockerUtils::configureTopBar(docker); +#endif + return docker; +} + +void ToolView::configureAddMathBtn(QWidget* menu, bool dockable) +{ + ChannelManager* cm = static_cast(QObject::sender()); + CustomPushButton* addBtn = cm->getAddChannelBtn(); + int id; + + if (dockable) { + QDockWidget* docker = this->createDetachableMenu(menu, id); + + connect(docker, &QDockWidget::topLevelChanged, addBtn, [=](bool topLevel) { + addBtn->setChecked(!topLevel); + addBtn->setDisabled(topLevel); + + if (topLevel) { + m_menuOrder.removeOne(addBtn); + } + }); + } else { + id = m_ui->stackedWidget->addWidget(menu); + } + + m_group.addButton(addBtn); + addBtn->setProperty("id", QVariant(-id)); + + connect(addBtn, &CustomPushButton::toggled, this, &ToolView::triggerRightMenuToggle); + connect(addBtn, &CustomPushButton::toggled, m_ui->widgetSettingsPairBtns->getSettingsBtn(), + &QPushButton::setChecked); +} + +ChannelWidget* ToolView::buildNewChannel(ChannelManager* channelManager, GenericMenu* menu, bool dockable, int chId, + bool deletable, bool simplefied, QColor color, const QString& fullName, + const QString& shortName) +{ + ChannelWidget* ch = channelManager->buildNewChannel(chId, deletable, simplefied, color, fullName, shortName); + int id; + + if (dockable) { + QDockWidget* docker = this->createDetachableMenu(menu, id); + + connect(docker, &QDockWidget::topLevelChanged, ch->menuButton(), [=](bool topLevel) { + CustomPushButton* btn = static_cast(ch->menuButton()); + btn->setChecked(!topLevel); + btn->setDisabled(topLevel); + + ch->setMenuFloating(topLevel); + + if (topLevel) { + m_menuOrder.removeOne(btn); + } + }); + + if (deletable) { + connect(ch, &ChannelWidget::deleteClicked, this, [=]() { docker->close(); }); + } + + } else { + id = m_ui->stackedWidget->addWidget(menu); + } + + m_group.addButton(ch->menuButton()); + m_channelsGroup.addButton(ch->nameButton()); + ch->menuButton()->setProperty("id", QVariant(-id)); + + connect(ch->menuButton(), &CustomPushButton::toggled, this, &ToolView::triggerRightMenuToggle); + connect(ch->menuButton(), &CustomPushButton::toggled, m_ui->widgetSettingsPairBtns->getSettingsBtn(), + &QPushButton::setChecked); + connect(ch->enableButton(), &QAbstractButton::toggled, [=](bool toggled) { + if (!toggled) { + // we also remove the button from the history + // so that the last menu opened button on top + // won't open the menu when it is disabled + m_menuOrder.removeOne(qobject_cast(ch->menuButton())); + } + + // mirror menu btn + menu->setMenuButton(toggled); + }); + + connect(menu, &GenericMenu::enableBtnToggled, [=](bool toggled) { ch->enableButton()->setChecked(toggled); }); + + if (deletable) { + connect(ch, &ChannelWidget::deleteClicked, this, [=]() { + if (ch->menuButton()->isChecked()) { + m_menuButtonActions.removeAll(QPair( + qobject_cast(ch->menuButton()), true)); + toggleRightMenu(qobject_cast(ch->menuButton()), false); + } + m_menuOrder.removeOne(qobject_cast(ch->menuButton())); + + channelManager->removeChannel(ch); + }); + } + + return ch; +} + +void ToolView::buildNewInstrumentMenu(GenericMenu* menu, bool dockable, const QString& name, bool checkBoxVisible, + bool checkBoxChecked) +{ + m_ui->widgetFooter->setVisible(true); + m_ui->widgetMenuBtns->setVisible(true); + + CustomMenuButton* btn = new CustomMenuButton(name, checkBoxVisible, checkBoxChecked); + int id; + + if (dockable) { + QDockWidget* docker = this->createDetachableMenu(menu, id); + + connect(docker, &QDockWidget::topLevelChanged, btn, [=](bool topLevel) { + btn->getBtn()->setChecked(!topLevel); + btn->getBtn()->setDisabled(topLevel); + + btn->setMenuFloating(topLevel); + + if (topLevel) { + m_menuOrder.removeOne(btn->getBtn()); + } + }); + + } else { + id = m_ui->stackedWidget->addWidget(menu); + } + + m_ui->hLayoutMenuBtnsContainer->addWidget(btn); + m_group.addButton(btn->getBtn()); + btn->getBtn()->setProperty("id", QVariant(-id)); + + connect(btn->getBtn(), &CustomPushButton::toggled, this, &ToolView::triggerRightMenuToggle); + connect(btn->getBtn(), &CustomPushButton::toggled, m_ui->widgetSettingsPairBtns->getSettingsBtn(), + &QPushButton::setChecked); + connect(btn->getCheckBox(), &QCheckBox::toggled, [=](bool toggled) { + if (!toggled) { + // we also remove the button from the history + // so that the last menu opened button on top + // won't open the menu when it is disabled + m_menuOrder.removeOne(btn->getBtn()); + } + // mirror menu btn + menu->setMenuButton(toggled); + }); + + connect(menu, &GenericMenu::enableBtnToggled, [=](bool toggled) { btn->getCheckBox()->setChecked(toggled); }); + + if ((checkBoxVisible && checkBoxChecked) || !checkBoxVisible) { + m_menuOrder.push_back(btn->getBtn()); + } +} + +void ToolView::addFixedCentralWidget(QWidget *widget, int row, int column, int rowspan, int columnspan) +{ + if (row == -1 || column == -1) { + m_ui->gridWidgetCentral->addWidget(widget); + } else { + if (rowspan == -1 || columnspan == -1) { + m_ui->gridWidgetCentral->addWidget(widget, row, column); + } else { + m_ui->gridWidgetCentral->addWidget(widget, row, column, rowspan, columnspan); + } + } +} + +int ToolView::addDockableCentralWidget(QWidget *widget, Qt::DockWidgetArea area, const QString &dockerName) +{ + QDockWidget* docker = this->createDockableWidget(widget, dockerName); + + m_centralMainWindow->addDockWidget(area, docker); + m_docksList.append(docker); + + return m_docksList.size() - 1; +} + +void ToolView::addDockableTabbedWidget(QWidget *widget, const QString &dockerName, int plotId) +{ + QDockWidget* docker = this->createDockableWidget(widget, dockerName); + m_centralMainWindow->tabifyDockWidget(m_docksList.at(plotId), docker); +} + +int ToolView::addFixedTabbedWidget(QWidget *widget, const QString& title, int plotId, int row, int column, int rowspan, int columnspan) +{ + if(m_centralFixedWidgets.size() > plotId && plotId != -1) { + // adding widget to an existing TabWidget + + QTabWidget* tabWidget = static_cast(m_centralFixedWidgets.at(plotId)); + tabWidget->addTab(widget, title); + + return plotId; + + } else { + // creating new TabWidget + + QTabWidget* tabWidget = new QTabWidget(m_ui->widgetCentral); + tabWidget->addTab(widget, title); + m_centralFixedWidgets.append(tabWidget); + + this->addFixedCentralWidget(tabWidget, row, column, rowspan, columnspan); + + return m_centralFixedWidgets.size() - 1; + } +} + +void ToolView::setGeneralSettingsMenu(QWidget* menu, bool dockable) +{ + CustomPushButton* generalSettingsBtn = m_ui->widgetSettingsPairBtns->getGeneralSettingsBtn(); + + if (dockable) { + QDockWidget* docker = this->createDetachableMenu(menu, m_generalSettingsMenuId); + + connect(docker, &QDockWidget::topLevelChanged, generalSettingsBtn, [=](bool topLevel) { + generalSettingsBtn->setChecked(!topLevel); + generalSettingsBtn->setDisabled(topLevel); + }); + } else { + m_generalSettingsMenuId = m_ui->stackedWidget->addWidget(menu); + } + + generalSettingsBtn->setProperty("id", QVariant(-m_generalSettingsMenuId)); + m_group.addButton(generalSettingsBtn); + + connect(generalSettingsBtn, &CustomPushButton::toggled, this, [=](bool toggled) { + triggerRightMenuToggle(toggled); + if (toggled) { + m_ui->widgetSettingsPairBtns->getSettingsBtn()->setChecked(!toggled); + } + }); +} + +void ToolView::setFixedMenu(QWidget* menu, bool dockable) +{ + int id; + + if (dockable) { + QDockWidget* docker = this->createDetachableMenu(menu, id); + + connect(docker, &QDockWidget::topLevelChanged, + [=](bool topLevel) { m_ui->widgetMenuAnim->toggleMenu(!topLevel); }); + } else { + id = m_ui->stackedWidget->addWidget(menu); + } + + settingsPanelUpdate(-id); + m_ui->widgetMenuAnim->toggleMenu(true); +} + +QWidget* ToolView::getTopExtraWidget() { return m_ui->widgetTopExtra; } + +void ToolView::setVisibleTopExtraWidget(bool visible) { m_ui->widgetTopExtra->setVisible(visible); } + +void ToolView::addTopExtraWidget(QWidget* widget) { m_ui->widgetTopExtra->layout()->addWidget(widget); } + +QWidget* ToolView::getBottomExtraWidget() { return m_ui->widgetBottomExtra; } + +void ToolView::setVisibleBottomExtraWidget(bool visible) { m_ui->widgetBottomExtra->setVisible(visible); } + +void ToolView::addBottomExtraWidget(QWidget* widget) { m_ui->widgetBottomExtra->layout()->addWidget(widget); } + +QWidget* ToolView::getCentralWidget() { return m_ui->widgetCentral; } + +QStackedWidget* ToolView::getStackedWidget() { return m_ui->stackedWidget; } + +void ToolView::setInstrumentNotesVisible(bool visible) { m_ui->widgetInstrumentNotes->setVisible(visible); } + +LinkedButton* ToolView::getHelpBtn() { return m_ui->btnHelp; } + +void ToolView::setHelpBtnVisible(bool visible) { m_ui->btnHelp->setVisible(visible); } + +void ToolView::setUrlHelpBtn(const QString& url) { m_ui->btnHelp->setUrl(url); } + +QPushButton* ToolView::getRunBtn() { return m_ui->widgetRunSingleBtns->getRunButton(); } + +void ToolView::setRunBtnVisible(bool visible) { m_ui->widgetRunSingleBtns->enableRunButton(visible); } + +QPushButton* ToolView::getSingleBtn() { return m_ui->widgetRunSingleBtns->getSingleButton(); } + +void ToolView::setSingleBtnVisible(bool visible) { m_ui->widgetRunSingleBtns->enableSingleButton(visible); } + +QPushButton* ToolView::getPrintBtn() { return m_ui->btnPrint; } + +void ToolView::setPrintBtnVisible(bool visible) { m_ui->btnPrint->setVisible(visible); } + +void ToolView::setPairSettingsVisible(bool visible) { m_ui->widgetSettingsPairBtns->setVisible(visible); } + +CustomPushButton* ToolView::getGeneralSettingsBtn() { return m_ui->widgetSettingsPairBtns->getGeneralSettingsBtn(); } + +QPushButton* ToolView::getSettingsBtn() { return m_ui->widgetSettingsPairBtns->getSettingsBtn(); } diff --git a/src/gui/tool_view.hpp b/src/gui/tool_view.hpp new file mode 100644 index 0000000000..8b722ee275 --- /dev/null +++ b/src/gui/tool_view.hpp @@ -0,0 +1,115 @@ +#ifndef TOOL_VIEW_HPP +#define TOOL_VIEW_HPP + +#include +#include +#include +#include +#include +#include + +#include "channel_manager.hpp" +#include "channel_widget.hpp" +#include "custom_menu_button.hpp" +#include "customPushButton.hpp" +#include "generic_menu.hpp" +#include "linked_button.hpp" + +namespace Ui { +class ToolView; +} + +namespace adiscope { +namespace gui { + +class ToolView : public QWidget +{ + friend class ToolViewBuilder; + + Q_OBJECT + +public: + explicit ToolView(QWidget* parent = nullptr); + ~ToolView(); + + LinkedButton* getHelpBtn(); + void setHelpBtnVisible(bool visible); + void setUrlHelpBtn(const QString& url); + + QPushButton* getPrintBtn(); + void setPrintBtnVisible(bool visible); + + QPushButton* getRunBtn(); + void setRunBtnVisible(bool visible); + + QPushButton* getSingleBtn(); + void setSingleBtnVisible(bool visible); + + QWidget* getTopExtraWidget(); + void setVisibleTopExtraWidget(bool visible); + void addTopExtraWidget(QWidget* widget); + + QWidget* getBottomExtraWidget(); + void setVisibleBottomExtraWidget(bool visible); + void addBottomExtraWidget(QWidget* widget); + + QWidget* getCentralWidget(); + QStackedWidget* getStackedWidget(); + + CustomPushButton* getGeneralSettingsBtn(); + QPushButton* getSettingsBtn(); + void setPairSettingsVisible(bool visible); + + void setInstrumentNotesVisible(bool visible); + + void setFixedMenu(QWidget* menu, bool dockable); + void setGeneralSettingsMenu(QWidget* menu, bool dockable); + + ChannelWidget* buildNewChannel(ChannelManager* channelManager, GenericMenu* menu, bool dockable, int chId, + bool deletable, bool simplified, QColor color, const QString& fullName, + const QString& shortName); + void buildNewInstrumentMenu(GenericMenu* menu, bool dockable, const QString& name, bool checkBoxVisible = false, + bool checkBoxChecked = false); + + void addFixedCentralWidget(QWidget* widget, int row = -1, int column = -1,int rowspan = -1, int columnspan = -1); + int addDockableCentralWidget(QWidget* widget, Qt::DockWidgetArea area, const QString& dockerName); + void addDockableTabbedWidget(QWidget* widget, const QString &dockerName, int plotId); + int addFixedTabbedWidget(QWidget* widget, const QString& title, int plotId = -1, int row = -1, int column = -1,int rowspan = -1, int columnspan = -1); + +private: + void configureLastOpenedMenu(); + void buildChannelsContainer(ChannelManager* channelManager, ChannelsPositionEnum position); + void toggleRightMenu(CustomPushButton* btn, bool checked); + void settingsPanelUpdate(int id); + void rightMenuFinished(bool opened); + QDockWidget* createDetachableMenu(QWidget* menu, int& id); + QDockWidget* createDockableWidget(QWidget* widget, const QString& dockerName); + +public Q_SLOTS: + void triggerRightMenuToggle(bool checked); + void configureAddMathBtn(QWidget* menu, bool dockable); + +Q_SIGNALS: + void changeParent(QWidget* newParent); + void channelDisabled(bool disabled); + void instrumentMenuDisabled(bool disabled); + +private: + Ui::ToolView* m_ui; + + QButtonGroup m_group; + QButtonGroup m_channelsGroup; // selected state of each channel + + QQueue> m_menuButtonActions; + QList m_menuOrder; + + int m_generalSettingsMenuId; + + QMainWindow* m_centralMainWindow; + QList m_docksList; + QList m_centralFixedWidgets; +}; +} // namespace gui +} // namespace scopy + +#endif // TOOL_VIEW_HPP diff --git a/src/gui/tool_view_builder.cpp b/src/gui/tool_view_builder.cpp new file mode 100644 index 0000000000..7c820dcfd9 --- /dev/null +++ b/src/gui/tool_view_builder.cpp @@ -0,0 +1,47 @@ +#include "dynamicWidget.hpp" + +#include "tool_view_builder.hpp" + +using namespace adiscope::gui; + +ToolViewBuilder::ToolViewBuilder(const ToolViewRecipe& recipe, ChannelManager* channelManager) +{ + m_toolView = new ToolView(); + + if (recipe.hasRunBtn) { + m_toolView->setRunBtnVisible(true); + } + if (recipe.hasSingleBtn) { + m_toolView->setSingleBtnVisible(true); + } + if (recipe.hasHelpBtn) { + m_toolView->setHelpBtnVisible(true); + m_toolView->setUrlHelpBtn(recipe.helpBtnUrl); + } + if (recipe.hasPrintBtn) { + m_toolView->setPrintBtnVisible(true); + } + if (recipe.hasGroupBtn) { + QPushButton* btn = new QPushButton; + btn->setStyleSheet("QPushButton{ width: 80px;" + "height: 40px;" + "text-align: left;" + "font-weight: bold;" + "padding-left: 15px;" + "padding-right: 15px;}"); + btn->setText("Group"); + adiscope::setDynamicProperty(btn, "blue_button", true); + m_toolView->addTopExtraWidget(btn); + } + + if (recipe.hasPairSettingsBtn) { + m_toolView->setPairSettingsVisible(true); + m_toolView->configureLastOpenedMenu(); + } + + if (recipe.hasChannels) { + m_toolView->buildChannelsContainer(channelManager, recipe.channelsPosition); + } +} + +ToolView* ToolViewBuilder::build() { return m_toolView; } diff --git a/src/gui/tool_view_builder.hpp b/src/gui/tool_view_builder.hpp new file mode 100644 index 0000000000..6be02f193a --- /dev/null +++ b/src/gui/tool_view_builder.hpp @@ -0,0 +1,38 @@ +#ifndef TOOLBUILDER_HPP +#define TOOLBUILDER_HPP + +#include "tool_view.hpp" + +namespace adiscope { +namespace gui { + +struct ToolViewRecipe +{ + QString helpBtnUrl{""}; + bool hasHelpBtn{true}; + bool hasPrintBtn{false}; + bool hasGroupBtn{false}; + + bool hasRunBtn{false}; + bool hasSingleBtn{false}; + + bool hasPairSettingsBtn{false}; + + bool hasChannels{false}; + ChannelsPositionEnum channelsPosition{ChannelsPositionEnum::HORIZONTAL}; +}; + +class ToolViewBuilder +{ +public: + ToolViewBuilder(const ToolViewRecipe& recipe, ChannelManager* channelManager = nullptr); + + ToolView* build(); + +private: + ToolView* m_toolView; +}; +} // namespace gui +} // namespace scopy + +#endif // TOOLVIEWBUILDER_HPP diff --git a/src/user_notes.cpp b/src/gui/user_notes.cpp similarity index 99% rename from src/user_notes.cpp rename to src/gui/user_notes.cpp index 97713420e3..f375889864 100644 --- a/src/user_notes.cpp +++ b/src/gui/user_notes.cpp @@ -22,7 +22,7 @@ #include "ui_user_notes.h" #include "ui_note.h" #include "ui_user_note_page.h" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include #include diff --git a/src/user_notes.hpp b/src/gui/user_notes.hpp similarity index 100% rename from src/user_notes.hpp rename to src/gui/user_notes.hpp diff --git a/src/user_notes_api.cpp b/src/gui/user_notes_api.cpp similarity index 100% rename from src/user_notes_api.cpp rename to src/gui/user_notes_api.cpp diff --git a/src/user_notes_api.hpp b/src/gui/user_notes_api.hpp similarity index 100% rename from src/user_notes_api.hpp rename to src/gui/user_notes_api.hpp diff --git a/src/handles_area.cpp b/src/handles_area.cpp index f4e8407489..fd515016af 100644 --- a/src/handles_area.cpp +++ b/src/handles_area.cpp @@ -53,6 +53,7 @@ void HandlesArea::mousePressEvent(QMouseEvent *event) hotspot = event->pos() - child->pos(); child->setGrabbed(true); } + event->accept(); } void HandlesArea::mouseReleaseEvent(QMouseEvent *) diff --git a/src/handlesareaextension.cpp b/src/handlesareaextension.cpp index 29797112cb..406aceb36f 100644 --- a/src/handlesareaextension.cpp +++ b/src/handlesareaextension.cpp @@ -41,7 +41,7 @@ bool XBottomRuller::draw(QPainter *painter, QWidget *owner) for (int i = 0; i < majorTicks.size(); ++i) { currentValue = majorTicks.at(i); - pointVal = plot->transform(QwtPlot::xBottom, currentValue) + leftP; + pointVal = plot->transform(QwtAxis::XBottom, currentValue) + leftP; const QString text = plot->formatXValue(currentValue, 2); @@ -75,7 +75,7 @@ bool XBottomRuller::draw(QPainter *painter, QWidget *owner) // PainterSaveRestore psr(painter); - const QwtInterval interval = plot->axisInterval(QwtPlot::xBottom); + const QwtInterval interval = plot->axisInterval(QwtAxis::XBottom); const int labels = plot->xAxisNumDiv() + 1; @@ -110,7 +110,7 @@ bool XBottomRuller::draw(QPainter *painter, QWidget *owner) } // get nr of major ticks - const int nrMajorTicks = plot->axisScaleDiv(QwtPlot::xBottom).ticks(QwtScaleDiv::MajorTick).size(); + const int nrMajorTicks = plot->axisScaleDiv(QwtAxis::XBottom).ticks(QwtScaleDiv::MajorTick).size(); const int midLabelTick = nrMajorTicks / 2; if (allLabelsTheSame) { @@ -240,7 +240,7 @@ bool XTopRuller::draw(QPainter *painter, QWidget *owner) for (int i = 0; i < majorTicks.size(); ++i) { currentValue = majorTicks.at(i); - pointVal = plot->transform(QwtPlot::xTop, currentValue) + leftP; + pointVal = plot->transform(QwtAxis::XTop, currentValue) + leftP; const QString text = plot->formatXValue(currentValue, 2); @@ -276,7 +276,7 @@ bool XTopRuller::draw(QPainter *painter, QWidget *owner) // PainterSaveRestore psr(painter); - const QwtInterval interval = plot->axisInterval(QwtPlot::xTop); + const QwtInterval interval = plot->axisInterval(QwtAxis::XTop); const int labels = plot->xAxisNumDiv() + 1; @@ -310,7 +310,7 @@ bool XTopRuller::draw(QPainter *painter, QWidget *owner) } // get nr of major ticks - const int nrMajorTicks = plot->axisScaleDiv(QwtPlot::xTop).ticks(QwtScaleDiv::MajorTick).size(); + const int nrMajorTicks = plot->axisScaleDiv(QwtAxis::XTop).ticks(QwtScaleDiv::MajorTick).size(); const int midLabelTick = nrMajorTicks / 2; if (allLabelsTheSame) { @@ -444,7 +444,7 @@ bool YLeftRuller::draw(QPainter *painter, QWidget *owner) for (int i = 0; i < majorTicks.size(); ++i) { currentValue = majorTicks.at(i); - pointVal = plot->transform(QwtPlot::yLeft, currentValue) + topP; + pointVal = plot->transform(QwtAxis::YLeft, currentValue) + topP; const QString text = plot->formatYValue(currentValue, 2); @@ -475,7 +475,7 @@ bool YLeftRuller::draw(QPainter *painter, QWidget *owner) else { - const QwtInterval interval = plot->axisInterval(QwtPlot::yLeft); + const QwtInterval interval = plot->axisInterval(QwtAxis::YLeft); const int labels = plot->yAxisNumDiv(); @@ -511,7 +511,7 @@ bool YLeftRuller::draw(QPainter *painter, QWidget *owner) } // get nr of major ticks - const int nrMajorTicks = plot->axisScaleDiv(QwtPlot::yLeft).ticks(QwtScaleDiv::MajorTick).size(); + const int nrMajorTicks = plot->axisScaleDiv(QwtAxis::YLeft).ticks(QwtScaleDiv::MajorTick).size(); const int midLabelTick = nrMajorTicks / 2; if (allLabelsTheSame) { diff --git a/src/histogram_sink_f_impl.cc b/src/histogram_sink_f_impl.cc index 2e23798c6d..9ce422827b 100644 --- a/src/histogram_sink_f_impl.cc +++ b/src/histogram_sink_f_impl.cc @@ -94,7 +94,7 @@ namespace adiscope { set_alignment(std::max(1,alignment_multiple)); this->plot = (HistogramDisplayPlot*)plot; - initialize(); + initialize(); } histogram_sink_f_impl::~histogram_sink_f_impl() @@ -117,12 +117,11 @@ namespace adiscope { if(qApp != NULL) { d_qApplication = qApp; } + set_update_time(1/60.0); plot->setNumBins(d_bins); plot->setXaxis(d_xmin, d_xmax); - // initialize update time to 10 times a second - set_update_time(0.1); } void diff --git a/src/iio_manager.cpp b/src/iio_manager.cpp index d5a4fcee39..b44ff13ede 100644 --- a/src/iio_manager.cpp +++ b/src/iio_manager.cpp @@ -28,10 +28,11 @@ #include #include +#include using namespace adiscope; using namespace gr; -static const int KERNEL_BUFFERS_DEFAULT = 4; +static const int KERNEL_BUFFERS_DEFAULT = 1; std::map iio_manager::dev_map; unsigned iio_manager::_id = 0; @@ -54,22 +55,11 @@ iio_manager::iio_manager(unsigned int block_id, nb_channels = iio_device_get_channels_count(dev); - iio_block = gr::m2k::analog_in_source::make_from(m_context, - _buffer_size, - {1, 1}, - {0, 0}, - 10000, - 1, - KERNEL_BUFFERS_DEFAULT, - false, - false, - {0, 0}, - {0, 0}, - 0, - 0, - {0, 0}, - false, - false); + // get target fps from preferences + double targetFps = getScopyPreferences()->getTarget_fps(); + iio_block = gr::m2k::analog_in_source::make_from(m_context, _buffer_size, {1, 1}, {0, 0}, 10000, 1, + KERNEL_BUFFERS_DEFAULT, false, false, {0, 0}, {0, 0}, 0, 0, {0, 0}, + false, false, targetFps); /* Avoid unconnected channel errors by connecting a dummy sink */ auto dummy_copy = blocks::copy::make(sizeof(short)); @@ -371,6 +361,18 @@ void iio_manager::set_device_timeout(unsigned int mseconds) } } +void iio_manager::set_data_rate(double rate) { + iio_block->set_data_rate(rate); +} + +void iio_manager::set_kernel_buffer_count(int kb) { + if(kb) { + m_analogin->setKernelBuffersCount(kb); + } else { + m_analogin->setKernelBuffersCount(KERNEL_BUFFERS_DEFAULT); + } +} + void iio_manager::enableMixedSignal(m2k::mixed_signal_source::sptr mixed_source) { for (int i = 0; i < nb_channels; ++i) { diff --git a/src/iio_manager.hpp b/src/iio_manager.hpp index 1d8fdf6082..7bc9cb1661 100644 --- a/src/iio_manager.hpp +++ b/src/iio_manager.hpp @@ -105,6 +105,8 @@ namespace adiscope { * Warning: the flowgraph needs to be locked first! */ void set_buffer_size(port_id id, unsigned long size); void set_filter_parameters(int channel, int index, bool enable, float TC, float gain, float sample_rate ); + void set_data_rate(double rate); + void set_kernel_buffer_count(int kb = 0); /* VERY ugly hack. The reconfiguration that happens after * locking/unlocking the flowgraph is sort of broken; the tags diff --git a/src/limitedplotzoomer.cpp b/src/limitedplotzoomer.cpp index bb39b54a1a..f3878d1342 100644 --- a/src/limitedplotzoomer.cpp +++ b/src/limitedplotzoomer.cpp @@ -19,12 +19,13 @@ */ #include "limitedplotzoomer.h" #include +#include using namespace adiscope; LimitedPlotZoomer::LimitedPlotZoomer(QWidget *parent, bool doReplot): QwtPlotZoomer(parent, doReplot), - m_boundVertical(false) + m_boundVertical(false), m_updateBaseNextZoom(true) { setMaxStackDepth(5); } @@ -32,9 +33,13 @@ LimitedPlotZoomer::LimitedPlotZoomer(QWidget *parent, bool doReplot): void LimitedPlotZoomer::resetZoom() { QwtPlotZoomer::zoom(0); + m_updateBaseNextZoom = true; } - +void LimitedPlotZoomer::popZoom() +{ + QwtPlotZoomer::zoom(-1); +} void LimitedPlotZoomer::setBoundVertical(bool bound) { @@ -43,6 +48,11 @@ void LimitedPlotZoomer::setBoundVertical(bool bound) void LimitedPlotZoomer::zoom(const QRectF &rect) { + + if(m_updateBaseNextZoom) { + setZoomBase(); + m_updateBaseNextZoom = false; + } QRectF boundedRect = rect & zoomBase(); if (m_boundVertical) { diff --git a/src/limitedplotzoomer.h b/src/limitedplotzoomer.h index d09125cba8..0ae377836f 100644 --- a/src/limitedplotzoomer.h +++ b/src/limitedplotzoomer.h @@ -28,6 +28,7 @@ class LimitedPlotZoomer : public QwtPlotZoomer public: LimitedPlotZoomer(QWidget*, bool doReplot = false); void resetZoom(); + void popZoom(); void setBoundVertical(bool bound); @@ -37,6 +38,7 @@ class LimitedPlotZoomer : public QwtPlotZoomer private: bool m_boundVertical; + bool m_updateBaseNextZoom; }; } diff --git a/src/logging_categories.cpp b/src/logging_categories.cpp index c802193858..78ea67262d 100644 --- a/src/logging_categories.cpp +++ b/src/logging_categories.cpp @@ -33,4 +33,5 @@ Q_LOGGING_CATEGORY(CAT_PATTERN_GENERATOR, "patternGenerator") Q_LOGGING_CATEGORY(CAT_CALIBRATION, "calibration") Q_LOGGING_CATEGORY(CAT_CALIBRATION_MANUAL, "calibration.manual") Q_LOGGING_CATEGORY(CAT_IIO_MANAGER, "iioManager") +Q_LOGGING_CATEGORY(CAT_PLOT, "plot") #endif diff --git a/src/logging_categories.h b/src/logging_categories.h index edabca2186..588a19dcb9 100644 --- a/src/logging_categories.h +++ b/src/logging_categories.h @@ -36,6 +36,7 @@ Q_DECLARE_LOGGING_CATEGORY(CAT_PATTERN_GENERATOR) Q_DECLARE_LOGGING_CATEGORY(CAT_CALIBRATION) Q_DECLARE_LOGGING_CATEGORY(CAT_CALIBRATION_MANUAL) Q_DECLARE_LOGGING_CATEGORY(CAT_IIO_MANAGER) +Q_DECLARE_LOGGING_CATEGORY(CAT_PLOT) #else #define CAT_TOOL_LAUNCHER #define CAT_OSCILLOSCOPE @@ -50,6 +51,7 @@ Q_DECLARE_LOGGING_CATEGORY(CAT_IIO_MANAGER) #define CAT_CALIBRATION #define CAT_CALIBRATION_MANUAL #define CAT_IIO_MANAGER +#define CAT_PLOT #endif #endif // LOGGING_CATEGORIES_H diff --git a/src/logicanalyzer/annotationcurve.cpp b/src/logicanalyzer/annotationcurve.cpp index c490f9e9a9..ce5ea7ac7c 100644 --- a/src/logicanalyzer/annotationcurve.cpp +++ b/src/logicanalyzer/annotationcurve.cpp @@ -325,7 +325,7 @@ void AnnotationCurve::drawLines(QPainter *painter, const QwtScaleMap &xMap, cons mapper.setFlag( QwtPointMapper::RoundPoints, QwtPainter::roundingAlignment( painter ) ); mapper.setBoundingRect(canvasRect); - auto interval = plot()->axisInterval(QwtAxis::xBottom); + auto interval = plot()->axisInterval(QwtAxis::XBottom); QStringList titles; @@ -612,7 +612,7 @@ void AnnotationCurve::drawTwoSampleAnnotation(int row, const Annotation &ann, QP // END DRAW MULTI POINT annotation // DRAW LABEL - QwtInterval interval = plot()->axisInterval(QwtAxis::xBottom); + QwtInterval interval = plot()->axisInterval(QwtAxis::XBottom); const double bonus = xMap.invTransform(titleSize.width() + 5) - xMap.invTransform(0); @@ -690,7 +690,7 @@ void AnnotationCurve::drawOneSampleAnnotation(int row, const Annotation &ann, QP painter->save(); painter->setPen(QPen(QBrush(Qt::black), 20)); - QwtInterval interval = plot()->axisInterval(QwtAxis::xBottom); + QwtInterval interval = plot()->axisInterval(QwtAxis::XBottom); const double bonus = xMap.invTransform(titleSize.width() + 5) - xMap.invTransform(0); const double WidthInPoints = xMap.invTransform(m_traceHeight) - xMap.invTransform(0); diff --git a/src/logicanalyzer/logic_analyzer.cpp b/src/logicanalyzer/logic_analyzer.cpp index 0a820e86f2..bf3e5e732c 100644 --- a/src/logicanalyzer/logic_analyzer.cpp +++ b/src/logicanalyzer/logic_analyzer.cpp @@ -32,14 +32,14 @@ #include "logicanalyzer/annotationcurve.h" #include "logicanalyzer/decoder.h" -#include "basemenu.h" +#include "gui/basemenu.h" #include "logicgroupitem.h" #include "logicanalyzer_api.h" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include - +#include #include #include @@ -50,7 +50,7 @@ #include #include "scopyExceptionHandler.h" -#include "osc_export_settings.h" +#include "gui/osc_export_settings.h" #include "filemanager.h" #include "config.h" #include "state_updater.h" @@ -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, false, 16, 10), + m_plot(this, false, 16, 10, new TimePrefixFormatter, new MetricPrefixFormatter), m_bufferPreviewer(new DigitalBufferPreviewer(40, this)), m_m2k_context(m2kOpen(ctx, "")), m_m2kDigital(m_m2k_context->getDigital()), @@ -142,7 +142,7 @@ LogicAnalyzer::LogicAnalyzer(struct iio_context *ctx, adiscope::Filter *filt, for (uint8_t i = 0; i < m_nbChannels; ++i) { QCheckBox *channelBox = new QCheckBox("DIO " + QString::number(i)); - QHBoxLayout *hBoxLayout = new QHBoxLayout(this); + QHBoxLayout *hBoxLayout = new QHBoxLayout(); ui->channelEnumeratorLayout->addLayout(hBoxLayout, i % 8, i / 8); @@ -155,7 +155,7 @@ LogicAnalyzer::LogicAnalyzer(struct iio_context *ctx, adiscope::Filter *filt, channelBox->setChecked(true); - triggerBox->setStyleSheet("QComboBox QAbstractItemView { min-width: 130px; }"); + triggerBox->setStyleSheet("QComboBox { max-width: 60px; } QComboBox QAbstractItemView { min-width: 130px; }"); triggerBox->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); for (int i = 1; i < ui->triggerComboBox->count(); ++i) { @@ -280,10 +280,6 @@ LogicAnalyzer::~LogicAnalyzer() m_buffer = nullptr; } -// if (srd_exit() != SRD_OK) { -// qDebug() << "Error: srd_exit failed in ~LogicAnalyzer()"; -// } - delete cr_ui; delete ui; } @@ -1292,26 +1288,67 @@ void LogicAnalyzer::setupUi() // Plot positioning and settings m_plot.disableLegend(); + + // Build central widget + + QWidget* centralWidget = new QWidget(this); + QVBoxLayout* vLayout = new QVBoxLayout(centralWidget); + vLayout->setContentsMargins(0, 0, 0, 0); + vLayout->setSpacing(0); + + // add the buffer previewer + ui->plot_and_buffPreviewer->removeWidget(ui->hLayoutBufferPreview); + vLayout->addWidget(ui->hLayoutBufferPreview); + + // add plot elements + QWidget* plotWidget = new QWidget(this); + plotWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored); + QGridLayout* gridLayout = new QGridLayout(plotWidget); + gridLayout->setVerticalSpacing(0); + gridLayout->setHorizontalSpacing(0); + gridLayout->setContentsMargins(15, 0, 15, 0); + plotWidget->setLayout(gridLayout); + QSpacerItem *plotSpacer = new QSpacerItem(0, 5, QSizePolicy::Fixed, QSizePolicy::Fixed); -// ui->gridLayoutPlot->addWidget(measurePanel, 0, 1, 1, 1); - ui->gridLayoutPlot->addWidget(m_plot.topArea(), 0, 0, 1, 4); - ui->gridLayoutPlot->addWidget(m_plot.topHandlesArea(), 1, 0, 1, 4); + gridLayout->addWidget(m_plot.topArea(), 0, 0, 1, 4); + gridLayout->addWidget(m_plot.topHandlesArea(), 1, 0, 1, 4); - ui->gridLayoutPlot->addWidget(m_plot.leftHandlesArea(), 0, 0, 4, 1); - ui->gridLayoutPlot->addWidget(m_plot.rightHandlesArea(), 0, 3, 4, 1); + gridLayout->addWidget(m_plot.leftHandlesArea(), 0, 0, 4, 1); + gridLayout->addWidget(m_plot.rightHandlesArea(), 0, 3, 4, 1); + gridLayout->addWidget(&m_plot, 2, 1, 1, 1); + gridLayout->addWidget(m_plotScrollBar, 2, 5, 1, 1); - ui->gridLayoutPlot->addWidget(&m_plot, 2, 1, 1, 1); - ui->gridLayoutPlot->addWidget(m_plotScrollBar, 2, 5, 1, 1); + gridLayout->addWidget(m_plot.bottomHandlesArea(), 3, 0, 1, 4); + gridLayout->addItem(plotSpacer, 4, 0, 1, 4); - ui->gridLayoutPlot->addWidget(m_plot.bottomHandlesArea(), 3, 0, 1, 4); - ui->gridLayoutPlot->addItem(plotSpacer, 4, 0, 1, 4); -// ui->gridLayoutPlot->addWidget(statisticsPanel, 6, 1, 1, 1); + vLayout->addWidget(plotWidget); + centralWidget->setLayout(vLayout); - m_plot.enableAxis(QwtPlot::yLeft, false); - m_plot.enableAxis(QwtPlot::xBottom, false); + if(prefPanel->getCurrent_docking_enabled()) { + + // main window for dock widget + QMainWindow* mainWindow = new QMainWindow(this); + mainWindow->setCentralWidget(0); + mainWindow->setWindowFlags(Qt::Widget); + ui->gridLayoutPlot->addWidget(mainWindow, 1, 0, 1, 1); + + QDockWidget* docker = DockerUtils::createDockWidget(mainWindow, centralWidget); + + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, docker); + +#ifdef PLOT_MENU_BAR_ENABLED + DockerUtils::configureTopBar(docker); +#endif + } else { + ui->gridLayoutPlot->addWidget(centralWidget, 1, 0, 1, 1); + } + + + m_plot.setAxisVisible(QwtAxis::YLeft, false); + m_plot.setAxisVisible(QwtAxis::XBottom, false); m_plot.setUsingLeftAxisScales(false); m_plot.enableLabels(false); @@ -1606,7 +1643,7 @@ void LogicAnalyzer::settingsPanelUpdate(int id) void LogicAnalyzer::updateBufferPreviewer(int64_t min, int64_t max) { // Time interval within the plot canvas - QwtInterval plotInterval = m_plot.axisInterval(QwtPlot::xBottom); + QwtInterval plotInterval = m_plot.axisInterval(QwtAxis::XBottom); // Time interval that represents the captured data QwtInterval dataInterval(0.0, 0.0); @@ -1656,7 +1693,7 @@ void LogicAnalyzer::initBufferScrolling() connect(m_bufferPreviewer, &BufferPreviewer::bufferMovedBy, [=](int value) { m_resetHorizAxisOffset = false; double moveTo = 0.0; - auto interval = m_plot.axisInterval(QwtPlot::xBottom); + auto interval = m_plot.axisInterval(QwtAxis::XBottom); double min = interval.minValue(); double max = interval.maxValue(); int width = m_bufferPreviewer->width(); @@ -1688,6 +1725,7 @@ void LogicAnalyzer::startStop(bool start) } m_started = start; + m_plot.startStop(start); m_triggerUpdater->setEnabled(start); if (start) { @@ -1919,7 +1957,8 @@ void LogicAnalyzer::startStop(bool start) totalSamples = bufferSizeAdjusted; absIndex = 0; - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + int ms = (int)(1000.0 / getScopyPreferences()->getTarget_fps()); + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); } } while (totalSamples && !m_stopRequested); @@ -2406,7 +2445,9 @@ void LogicAnalyzer::restoreTriggerState() void LogicAnalyzer::readPreferences() { - qDebug() << "reading preferences!!!!"; + bool showFps = prefPanel->getShow_plot_fps(); + m_plot.setVisibleFpsLabel(showFps); + for (GenericLogicPlotCurve *curve : qAsConst(m_plotCurves)) { if (curve->getType() == LogicPlotCurveType::Data) { LogicDataCurve *ldc = dynamic_cast(curve); diff --git a/src/logicanalyzer/logic_analyzer.h b/src/logicanalyzer/logic_analyzer.h index 13cb0e4b41..ee88a93a50 100644 --- a/src/logicanalyzer/logic_analyzer.h +++ b/src/logicanalyzer/logic_analyzer.h @@ -34,7 +34,7 @@ #include "logic_tool.h" #include "oscilloscope_plot.hpp" #include "buffer_previewer.hpp" -#include "spinbox_a.hpp" +#include "gui/spinbox_a.hpp" #include "scroll_filter.hpp" #include "saverestoretoolsettings.h" diff --git a/src/logicanalyzer/logicdatacurve.cpp b/src/logicanalyzer/logicdatacurve.cpp index 8e94da8b00..60889ae296 100644 --- a/src/logicanalyzer/logicdatacurve.cpp +++ b/src/logicanalyzer/logicdatacurve.cpp @@ -169,7 +169,7 @@ void LogicDataCurve::drawLines(QPainter *painter, const QwtScaleMap &xMap, } if (edges.back().first + 1 == m_endSample - 1) { - displayedData += QPointF(plot()->axisInterval(QwtAxis::xBottom).maxValue(), displayedData.back().y()); + displayedData += QPointF(plot()->axisInterval(QwtAxis::XBottom).maxValue(), displayedData.back().y()); } painter->save(); @@ -193,7 +193,7 @@ void LogicDataCurve::drawLines(QPainter *painter, const QwtScaleMap &xMap, return; } - QwtInterval interval = plot()->axisInterval(QwtAxis::xBottom); + QwtInterval interval = plot()->axisInterval(QwtAxis::XBottom); int start = fromTimeToSample(interval.minValue()); int end = fromTimeToSample(interval.maxValue()); @@ -229,7 +229,7 @@ void LogicDataCurve::getSubsampledEdges(std::vector> & double dist = xMap.transform(fromSampleToTime(1)) - xMap.transform(fromSampleToTime(0)); - QwtInterval interval = plot()->axisInterval(QwtAxis::xBottom); + QwtInterval interval = plot()->axisInterval(QwtAxis::XBottom); uint64_t firstEdge = edgeAtX(fromTimeToSample(interval.minValue()), m_edges); uint64_t lastEdge = edgeAtX(fromTimeToSample(interval.maxValue()), m_edges); diff --git a/src/logicanalyzer/logicgroupitem.cpp b/src/logicanalyzer/logicgroupitem.cpp index fd74fff99e..05ff0904bf 100644 --- a/src/logicanalyzer/logicgroupitem.cpp +++ b/src/logicanalyzer/logicgroupitem.cpp @@ -26,7 +26,7 @@ #include #include -#include "basemenu.h" +#include "gui/basemenu.h" using namespace adiscope; diff --git a/src/logicanalyzer/logicgroupitem.h b/src/logicanalyzer/logicgroupitem.h index 71a24a2f9a..6c22a86064 100644 --- a/src/logicanalyzer/logicgroupitem.h +++ b/src/logicanalyzer/logicgroupitem.h @@ -22,7 +22,7 @@ #ifndef LOGICGROUPITEM_H #define LOGICGROUPITEM_H -#include "basemenuitem.h" +#include "gui/basemenuitem.h" #include diff --git a/src/main.cpp b/src/main.cpp index 2518826167..734cb4e8ca 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,11 +40,27 @@ #include "scopy_color_editor.h" #include "application_restarter.h" +#ifdef __ANDROID__ + #include +#endif using namespace adiscope; int main(int argc, char **argv) { +#ifdef __ANDROID__ + QAndroidJniObject jniObject = QtAndroid::androidActivity().callObjectMethod("getScaleFactor", "()Ljava/lang/String;"); + QString scaleFactor = jniObject.toString(); + + qputenv("QT_SCALE_FACTOR", scaleFactor.toUtf8()); + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true); + QApplication::setAttribute(Qt::AA_CompressTabletEvents, true); + qputenv("SCOPY_USE_OPEN_GL", "1"); +#endif + QApplication::setAttribute(Qt::AA_ShareOpenGLContexts,true); + ScopyApplication app(argc, argv); #ifdef LIBM2K_ENABLE_LOG enableLogging(true); @@ -60,13 +76,13 @@ int main(int argc, char **argv) #ifdef Q_OS_WIN google_breakpad::ExceptionHandler eh(L"C:/dumps/", - NULL, - ScopyApplication::dumpCallback, - NULL, - google_breakpad::ExceptionHandler::HANDLER_ALL, - MiniDumpNormal, - (wchar_t*)NULL, - NULL); + NULL, + ScopyApplication::dumpCallback, + NULL, + google_breakpad::ExceptionHandler::HANDLER_ALL, + MiniDumpNormal, + (wchar_t*)NULL, + NULL); #endif app.setExceptionHandler(&eh); #endif @@ -110,11 +126,13 @@ int main(int argc, char **argv) parser.addVersionOption(); parser.addOptions({ - { {"s", "script"}, "Run given script.", "script" }, - { {"n", "nogui"}, "Run Scopy without GUI" }, - { {"d", "nodecoders"}, "Run Scopy without digital decoders"}, - { {"nd", "nonativedialog"}, "Run Scopy without native file dialogs"} - }); + { {"s", "script"}, "Run given script.", "script" }, + { {"n", "nogui"}, "Run Scopy without GUI" }, + { {"d", "nodecoders"}, "Run Scopy without digital decoders"}, + { {"nd", "nonativedialog"}, "Run Scopy without native file dialogs"}, + { {"og", "opengl"}, "Force use OpenGL for plots"} , + { {"nog", "noopengl"}, "Force software rendering for plots"} , + }); parser.process(app); @@ -159,6 +177,19 @@ int main(int argc, char **argv) app.setStyleSheet(colorEditor->getStyleSheet()); } + bool openGl = parser.isSet("opengl"); + bool noOpenGl = parser.isSet("noopengl"); + if(openGl && noOpenGl) { + qDebug()<<"Ambigous openGL parameters"; + return -1; + } + if(openGl) { + qputenv("SCOPY_USE_OPENGL","1"); + } + if(noOpenGl) { + qputenv("SCOPY_USE_OPENGL","0"); + } + ToolLauncher launcher(prevCrashDump); launcher.getPrefPanel()->setColorEditor(colorEditor); @@ -198,10 +229,10 @@ int main(int argc, char **argv) file.close(); QMetaObject::invokeMethod(&launcher, - "runProgram", - Qt::QueuedConnection, - Q_ARG(QString, contents), - Q_ARG(QString, script)); + "runProgram", + Qt::QueuedConnection, + Q_ARG(QString, contents), + Q_ARG(QString, script)); } return restarter.restart(app.exec()); } diff --git a/src/manualcalibration.h b/src/manualcalibration.h index c343b55406..16b2a5f3a9 100644 --- a/src/manualcalibration.h +++ b/src/manualcalibration.h @@ -31,7 +31,7 @@ /*Local includes*/ #include "tool.hpp" -#include "detachedWindow.hpp" +#include "gui/detachedWindow.hpp" #include "tool_launcher.hpp" #include "filter.hpp" diff --git a/src/marker_controller.cpp b/src/marker_controller.cpp index 3d20650a52..30b6064b2e 100644 --- a/src/marker_controller.cpp +++ b/src/marker_controller.cpp @@ -118,9 +118,9 @@ void MarkerController::onPickerMoved(QPoint p) if (d_picked_mrk) { QPointF val = d_picked_mrk->plotPixelsToValue(p); QwtInterval xItv = plot()->axisScaleDiv( - QwtPlot::xBottom).interval(); + QwtAxis::XBottom).interval(); QwtInterval yItv = plot()->axisScaleDiv( - QwtPlot::yLeft).interval(); + QwtAxis::YLeft).interval(); // Make sure the marker does not leave the plot canvas if (val.x() < xItv.minValue()) { diff --git a/src/math.cpp b/src/math.cpp index 190b1395e8..63234bd177 100644 --- a/src/math.cpp +++ b/src/math.cpp @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include "math.hpp" #include diff --git a/src/measurement_gui.cpp b/src/measurement_gui.cpp index 1cf18314dc..a4a5ad5483 100644 --- a/src/measurement_gui.cpp +++ b/src/measurement_gui.cpp @@ -18,7 +18,7 @@ * along with this program. If not, see . */ #include "measurement_gui.h" -#include "measure.h" +#include "gui/measure.h" #include @@ -182,6 +182,86 @@ void PercentageMeasurementGui::update(const MeasurementData& data, double displa m_valueLabel->setText(m_value); } +/* + * Class DecibelsMeasurementGui implementation + */ + + DecibelsMeasurementGui::DecibelsMeasurementGui(): + MeasurementGui() +{ +} + +void DecibelsMeasurementGui::init(QLabel *name, QLabel *value) +{ + // Get the necessary label width so that the label will never resize + QLabel *label = new QLabel(value); + label->setText("-999.999 dB"); + m_minValLableWidth = label->minimumSizeHint().width(); + value->setMinimumWidth(m_minValLableWidth); + delete label; + + MeasurementGui::init(name, value); +} + +void DecibelsMeasurementGui::update(const MeasurementData& data, double displayScale) +{ + m_name = data.name() + ":"; + + if (data.measured() && data.enabled()) { + double value = data.value(); + if (data.axis() == MeasurementData::VERTICAL_F) { + value *= displayScale; + } + m_value.setNum(value, 'f', 3); + m_value += "dB"; + } else { + m_value = "--"; + } + + m_nameLabel->setText(m_name); + m_valueLabel->setText(m_value); +} + +/* + * Class DecibelstoCarrierMeasurementGui implementation + */ + + DecibelstoCarrierMeasurementGui::DecibelstoCarrierMeasurementGui(): + MeasurementGui() +{ +} + +void DecibelstoCarrierMeasurementGui::init(QLabel *name, QLabel *value) +{ + // Get the necessary label width so that the label will never resize + QLabel *label = new QLabel(value); + label->setText("-999.999 dB"); + m_minValLableWidth = label->minimumSizeHint().width(); + value->setMinimumWidth(m_minValLableWidth); + delete label; + + MeasurementGui::init(name, value); +} + +void DecibelstoCarrierMeasurementGui::update(const MeasurementData& data, double displayScale) +{ + m_name = data.name() + ":"; + + if (data.measured() && data.enabled()) { + double value = data.value(); + if (data.axis() == MeasurementData::VERTICAL_F) { + value *= displayScale; + } + m_value.setNum(value, 'f', 3); + m_value += "dB"; + } else { + m_value = "--"; + } + + m_nameLabel->setText(m_name); + m_valueLabel->setText(m_value); +} + /* * Class DimensionlessMeasurementGui implementation */ diff --git a/src/measurement_gui.h b/src/measurement_gui.h index aac46beaa7..59a71de283 100644 --- a/src/measurement_gui.h +++ b/src/measurement_gui.h @@ -83,6 +83,24 @@ class PercentageMeasurementGui: public MeasurementGui virtual void update(const MeasurementData& data, double displayScale); }; +class DecibelsMeasurementGui: public MeasurementGui +{ +public: + DecibelsMeasurementGui(); + + virtual void init(QLabel *name, QLabel *value); + virtual void update(const MeasurementData& data, double displayScale); +}; + +class DecibelstoCarrierMeasurementGui: public MeasurementGui +{ +public: + DecibelstoCarrierMeasurementGui(); + + virtual void init(QLabel *name, QLabel *value); + virtual void update(const MeasurementData& data, double displayScale); +}; + class DimensionlessMeasurementGui: public MeasurementGui { public: diff --git a/src/mixed_signal_sink.h b/src/mixed_signal_sink.h index 16c471859a..64cca446de 100644 --- a/src/mixed_signal_sink.h +++ b/src/mixed_signal_sink.h @@ -38,6 +38,7 @@ class mixed_signal_sink : virtual public gr::sync_block virtual void clean_buffers() = 0; virtual void set_nsamps(int newsize) = 0; virtual void set_displayOneBuffer(bool display) = 0; + virtual void set_update_time(double t) = 0; }; #endif // MIXED_SIGNAL_SINK_H diff --git a/src/mixed_signal_sink_impl.cpp b/src/mixed_signal_sink_impl.cpp index ff200f181d..7440b8fee6 100644 --- a/src/mixed_signal_sink_impl.cpp +++ b/src/mixed_signal_sink_impl.cpp @@ -66,6 +66,8 @@ mixed_signal_sink_impl::mixed_signal_sink_impl(adiscope::logic::LogicAnalyzer *l static_cast(volk_malloc(d_buffer_size * sizeof(double), volk_get_alignment()))); memset(d_analog_plot_buffers[i], 0, d_buffer_size * sizeof(double)); } + + set_update_time(1/60.0); } int mixed_signal_sink_impl::work(int noutput_items, @@ -191,6 +193,14 @@ void mixed_signal_sink_impl::set_nsamps(int newsize) } } +void mixed_signal_sink_impl::set_update_time(double t) +{ + //convert update time to ticks + gr::high_res_timer_type tps = gr::high_res_timer_tps(); + d_update_time = t * tps; + d_last_time = 0; +} + void mixed_signal_sink_impl::set_displayOneBuffer(bool display) { if (d_display_one_buffer != display) { diff --git a/src/mixed_signal_sink_impl.h b/src/mixed_signal_sink_impl.h index fd6d70f84c..085ebf622e 100644 --- a/src/mixed_signal_sink_impl.h +++ b/src/mixed_signal_sink_impl.h @@ -36,6 +36,7 @@ class mixed_signal_sink_impl : public mixed_signal_sink void clean_buffers() override; void set_nsamps(int newsize) override; void set_displayOneBuffer(bool display) override; + void set_update_time(double t) override; private: void _adjust_tags(int adj); diff --git a/src/movingaverage.cpp b/src/movingaverage.cpp new file mode 100644 index 0000000000..ed0be4f4f8 --- /dev/null +++ b/src/movingaverage.cpp @@ -0,0 +1,36 @@ +#include "movingaverage.h" + +MovingAverage::MovingAverage() +{ + sum = 0; +} + +int MovingAverage::getCapacity() const +{ + return capacity; +} + +void MovingAverage::setCapacity(int newCapacity) +{ + capacity = newCapacity; +} + +const QVector &MovingAverage::getHistory() const +{ + return history; +} + +double MovingAverage::pushValueReturnAverage(double newVal){ + sum+=newVal; + if(history.count() == capacity && capacity > 0) { + sum-=history.front(); + history.pop_front(); + } + history.push_back(newVal); + return (sum/(double)history.count()); +} + +void MovingAverage::clearHistory() { + history.clear(); + sum = 0; +} diff --git a/src/movingaverage.h b/src/movingaverage.h new file mode 100644 index 0000000000..6df37c2f32 --- /dev/null +++ b/src/movingaverage.h @@ -0,0 +1,24 @@ +#ifndef MOVINGAVERAGE_H +#define MOVINGAVERAGE_H + +#include + +class MovingAverage +{ +public: + MovingAverage(); + double pushValueReturnAverage(double newVal); + + int getCapacity() const; + void setCapacity(int newCapacity); + void clearHistory(); + const QVector &getHistory() const; + +private: + QVector history; + int capacity; + double sum; + +}; + +#endif // MOVINGAVERAGE_H diff --git a/src/network_analyzer.cpp b/src/network_analyzer.cpp index bb223ed04c..67a1059cb2 100644 --- a/src/network_analyzer.cpp +++ b/src/network_analyzer.cpp @@ -19,10 +19,10 @@ */ #include "logging_categories.h" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include "network_analyzer.hpp" #include "signal_generator.hpp" -#include "spinbox_a.hpp" +#include "gui/spinbox_a.hpp" #include "hardware_trigger.hpp" #include "ui_network_analyzer.h" #include "filemanager.h" @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -422,18 +423,73 @@ NetworkAnalyzer::NetworkAnalyzer(struct iio_context *ctx, Filter *filt, 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); + // plot widget + QWidget* centralWidget = new QWidget(this); + QGridLayout* gridLayout = new QGridLayout(centralWidget); + gridLayout->setContentsMargins(9, 0, 0, 9); + gridLayout->setHorizontalSpacing(10); + gridLayout->setVerticalSpacing(0); - 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); + gridLayout->addWidget(bufferPreviewer, 0, 1, 1, 1); + gridLayout->addWidget(ui->statusWidget, 1, 1, 1, 1); + gridLayout->addWidget(m_dBgraph.rightHandlesArea(), 0, 2, 6, 1); + gridLayout->addWidget(m_dBgraph.topHandlesArea(), 2, 0, 1, 2); + gridLayout->addWidget(m_dBgraph.leftHandlesArea(), 3, 0, 1, 1); + gridLayout->addWidget(&m_dBgraph, 3, 1, 1, 1); + + gridLayout->addWidget(m_phaseGraph.topHandlesArea(), 4, 0, 1, 2); + gridLayout->addWidget(m_phaseGraph.leftHandlesArea(), 5, 0, 1, 1); + gridLayout->addWidget(&m_phaseGraph, 5, 1, 1, 1); + + gridLayout->addWidget(m_dBgraph.bottomHandlesArea(), 6, 0, 1, 3); + + centralWidget->setLayout(gridLayout); + + if(prefPanel->getCurrent_docking_enabled()) { + // bode graph + QMainWindow* bodeWindow = new QMainWindow(this); + bodeWindow->setCentralWidget(0); + bodeWindow->setWindowFlags(Qt::Widget); + ui->gridLayout_plots->addWidget(bodeWindow, 0, 0); + + QDockWidget* bodeDockWidget = DockerUtils::createDockWidget(bodeWindow, centralWidget); + bodeWindow->addDockWidget(Qt::LeftDockWidgetArea, bodeDockWidget); + + + // nyquist graph + QMainWindow* nyquistWindow = new QMainWindow(this); + nyquistWindow->setCentralWidget(0); + nyquistWindow->setWindowFlags(Qt::Widget); + + ui->stackedWidgetPage2->layout()->removeWidget(ui->xygraph); + ui->stackedWidgetPage2->layout()->addWidget(nyquistWindow); + + QDockWidget* nyquistDockWidget = DockerUtils::createDockWidget(nyquistWindow, ui->xygraph); + nyquistWindow->addDockWidget(Qt::LeftDockWidgetArea, nyquistDockWidget); + + + // nichols graph + QMainWindow* nicholsWindow = new QMainWindow(this); + nicholsWindow->setCentralWidget(0); + nicholsWindow->setWindowFlags(Qt::Widget); + + ui->stackedWidgetPage3->layout()->removeWidget(ui->nicholsgraph); + ui->stackedWidgetPage3->layout()->addWidget(nicholsWindow); + + QDockWidget* nicholsDockWidget = DockerUtils::createDockWidget(nicholsWindow, ui->nicholsgraph); + nicholsWindow->addDockWidget(Qt::LeftDockWidgetArea, nicholsDockWidget); + +#ifdef PLOT_MENU_BAR_ENABLED + DockerUtils::configureTopBar(bodeDockWidget); + DockerUtils::configureTopBar(nyquistDockWidget); + DockerUtils::configureTopBar(nicholsDockWidget); +#endif + } else { + gridLayout->setHorizontalSpacing(0); + gridLayout->setVerticalSpacing(6); + ui->gridLayout_plots->addWidget(centralWidget); + } - ui->gridLayout_plots->addWidget(m_dBgraph.bottomHandlesArea(), 6, 0, 1, 3); m_phaseGraph.enableXaxisLabels(); m_dBgraph.enableXaxisLabels(); @@ -552,14 +608,18 @@ NetworkAnalyzer::NetworkAnalyzer(struct iio_context *ctx, Filter *filt, api->load(*settings); api->js_register(engine); - connect((m_dBgraph.getAxisWidget(QwtPlot::xTop)), SIGNAL(scaleDivChanged()), + connect((m_dBgraph.getAxisWidget(QwtAxis::XTop)), SIGNAL(scaleDivChanged()), &m_phaseGraph, SLOT(scaleDivChanged())); - connect((m_phaseGraph.getAxisWidget(QwtPlot::xTop)), SIGNAL(scaleDivChanged()), + connect((m_phaseGraph.getAxisWidget(QwtAxis::XTop)), SIGNAL(scaleDivChanged()), &m_dBgraph, SLOT(scaleDivChanged())); connect(&m_dBgraph,SIGNAL(resetZoom()),&m_phaseGraph,SLOT(onResetZoom())); connect(&m_phaseGraph,SIGNAL(resetZoom()),&m_dBgraph,SLOT(onResetZoom())); +#ifdef __ANDROID__ + connect(&m_dBgraph, &dBgraph::zoomOut, &m_phaseGraph, &dBgraph::onZoomOut); + connect(&m_phaseGraph, &dBgraph::zoomOut, &m_dBgraph, &dBgraph::onZoomOut); +#endif connect(ui->rightMenu, &MenuAnim::finished, this, &NetworkAnalyzer::rightMenuFinished); @@ -1632,6 +1692,8 @@ void NetworkAnalyzer::startStop(bool pressed) } m_running = pressed; + m_dBgraph.startStop(pressed); + m_phaseGraph.startStop(pressed); bool shouldClear = false; if (QObject::sender() == ui->runSingleWidget) { @@ -1777,6 +1839,9 @@ void NetworkAnalyzer::toggleCursors(bool en) void NetworkAnalyzer::readPreferences() { + bool showFps = prefPanel->getShow_plot_fps(); + m_dBgraph.setVisibleFpsLabel(showFps); + m_phaseGraph.setVisibleFpsLabel(showFps); m_dBgraph.setShowZero(prefPanel->getNa_show_zero()); m_phaseGraph.setShowZero(prefPanel->getNa_show_zero()); ui->instrumentNotes->setVisible(prefPanel->getInstrumentNotesActive()); diff --git a/src/network_analyzer.hpp b/src/network_analyzer.hpp index 26a699645d..9dbd21eb76 100644 --- a/src/network_analyzer.hpp +++ b/src/network_analyzer.hpp @@ -21,7 +21,7 @@ #ifndef SCOPY_NETWORK_ANALYZER_HPP #define SCOPY_NETWORK_ANALYZER_HPP -#include "spinbox_a.hpp" +#include "gui/spinbox_a.hpp" #include "apiObject.hpp" #include "iio_manager.hpp" #include "signal_sample.hpp" @@ -29,7 +29,7 @@ #include "dbgraph.hpp" #include "handles_area.hpp" #include -#include "customPushButton.hpp" +#include "gui/customPushButton.hpp" #include "scroll_filter.hpp" #include #include @@ -58,7 +58,7 @@ #include "TimeDomainDisplayPlot.h" #include "networkanalyzerbufferviewer.h" -#include "startstoprangewidget.h" +#include "gui/startstoprangewidget.h" extern "C" { struct iio_context; diff --git a/src/networkanalyzerbufferviewer.cpp b/src/networkanalyzerbufferviewer.cpp index cacda75e42..b8c7e2cd72 100644 --- a/src/networkanalyzerbufferviewer.cpp +++ b/src/networkanalyzerbufferviewer.cpp @@ -194,7 +194,9 @@ void NetworkAnalyzerBufferViewer::sendBufferToOscilloscope() d_osc->add_ref_waveform("NA1", d_currentXdata, yData1, d_data[index].first.sampleRate); d_osc->add_ref_waveform("NA2", d_currentXdata, yData2, d_data[index].second.sampleRate); +#ifndef __ANDROID__ d_osc->detached(); +#endif } void NetworkAnalyzerBufferViewer::btnPreviousClicked() @@ -218,12 +220,12 @@ void NetworkAnalyzerBufferViewer::_setupPlot() d_plot->insertLegend(nullptr); d_plot->setUsingLeftAxisScales(false); - int nrAxes = d_plot->axesCount(QwtPlot::yLeft); + int nrAxes = d_plot->axesCount(QwtAxis::YLeft); for (int i = 0; i < nrAxes; ++i) { - d_plot->setAxisVisible(QwtAxisId(QwtPlot::yLeft, i), + d_plot->setAxisVisible(QwtAxisId(QwtAxis::YLeft, i), false); } - d_plot->setAxisVisible(QwtAxisId(QwtPlot::xBottom, 0), + d_plot->setAxisVisible(QwtAxisId(QwtAxis::XBottom, 0), false); d_plot->plotLayout()->setAlignCanvasToScales(true); diff --git a/src/nyquistGraph.cpp b/src/nyquistGraph.cpp index 078e634ed7..6023c65254 100644 --- a/src/nyquistGraph.cpp +++ b/src/nyquistGraph.cpp @@ -43,14 +43,14 @@ namespace adiscope { NyquistSamplesArray() : QwtArraySeriesData() {} void addSample(const QwtPointPolar& point) { - d_samples.push_back(point); + m_samples.push_back(point); } - void clear() { d_samples.clear(); } - void reserve(unsigned int nb) { d_samples.reserve(nb); } + void clear() { m_samples.clear(); } + void reserve(unsigned int nb) { m_samples.reserve(nb); } QRectF boundingRect() const; QwtPointPolar sample(size_t index) const { - return d_samples.at(index); + return m_samples.at(index); } }; } @@ -65,8 +65,8 @@ QRectF NyquistSamplesArray::boundingRect() const { double xmin = 0.0, xmax = 0.0, ymin = 0.0, ymax = 0.0; - for (auto it = d_samples.begin(); - it != d_samples.end(); ++it) { + for (auto it = m_samples.begin(); + it != m_samples.end(); ++it) { double point_x = it->radius() * cos(it->azimuth()); double point_y = it->radius() * sin(it->azimuth()); @@ -256,6 +256,15 @@ void NyquistGraph::mousePressEvent(QMouseEvent *event) return; } +#ifdef __ANDROID__ + if (event->type() == QEvent::MouseButtonDblClick) { + zoomer->cancelZoom(); + QApplication::setOverrideCursor(Qt::CrossCursor); + QwtPolarPlot::mousePressEvent(event); + return; + } +#endif + if (zoomer->isZoomed()) QApplication::setOverrideCursor(Qt::ClosedHandCursor); diff --git a/src/osc_scale_zoomer.cpp b/src/osc_scale_zoomer.cpp index aeab9d2b84..0a169f4720 100644 --- a/src/osc_scale_zoomer.cpp +++ b/src/osc_scale_zoomer.cpp @@ -49,9 +49,9 @@ OscScaleZoomer::~OscScaleZoomer() QwtText OscScaleZoomer::trackerText(const QPoint& pos) const { const OscScaleDraw *draw_x = static_cast( - plot()->axisScaleDraw(QwtPlot::xTop)); + plot()->axisScaleDraw(QwtAxis::XTop)); const OscScaleDraw *draw_y = static_cast( - plot()->axisScaleDraw(QwtPlot::yLeft)); + plot()->axisScaleDraw(QwtAxis::YLeft)); QPointF dp = QwtPlotZoomer::invTransform(pos); QString text; diff --git a/src/oscilloscope.cpp b/src/oscilloscope.cpp index b7be9c4057..252b52de2a 100644 --- a/src/oscilloscope.cpp +++ b/src/oscilloscope.cpp @@ -39,6 +39,9 @@ #include #include #include +#include +#include +#include /* libm2k includes */ #include @@ -47,25 +50,26 @@ /* Local includes */ #include "logging_categories.h" #include "adc_sample_conv.hpp" -#include "customPushButton.hpp" +#include "gui/customPushButton.hpp" #include "oscilloscope.hpp" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include "measurement_gui.h" -#include "measure_settings.h" +#include "gui/measure_settings.h" #include "statistic_widget.h" #include "state_updater.h" #include "osc_capture_params.hpp" #include "buffer_previewer.hpp" #include "config.h" -#include "customplotpositionbutton.h" -#include "channel_widget.hpp" +#include "gui/customplotpositionbutton.h" +#include "gui/channel_widget.hpp" #include "signal_sample.hpp" #include "filemanager.h" #include "scopyExceptionHandler.h" #include "oscilloscope_api.hpp" #include "mixed_signal_sink.h" +#include -#include "runsinglewidget.h" +#include "gui/runsinglewidget.h" /* Generated UI */ #include "ui_channel_settings.h" @@ -107,7 +111,7 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, ui(new Ui::Oscilloscope), trigger_settings(m_m2k_analogin), measure_settings(nullptr), - plot(this, false, 16, 10), + plot(this, false, 16, 10, new TimePrefixFormatter, new MetricPrefixFormatter), fft_plot(nb_channels, this), xy_plot(nb_channels / 2, this), hist_plot(nb_channels, this), @@ -171,6 +175,9 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, fft_plot_size = 1024; fft_plot.setNumPoints(0); + fft_plot.setBtmHorAxisUnit("Hz"); + fft_plot.setLeftVertAxisUnit("dB"); + last_set_sample_count = 0; last_set_time_pos = 0; @@ -190,6 +197,13 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, this->qt_time_block->set_trigger_mode(TRIG_MODE_TAG, 0, "buffer_start"); + // get target fps from preferences + double targetFps = getScopyPreferences()->getTarget_fps(); + qt_time_block->set_update_time(1.0/targetFps); + qt_fft_block->set_update_time(1.0/targetFps); + qt_hist_block->set_update_time(1.0/targetFps); + qt_xy_block->set_update_time(1.0/targetFps); + // Prevent the application from hanging while waiting for a trigger condition m_m2k_context->setTimeout(UINT_MAX); @@ -312,27 +326,157 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, buffer_previewer->setCursorPos(0.5); - /* Plot layout */ + + // Build central widget + QWidget* centralWidget = new QWidget(this); + QVBoxLayout* vLayout = new QVBoxLayout(centralWidget); + vLayout->setContentsMargins(0, 0, 0, 0); + vLayout->setSpacing(0); + + // add the buffer previewer + ui->plot_and_buffPreviewer->removeWidget(ui->hLayoutBufferPreview); + vLayout->addWidget(ui->hLayoutBufferPreview); + + // add plot elements + QWidget* plotWidget = new QWidget(this); + gridPlot = new QGridLayout(plotWidget); + gridPlot->setVerticalSpacing(0); + gridPlot->setHorizontalSpacing(0); + gridPlot->setContentsMargins(9, 0, 9, 0); + plotWidget->setLayout(gridPlot); QSpacerItem *plotSpacer = new QSpacerItem(0, 5, QSizePolicy::Fixed, QSizePolicy::Fixed); - ui->gridLayoutPlot->addWidget(measurePanel, 0, 1, 1, 1); - ui->gridLayoutPlot->addWidget(plot.topArea(), 1, 0, 1, 4); - ui->gridLayoutPlot->addWidget(plot.topHandlesArea(), 2, 0, 1, 4); + gridPlot->addWidget(measurePanel, 0, 1, 1, 1); + gridPlot->addWidget(plot.topArea(), 1, 0, 1, 4); + gridPlot->addWidget(plot.topHandlesArea(), 2, 0, 1, 4); + + gridPlot->addWidget(plot.leftHandlesArea(), 1, 0, 4, 1); + gridPlot->addWidget(plot.rightHandlesArea(), 1, 3, 4, 1); - ui->gridLayoutPlot->addWidget(plot.leftHandlesArea(), 1, 0, 4, 1); - ui->gridLayoutPlot->addWidget(plot.rightHandlesArea(), 1, 3, 4, 1); + gridPlot->addWidget(&plot, 3, 1, 1, 1); + gridPlot->addWidget(&hist_plot, 3, 2, 1, 1); - ui->gridLayoutPlot->addWidget(&plot, 3, 1, 1, 1); - ui->gridLayoutPlot->addWidget(&hist_plot, 3, 2, 1, 1); + gridPlot->addWidget(plot.bottomHandlesArea(), 4, 0, 1, 4); + gridPlot->addItem(plotSpacer, 5, 0, 1, 4); + gridPlot->addWidget(statisticsPanel, 6, 1, 1, 1); - ui->gridLayoutPlot->addWidget(plot.bottomHandlesArea(), 4, 0, 1, 4); - ui->gridLayoutPlot->addItem(plotSpacer, 5, 0, 1, 4); - ui->gridLayoutPlot->addWidget(statisticsPanel, 6, 1, 1, 1); + vLayout->addWidget(plotWidget); + centralWidget->setLayout(vLayout); + ui->plot_and_scales->removeWidget(ui->scalesWidget); + vLayout->addWidget(ui->scalesWidget); + + // hide fixed containers + ui->container_fft_plot->hide(); + ui->xy_plot_container->hide(); + + // add space for histogram plot.setBonusWidthForHistogram(25); + if(prefPanel->getCurrent_docking_enabled()) { + ui->histogram_container->hide(); + + // main window for all dock widgets + QMainWindow* mainWindow = new QMainWindow(this); + mainWindow->setCentralWidget(0); + mainWindow->setWindowFlags(Qt::Widget); + ui->gridLayoutPlot->addWidget(mainWindow, 0, 0, 1, 1); + + // time domain plot dock + QDockWidget* plotDockWidget = DockerUtils::createDockWidget(mainWindow, centralWidget, "TimeDomain"); + + + // necessary to move around the dockWidgets + centralWidget->setMinimumHeight(50); + centralWidget->setMinimumWidth(50); + + fft_plot.setMinimumHeight(50); + fft_plot.setMinimumWidth(50); + + xy_plot.setMinimumHeight(50); + xy_plot.setMinimumWidth(50); + + + // histogram widget + histWidget = new QWidget(this); + QVBoxLayout* histLayout = new QVBoxLayout(histWidget); + histWidget->setLayout(histLayout); + + // histogram dock + histDockWidget = DockerUtils::createDockWidget(mainWindow, histWidget, "Histogram"); + histDockWidget->hide(); + + + // fft dock + fftDockWidget = DockerUtils::createDockWidget(mainWindow, &fft_plot, "FFT"); + fftDockWidget->hide(); + + + // xy widget + QWidget *xyWidget = new QWidget(this); + QGridLayout *gridL = new QGridLayout(xyWidget); + gridL->setVerticalSpacing(0); + gridL->setHorizontalSpacing(0); + gridL->setContentsMargins(0, 0, 0, 0); + + gridL->addWidget(&xy_plot, 1, 0); + gridL->addWidget(gridL->itemAtPosition(1, 0)->widget(), 2, 0); + xyWidget->setLayout(gridL); + + // xy dock + xyDockWidget = DockerUtils::createDockWidget(mainWindow, xyWidget, "XY"); + xyDockWidget->hide(); + + + // arange all dockers +#ifdef __ANDROID__ + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, fftDockWidget); + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, histDockWidget); + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, plotDockWidget); + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, xyDockWidget); + + mainWindow->tabifyDockWidget(plotDockWidget, histDockWidget); + mainWindow->tabifyDockWidget(plotDockWidget, fftDockWidget); + mainWindow->tabifyDockWidget(plotDockWidget, xyDockWidget); +#else + mainWindow->addDockWidget(Qt::RightDockWidgetArea, fftDockWidget); + mainWindow->addDockWidget(Qt::RightDockWidgetArea, xyDockWidget); + mainWindow->tabifyDockWidget(fftDockWidget, xyDockWidget); + + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, histDockWidget); + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, plotDockWidget); + mainWindow->tabifyDockWidget(plotDockWidget, histDockWidget); +#endif + +#ifdef PLOT_MENU_BAR_ENABLED + DockerUtils::configureTopBar(plotDockWidget); + DockerUtils::configureTopBar(histDockWidget); + DockerUtils::configureTopBar(fftDockWidget); + DockerUtils::configureTopBar(xyDockWidget); +#endif + + } else { + ui->gridLayoutPlot->addWidget(centralWidget, 1, 0, 1, 1); + ui->hlayout_fft->addWidget(&fft_plot); + + QGridLayout *gridL = static_cast(ui->xy_plot_container->layout()); + QWidget *w = gridL->itemAtPosition(1, 0)->widget(); + gridL->addWidget(&xy_plot, 1, 0); + gridL->addWidget(w, 2, 0); + + fft_plot.setMinimumHeight(250); + fft_plot.setMinimumWidth(500); + } + + hist_plot.setMinimumHeight(60); + hist_plot.setMinimumWidth(25); + hist_plot.setMaximumWidth(25); + + // xy_plot.setMinimumHeight(50); + // xy_plot.setMinimumWidth(50); + /* Default plot settings */ plot.setSampleRate(active_sample_rate, 1, ""); plot.setActiveVertAxis(0); @@ -343,8 +487,8 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, for (unsigned int i = 0; i < nb_channels; i++) { plot.Curve(i)->setAxes( - QwtAxisId(QwtPlot::xBottom, 0), - QwtAxisId(QwtPlot::yLeft, i)); + QwtAxisId(QwtAxis::XBottom, 0), + QwtAxisId(QwtAxis::YLeft, i)); plot.addZoomer(i); probe_attenuation.push_back(1); auto multiply = gr::blocks::multiply_const_ff::make(1); @@ -360,25 +504,15 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, iio->unlock(); - plot.levelTriggerA()->setMobileAxis(QwtAxisId(QwtPlot::yLeft, 0)); + plot.levelTriggerA()->setMobileAxis(QwtAxisId(QwtAxis::YLeft, 0)); plot.setTriggerAEnabled(trigger_settings.analogEnabled()); plot.levelTriggerA()->setPosition(trigger_settings.level()); // TO DO: Give user the option to make these axes visible - plot.enableAxis(QwtPlot::yLeft, false); - plot.enableAxis(QwtPlot::xBottom, false); + plot.setAxisVisible(QwtAxis::YLeft, false); + plot.setAxisVisible(QwtAxis::XBottom, false); plot.setUsingLeftAxisScales(false); - fft_plot.setMinimumHeight(250); - fft_plot.setMinimumWidth(500); - - hist_plot.setMinimumHeight(60); - hist_plot.setMinimumWidth(25); - hist_plot.setMaximumWidth(25); - - xy_plot.setMinimumHeight(50); - xy_plot.setMinimumWidth(50); - xy_plot.setVertUnitsPerDiv(5); xy_plot.setHorizUnitsPerDiv(5); @@ -394,17 +528,6 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, xy_plot.setLineColor(0, QColor("#4a64ff")); - ui->hlayout_fft->addWidget(&fft_plot); - ui->container_fft_plot->hide(); - - QGridLayout *gridL = static_cast( - ui->xy_plot_container->layout()); - QWidget *w = gridL->itemAtPosition(1, 0)->widget(); - gridL->addWidget(&xy_plot, 1, 0); - gridL->addWidget(w, 2, 0); - - ui->xy_plot_container->hide(); - ui->rightMenu->setMaximumWidth(0); // Controls for scale/division and position controls (Horizontal & Vertical) @@ -701,10 +824,9 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, resetHistogramDataPoints(); }); - connect(ch_ui->probe_attenuation, QOverload::of(&QComboBox::currentIndexChanged), - [=](int index){ - double value = 0.1 * (std::pow(10, index)); + connect(ch_ui->probe_attenuation_value, &QLineEdit::textChanged, this, [=](){ + double value = ch_ui->probe_attenuation_value->text().toDouble(); probe_attenuation[current_ch_widget] = value; if (current_channel == current_ch_widget) { plot.setDisplayScale(probe_attenuation[current_ch_widget]); @@ -836,6 +958,12 @@ Oscilloscope::Oscilloscope(struct iio_context *ctx, Filter *filt, ui->btnHelp->setUrl("https://wiki.analog.com/university/tools/m2k/scopy/oscilloscope"); +#ifdef __ANDROID__ + ui->btnAddMath->setIconSize(QSize(24, 24)); +#endif + + plot.replot(); + plot.zoomBaseUpdate(true); } int Oscilloscope::binSearchPointOnXaxis(double time) @@ -866,7 +994,7 @@ int Oscilloscope::binSearchPointOnXaxis(double time) void Oscilloscope::resetHistogramDataPoints() { - QwtInterval xBot = plot.axisInterval(QwtPlot::xBottom); + QwtInterval xBot = plot.axisInterval(QwtAxis::XBottom); double zoomMinTime = xBot.minValue(); double zoomMaxTime = xBot.maxValue(); @@ -1008,8 +1136,8 @@ void Oscilloscope::add_ref_waveform(QString name, QVector xData, QVector probe_attenuation.push_back(1); plot.Curve(curve_id)->setAxes( - QwtAxisId(QwtPlot::xBottom, 0), - QwtAxisId(QwtPlot::yLeft, curve_id)); + QwtAxisId(QwtAxis::XBottom, 0), + QwtAxisId(QwtAxis::YLeft, curve_id)); plot.Curve(curve_id)->setTitle("REF " + QString::number(nb_ref_channels + 1)); plot.addZoomer(curve_id); plot.replot(); @@ -1029,7 +1157,6 @@ void Oscilloscope::add_ref_waveform(QString name, QVector xData, QVector plot.showYAxisWidget(curve_id, true); plot.setVertUnitsPerDiv(1, curve_id); // force v/div to 1 - plot.zoomBaseUpdate(); init_selected_measurements(curve_id, {0, 1, 4, 5}); plot.computeMeasurementsForChannel(curve_id, sampleRate); @@ -1127,8 +1254,8 @@ void Oscilloscope::add_ref_waveform(unsigned int chIdx) probe_attenuation.push_back(1); plot.Curve(curve_id)->setAxes( - QwtAxisId(QwtPlot::xBottom, 0), - QwtAxisId(QwtPlot::yLeft, curve_id)); + QwtAxisId(QwtAxis::XBottom, 0), + QwtAxisId(QwtAxis::YLeft, curve_id)); plot.Curve(curve_id)->setTitle("REF " + QString::number(nb_ref_channels + 1)); plot.addZoomer(curve_id); plot.replot(); @@ -1148,7 +1275,6 @@ void Oscilloscope::add_ref_waveform(unsigned int chIdx) plot.showYAxisWidget(curve_id, true); plot.setVertUnitsPerDiv(1, curve_id); // force v/div to 1 - plot.zoomBaseUpdate(); init_selected_measurements(curve_id, {0, 1, 4, 5}); } @@ -1250,6 +1376,11 @@ void Oscilloscope::settingsLoaded() void Oscilloscope::readPreferences() { + bool showFps = prefPanel->getShow_plot_fps(); + plot.setVisibleFpsLabel(showFps); + xy_plot.setVisibleFpsLabel(showFps); + fft_plot.setVisibleFpsLabel(showFps); + hist_plot.setVisibleFpsLabel(showFps); plot.setGraticuleEnabled(prefPanel->getOsc_graticule_enabled()); ui->instrumentNotes->setVisible(prefPanel->getInstrumentNotesActive()); @@ -1278,6 +1409,12 @@ void Oscilloscope::readPreferences() update_chn_settings_panel(current_ch_widget); setFilteringEnabled(prefPanel->getOsc_filtering_enabled()); + double fps = prefPanel->getTarget_fps(); + iio->set_data_rate(std::max(fps, 15.0)); // minimum 15 buffers/second + qt_time_block->set_update_time(1.0/fps); + qt_fft_block->set_update_time(1.0/fps);; + qt_xy_block->set_update_time(1.0/fps);; + qt_hist_block->set_update_time(1.0/fps);; } @@ -1316,7 +1453,12 @@ void Oscilloscope::enableMixedSignalView(ChannelWidget *cw) mixed_sink = mixed_signal_sink::make(m_logicAnalyzer, &this->plot, active_sample_count); - mixed_source = gr::m2k::mixed_signal_source::make_from(m_m2k_context, active_sample_count); + double targetFps = getScopyPreferences()->getTarget_fps(); + + // this was buggy from the beginning - when using autotriggering, mixed signal acquisition restarts + // with wrong trigger settings because autotriggering switches inbetween always and actual trigger mode + // workaround consists in using 2 kernel buffers before restarting the acquisition + mixed_source = gr::m2k::mixed_signal_source::make_from(m_m2k_context, active_sample_count, targetFps, 2); if (iioStarted) { // enable the mixed_source in the iio_manager @@ -1506,6 +1648,7 @@ void Oscilloscope::init_channel_settings() }); } + void Oscilloscope::activateAcCoupling(int i) { double alpha, beta; @@ -2322,7 +2465,7 @@ void Oscilloscope::add_math_channel(const std::string& function) } auto rail = gr::analog::rail_ff::make(MIN_MATH_RANGE, MAX_MATH_RANGE); - auto math = scopy::iio_math::make(function, nb_channels); + auto math = gr::scopy::iio_math::make(function, nb_channels); unsigned int curve_id = nb_channels + nb_math_channels + nb_ref_channels; unsigned int curve_number = find_curve_number(); @@ -2336,6 +2479,8 @@ void Oscilloscope::add_math_channel(const std::string& function) noZoomXAxisWidth * getSampleRate() / m_m2k_analogin->getOversamplingRatio(), getSampleRate() / m_m2k_analogin->getOversamplingRatio(), name, 1, (QObject *)&plot); + double targetFps = getScopyPreferences()->getTarget_fps(); + math_sink->set_update_time(1.0/targetFps); /* Add the math block and the math scope sink into a container, so that * we can disconnect them when removing the math channel later */ auto math_pair = QPair( @@ -2410,8 +2555,8 @@ void Oscilloscope::add_math_channel(const std::string& function) ui->chn_scales->addWidget(label); plot.Curve(curve_id)->setAxes( - QwtAxisId(QwtPlot::xBottom, 0), - QwtAxisId(QwtPlot::yLeft, curve_id)); + QwtAxisId(QwtAxis::XBottom, 0), + QwtAxisId(QwtAxis::YLeft, curve_id)); plot.Curve(curve_id)->setTitle("M " + QString::number(curve_number + 1)); plot.addZoomer(curve_id); plot.replot(); @@ -2635,8 +2780,8 @@ void Oscilloscope::onChannelWidgetDeleteClicked() i < nb_channels + nb_math_channels + nb_ref_channels; i++) { /* Update the curve-to-axis map */ plot.Curve(i)->setAxes( - QwtAxisId(QwtPlot::xBottom, 0), - QwtAxisId(QwtPlot::yLeft, i)); + QwtAxisId(QwtAxis::XBottom, 0), + QwtAxisId(QwtAxis::YLeft, i)); } onMeasurementSelectionListChanged(); @@ -2786,6 +2931,9 @@ void Oscilloscope::runStopToggled(bool checked) // Update trigger status m_running = checked; + plot.startStop(checked); + hist_plot.startStop(checked); + triggerUpdater->setEnabled(checked); } @@ -2795,8 +2943,8 @@ void Oscilloscope::setFFT_params(bool force) fft_plot.setSampleRate(getSampleRate(), 1, ""); double start = 0; double stop = getSampleRate() / 2; - fft_plot.setAxisScale(QwtPlot::xBottom, start, stop); - fft_plot.setAxisScale(QwtPlot::yLeft, -200, 0, 10); + fft_plot.setAxisScale(QwtAxis::XBottom, start, stop); + fft_plot.setAxisScale(QwtAxis::YLeft, -200, 0, 10); fft_plot.zoomBaseUpdate(); } } @@ -2877,9 +3025,19 @@ void Oscilloscope::onFFT_view_toggled(bool visible) iio->connect(ctm_blocks.at(i), 0, qt_fft_block, i); } - ui->container_fft_plot->show(); + if(prefPanel->getCurrent_docking_enabled()) { + fftDockWidget->show(); + } else { + ui->container_fft_plot->show(); + } } else { - ui->container_fft_plot->hide(); + + if(prefPanel->getCurrent_docking_enabled()) { + fftDockWidget->setFloating(false); + fftDockWidget->hide(); + } else { + ui->container_fft_plot->hide(); + } if (fft_is_visible && (fft_channels.size() > 0)) { for (unsigned int i = 0; i < nb_channels; i++) { @@ -2904,26 +3062,41 @@ void Oscilloscope::onHistogram_view_toggled(bool visible) { cancelZoom(); - if(!visible){ + if(!visible) { + if(prefPanel->getCurrent_docking_enabled()) { + histDockWidget->setFloating(false); + histDockWidget->hide(); + histWidget->layout()->removeWidget(&hist_plot); + } else { + ui->hist_layout->removeWidget(&hist_plot); + } + + gridPlot->addWidget(&hist_plot, 3, 2, 1, 1); + gridPlot->addWidget(plot.rightHandlesArea(), 1, 3, 4, 1); + hist_plot.setOrientation(Qt::Horizontal); hist_plot.setMinimumWidth(25); hist_plot.setMaximumWidth(25); hist_plot.setMaximumHeight(1000); - ui->hist_layout->removeWidget(&hist_plot); - ui->gridLayoutPlot->addWidget(&hist_plot, 3, 2, 1, 1); - ui->gridLayoutPlot->addWidget(plot.rightHandlesArea(), 1, 3, 4, 1); plot.setBonusWidthForHistogram(25); scaleHistogramPlot(); toggleMiniHistogramPlotVisible(miniHistogram); } else { + gridPlot->removeWidget(&hist_plot); + gridPlot->addWidget(plot.rightHandlesArea(), 1, 2, 3, 1); + + if(prefPanel->getCurrent_docking_enabled()) { + histWidget->layout()->addWidget(&hist_plot); + histDockWidget->show(); + } else { + ui->hist_layout->addWidget(&hist_plot); + } + hist_plot.setOrientation(Qt::Vertical); hist_plot.setMinimumWidth(plot.width()); hist_plot.setMaximumHeight(300); hist_plot.setMaximumWidth(2000); - ui->gridLayoutPlot->removeWidget(&hist_plot); - ui->gridLayoutPlot->addWidget(plot.rightHandlesArea(), 1, 2, 3, 1); - ui->hist_layout->addWidget(&hist_plot); plot.setBonusWidthForHistogram(0); scaleHistogramPlot(); hist_plot.setVisible(true); @@ -2936,6 +3109,9 @@ void Oscilloscope::onXY_view_toggled(bool visible) if (visible) { gsettings_ui->xySettings->show(); } else { + if(prefPanel->getCurrent_docking_enabled()) { + xyDockWidget->setFloating(false); + } gsettings_ui->xySettings->hide(); } @@ -2999,9 +3175,19 @@ void Oscilloscope::onXY_view_toggled(bool visible) if(!xy_is_visible) iio->connect(ftc, 0, this->qt_xy_block, 0); - ui->xy_plot_container->show(); + if(prefPanel->getCurrent_docking_enabled()) { + xyDockWidget->show(); + } else { + ui->xy_plot_container->show(); + } } else { - ui->xy_plot_container->hide(); + if(prefPanel->getCurrent_docking_enabled()) { + xyDockWidget->setFloating(false); + xyDockWidget->hide(); + } else { + ui->xy_plot_container->hide(); + } + // Disconnect the XY section from the running flowgraph iio->disconnect(xy_channels.at(index_x).first, xy_channels.at(index_x).second, @@ -3067,7 +3253,7 @@ void adiscope::Oscilloscope::on_boxMeasure_toggled(bool on) void Oscilloscope::onTriggerSourceChanged(int chnIdx) { - plot.levelTriggerA()->setMobileAxis(QwtAxisId(QwtPlot::yLeft, chnIdx)); + plot.levelTriggerA()->setMobileAxis(QwtAxisId(QwtAxis::YLeft, chnIdx)); trigger_settings.setChannelAttenuation(probe_attenuation[chnIdx]); if (chnAcCoupled.at(chnIdx)) { deactivateAcCouplingTrigger(); @@ -3127,7 +3313,7 @@ void adiscope::Oscilloscope::onChannelWidgetEnabled(bool en) hist_plot.enableChannel(id, en); if (id < nb_channels) { - m_m2k_analogin->enableChannel(id, en); + runInHwThreadPool( m_m2k_analogin->enableChannel(id, en);); } if (en) { @@ -3287,8 +3473,6 @@ void adiscope::Oscilloscope::onVertScaleValueChanged(double value) cancelZoom(); if (value != plot.VertUnitsPerDiv(current_ch_widget)) { plot.setVertUnitsPerDiv(value, current_ch_widget); - plot.replot(); - plot.zoomBaseUpdate(); } voltsPosition->setStep(value / 10); @@ -3300,9 +3484,8 @@ void adiscope::Oscilloscope::onVertScaleValueChanged(double value) xy_plot.setHorizUnitsPerDiv(value); } if (current_ch_widget == index_y) { - xy_plot.setVertUnitsPerDiv(value, QwtPlot::yLeft); + xy_plot.setVertUnitsPerDiv(value, QwtAxis::YLeft); } - xy_plot.replot(); xy_plot.zoomBaseUpdate(); if (current_ch_widget < nb_channels) { @@ -3367,15 +3550,14 @@ void Oscilloscope::onCmbMemoryDepthChanged(QString value) setSinksDisplayOneBuffer(false); } - plot.replot(); plot.setXAxisNumPoints(bufferSize); plot.setHorizOffset(params.timePos); plot.setDataStartingPoint(active_trig_sample_count); plot.resetXaxisOnNextReceivedData(); - plot.zoomBaseUpdate(); + plot.cancelZoom(); if (zoom_level == 0) { - noZoomXAxisWidth = plot.axisInterval(QwtPlot::xBottom).width(); + noZoomXAxisWidth = plot.axisInterval(QwtAxis::XBottom).width(); } setFFT_params(true); @@ -3465,10 +3647,8 @@ void adiscope::Oscilloscope::onHorizScaleValueChanged(double value) plot.replot(); plot.setDataStartingPoint(active_trig_sample_count); plot.resetXaxisOnNextReceivedData(); - plot.zoomBaseUpdate(); plot.setXAxisNumPoints(0); - hist_plot.zoomBaseUpdate(); hist_plot.replot(); ch_ui->cmbMemoryDepth->setCurrentIndex(0); @@ -3488,7 +3668,7 @@ void adiscope::Oscilloscope::onHorizScaleValueChanged(double value) } if (zoom_level == 0) { - noZoomXAxisWidth = plot.axisInterval(QwtPlot::xBottom).width(); + noZoomXAxisWidth = plot.axisInterval(QwtAxis::XBottom).width(); } /* Reconfigure the GNU Radio block to receive a different number of samples */ @@ -3562,7 +3742,7 @@ bool adiscope::Oscilloscope::gainUpdateNeeded() double offset = plot.VertOffset(current_ch_widget); QwtInterval hw_input_itv(-2.5 + offset, 2.5 + offset); QwtInterval plot_vert_itv = plot.axisScaleDiv( - QwtAxisId(QwtPlot::yLeft, current_ch_widget)).interval(); + QwtAxisId(QwtAxis::YLeft, current_ch_widget)).interval(); if (plot_vert_itv.minValue() < hw_input_itv.minValue() || plot_vert_itv.maxValue() > hw_input_itv.maxValue() || @@ -3583,8 +3763,8 @@ void Oscilloscope::updateXyPlotScales() { int x = gsettings_ui->cmb_x_channel->currentIndex(); int y = gsettings_ui->cmb_y_channel->currentIndex(); - auto xInterval = plot.axisInterval(QwtAxisId(QwtPlot::yLeft, x)); - auto yInterval = plot.axisInterval(QwtAxisId(QwtPlot::yLeft, y)); + auto xInterval = plot.axisInterval(QwtAxisId(QwtAxis::YLeft, x)); + auto yInterval = plot.axisInterval(QwtAxisId(QwtAxis::YLeft, y)); xy_plot.set_axis(xInterval.minValue(), xInterval.maxValue(), yInterval.minValue(), yInterval.maxValue()); } @@ -3595,12 +3775,9 @@ void adiscope::Oscilloscope::onVertOffsetValueChanged(double value) if (value != -plot.VertOffset(current_ch_widget)) { plot.setVertOffset(-value, current_ch_widget); - plot.replot(); } - plot.zoomBaseUpdate(); scaleHistogramPlot(); - updateXyPlotScales(); // Switch between high and low gain modes only for the M2K channels @@ -3656,8 +3833,6 @@ void adiscope::Oscilloscope::onTimePositionChanged(double value) plot.setDataStartingPoint(active_trig_sample_count); plot.resetXaxisOnNextReceivedData(); - if (zoom_level == 0) - plot.zoomBaseUpdate(); if (started) { trigger_settings.setTriggerDelay(active_trig_sample_count); @@ -3902,21 +4077,15 @@ void Oscilloscope::update_chn_settings_panel(int id) } if (chn_widget->isMathChannel() || chn_widget->isReferenceChannel()) { - ch_ui->probe_attenuation->setVisible(false); + ch_ui->probe_attenuation_value->setVisible(false); ch_ui->probe_label->setVisible(false); ch_ui->label_3->setVisible(false); ch_ui->cmbMemoryDepth->setVisible(false); ch_ui->btnAutoset->setVisible(false); } else { - int index = 0; - double value = probe_attenuation[id]; - while (value > 0.1) { - value /= 10; - index++; - } - ch_ui->probe_attenuation->setCurrentIndex(index); - ch_ui->probe_attenuation->setVisible(true); + ch_ui->probe_attenuation_value->setText(QString::number(probe_attenuation[current_ch_widget])); + ch_ui->probe_attenuation_value->setVisible(true); ch_ui->probe_label->setVisible(true); ch_ui->label_3->setVisible(true); ch_ui->cmbMemoryDepth->setVisible(true); @@ -3992,7 +4161,7 @@ void Oscilloscope::editMathChannelFunction(int id, const std::string& new_functi std::string name = qname.toStdString(); auto rail = gr::analog::rail_ff::make(MIN_MATH_RANGE, MAX_MATH_RANGE); - auto math = scopy::iio_math::make(new_function, nb_channels); + auto math = gr::scopy::iio_math::make(new_function, nb_channels); bool started = isIioManagerStarted(); if (started) @@ -4197,7 +4366,8 @@ void Oscilloscope::measureUpdateValues() void Oscilloscope::measure_settings_init() { - measure_settings = new MeasureSettings(&plot, this); + QList* measure_obj = plot.getMeasurements(); + measure_settings = new MeasureSettings(measure_obj, this); int measure_panel = ui->stackedWidget->insertWidget(-1, measure_settings); @@ -4576,9 +4746,11 @@ void Oscilloscope::setupAutosetFreqSweep() qt_time_block->reset(); qt_time_block->clean_buffers(); if (m_m2k_analogin) { + runInHwThreadPool({ high_gain_modes[autosetChannel] = libm2k::analog::PLUS_MINUS_25V; trigger_settings.autoTriggerDisable(); trigger_settings.setTriggerEnable(false); + }); } autosetSampleRateCnt--; active_sample_rate = m_m2k_analogin->getAvailableSampleRates()[autosetSampleRateCnt]; @@ -4774,8 +4946,8 @@ void Oscilloscope::scaleHistogramPlot(bool newData) } for (int i = 0; i < nb_channels; i++) { - double min = plot.axisInterval(QwtAxisId(QwtPlot::yLeft, i)).minValue(); - double max = plot.axisInterval(QwtAxisId(QwtPlot::yLeft, i)).maxValue(); + double min = plot.axisInterval(QwtAxisId(QwtAxis::YLeft, i)).minValue(); + double max = plot.axisInterval(QwtAxisId(QwtAxis::YLeft, i)).maxValue(); hist_plot.setYaxisSpan(i, min, max); } @@ -4889,7 +5061,7 @@ void Oscilloscope::onTriggerModeChanged(int mode) void Oscilloscope::updateBufferPreviewer() { // Time interval within the plot canvas - QwtInterval plotInterval = plot.axisInterval(QwtPlot::xBottom); + QwtInterval plotInterval = plot.axisInterval(QwtAxis::XBottom); // Time interval that represents the captured data QwtInterval dataInterval(0.0, 0.0); @@ -4955,7 +5127,7 @@ void Oscilloscope::updateGainMode() double offset = plot.VertOffset(current_ch_widget); QwtInterval hw_input_itv(-2.5 + offset, 2.5 + offset); QwtInterval plot_vert_itv = plot.axisScaleDiv( - QwtAxisId(QwtPlot::yLeft, current_ch_widget)).interval(); + QwtAxisId(QwtAxis::YLeft, current_ch_widget)).interval(); auto chn = static_cast(current_ch_widget); // If max signal span that can be captured is smaller than the plot @@ -5006,7 +5178,8 @@ void Oscilloscope::setGainMode(uint chnIdx, libm2k::analog::M2K_RANGE gain_mode) if (ui->runSingleWidget->runButtonChecked()) { try { libm2k::analog::ANALOG_IN_CHANNEL chn = static_cast(chnIdx); - m_m2k_analogin->setRange(chn, gain_mode); + runInHwThreadPool( m_m2k_analogin->setRange(chn, gain_mode) ); + } catch (libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_OSCILLOSCOPE) << e.what(); @@ -5018,7 +5191,7 @@ void Oscilloscope::setGainMode(uint chnIdx, libm2k::analog::M2K_RANGE gain_mode) iio->freq_comp_filt[chnIdx][0]->set_high_gain(gain_mode); iio->freq_comp_filt[chnIdx][1]->set_high_gain(gain_mode); update_chn_settings_panel(chnIdx); - trigger_settings.updateHwVoltLevels(chnIdx); + runInHwThreadPool(trigger_settings.updateHwVoltLevels(chnIdx);); } void Oscilloscope::setChannelHwOffset(uint chnIdx, double offset) @@ -5027,7 +5200,8 @@ void Oscilloscope::setChannelHwOffset(uint chnIdx, double offset) if (ui->runSingleWidget->runButtonChecked()) { try { libm2k::analog::ANALOG_IN_CHANNEL chn = static_cast(chnIdx); - m_m2k_analogin->setVerticalOffset(chn, offset); + runInHwThreadPool(m_m2k_analogin->setVerticalOffset(chn, offset); ); + } catch (libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_OSCILLOSCOPE) << e.what(); @@ -5067,11 +5241,13 @@ void Oscilloscope::writeAllSettingsToHardware() if (m_m2k_analogin) { for (uint i = 0; i < nb_channels; i++) { try { - libm2k::analog::M2K_RANGE mode = high_gain_modes[i] ? - libm2k::analog::PLUS_MINUS_2_5V : libm2k::analog::PLUS_MINUS_25V; - libm2k::analog::ANALOG_IN_CHANNEL chn = static_cast(i); - m_m2k_analogin->setRange(chn, mode); - m_m2k_analogin->setVerticalOffset(chn, channel_offset[i]); + runInHwThreadPool( { + libm2k::analog::M2K_RANGE mode = high_gain_modes[i] ? + libm2k::analog::PLUS_MINUS_2_5V : libm2k::analog::PLUS_MINUS_25V; + libm2k::analog::ANALOG_IN_CHANNEL chn = static_cast(i); + m_m2k_analogin->setRange(chn, mode); + m_m2k_analogin->setVerticalOffset(chn, channel_offset[i]); + } ); } catch (libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_OSCILLOSCOPE) << e.what(); @@ -5086,7 +5262,7 @@ void Oscilloscope::writeAllSettingsToHardware() } // Writes all trigger settings to hardware - trigger_settings.setAdcRunningState(true); + runInHwThreadPool(trigger_settings.setAdcRunningState(true);); } void Oscilloscope::on_xyPlotLineType_toggled(bool checked) @@ -5109,10 +5285,10 @@ void Oscilloscope::setup_xy_channels() { int x = gsettings_ui->cmb_x_channel->currentIndex(); int y = gsettings_ui->cmb_y_channel->currentIndex(); - QWidget *xsw = xy_plot.axisWidget(QwtPlot::xBottom); + QWidget *xsw = xy_plot.axisWidget(QwtAxis::XBottom); xsw->setStyleSheet( QString("color: %1").arg(plot.getLineColor(x).name())); - QWidget *ysw = xy_plot.axisWidget(QwtPlot::yLeft); + QWidget *ysw = xy_plot.axisWidget(QwtAxis::YLeft); ysw->setStyleSheet( QString("color: %1").arg(plot.getLineColor(y).name())); @@ -5121,7 +5297,7 @@ void Oscilloscope::setup_xy_channels() onXY_view_toggled(true); xy_plot.setHorizUnitsPerDiv(plot.VertUnitsPerDiv(x)); - xy_plot.setVertUnitsPerDiv(plot.VertUnitsPerDiv(y), QwtPlot::yLeft); + xy_plot.setVertUnitsPerDiv(plot.VertUnitsPerDiv(y), QwtAxis::YLeft); updateXyPlotScales(); } @@ -5173,6 +5349,7 @@ void Oscilloscope::setSampleRate(double sample_rate) if (!m_m2k_analogin) { return; } + runInHwThreadPool( { try { auto maxSampleRate = m_m2k_analogin->getMaximumSamplerate(); if (m_filtering_enabled == false) { @@ -5186,6 +5363,7 @@ void Oscilloscope::setSampleRate(double sample_rate) HANDLE_EXCEPTION(e) qDebug(CAT_OSCILLOSCOPE) << e.what(); } + }); } diff --git a/src/oscilloscope.hpp b/src/oscilloscope.hpp index a12c9ea2fa..cebeef61d1 100644 --- a/src/oscilloscope.hpp +++ b/src/oscilloscope.hpp @@ -44,6 +44,7 @@ #include #include #include +#include /* Local includes */ #include "apiObject.hpp" @@ -57,11 +58,11 @@ #include "ConstellationDisplayPlot.h" #include "FftDisplayPlot.h" #include "HistogramDisplayPlot.h" -#include "spinbox_a.hpp" +#include "gui/spinbox_a.hpp" #include "trigger_settings.hpp" #include "plot_utils.hpp" #include "tool.hpp" -#include "osc_import_settings.h" +#include "gui/osc_import_settings.h" #include "math.hpp" #include "scroll_filter.hpp" #include "cancel_dc_offset_block.h" @@ -312,6 +313,12 @@ namespace adiscope { ExportSettings *exportSettings; CustomPlotPositionButton *cursorsPositionButton; + QGridLayout* gridPlot; + QDockWidget* fftDockWidget; + QDockWidget* xyDockWidget; + QDockWidget* histDockWidget; + QWidget* histWidget; + MouseWheelWidgetGuard *wheelEventGuard; QPair *math_pair; @@ -491,6 +498,10 @@ namespace adiscope { gr::m2k::mixed_signal_source::sptr mixed_source; mixed_signal_sink::sptr mixed_sink; QMetaObject::Connection showLogicAnalyzerTriggerConnection; + + QThreadPool hwSettingsThreadPool; + #define runInHwThreadPool(x) QtConcurrent::run(&hwSettingsThreadPool, std::bind([=]() { x; } )) + }; } #endif /* M2K_OSCILLOSCOPE_H */ diff --git a/src/oscilloscope_api.cpp b/src/oscilloscope_api.cpp index a5323e4323..fd900a27b9 100644 --- a/src/oscilloscope_api.cpp +++ b/src/oscilloscope_api.cpp @@ -20,11 +20,11 @@ #include "oscilloscope_api.hpp" #include "ui_oscilloscope.h" -#include "measure_settings.h" +#include "gui/measure_settings.h" #include "ui_measure_settings.h" #include "ui_cursors_settings.h" #include "ui_trigger_settings.h" -#include "channel_widget.hpp" +#include "gui/channel_widget.hpp" #include "ui_channel_settings.h" #include "ui_osc_general_settings.h" @@ -799,17 +799,8 @@ double Channel_API::getProbeAttenuation() const void Channel_API::setProbeAttenuation(double val) { int index = osc->channels_api.indexOf(this); - - int idx = std::log10(val / 0.1); - if (idx >= osc->ch_ui->probe_attenuation->count()) { - idx = osc->ch_ui->probe_attenuation->count() - 1; - } else if (idx <= 0) { - idx = 0; - } - val = std::pow(10, idx) * 0.1; - if (index == osc->current_ch_widget) { - osc->ch_ui->probe_attenuation->setCurrentIndex(idx); + osc->ch_ui->probe_attenuation_value->setText(QString::number(val)); } else { osc->probe_attenuation[index] = val; } diff --git a/src/oscilloscope_plot.cpp b/src/oscilloscope_plot.cpp index 7276a6f85d..f6ab8b9ce1 100644 --- a/src/oscilloscope_plot.cpp +++ b/src/oscilloscope_plot.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Analog Devices Inc. + * CopQwtAxis::YRight (c) 2019 Analog Devices Inc. * * This file is part of Scopy * (see http://www.github.com/analogdevicesinc/scopy). @@ -40,9 +40,9 @@ using namespace adiscope; /* * OscilloscopePlot class */ -OscilloscopePlot::OscilloscopePlot(QWidget *parent, bool isdBgraph, - unsigned int xNumDivs, unsigned int yNumDivs): - TimeDomainDisplayPlot(parent, isdBgraph, xNumDivs, yNumDivs) +OscilloscopePlot::OscilloscopePlot(QWidget *parent, bool isdBgraph, unsigned int xNumDivs, unsigned int yNumDivs + ,PrefixFormatter* pfXaxis, PrefixFormatter* pfYaxis): + TimeDomainDisplayPlot(parent, isdBgraph, xNumDivs, yNumDivs, pfXaxis, pfYaxis) { setYaxisUnit("V"); @@ -59,9 +59,9 @@ OscilloscopePlot::~OscilloscopePlot() /* * CapturePlot class */ -CapturePlot::CapturePlot(QWidget *parent, bool isdBgraph, - unsigned int xNumDivs, unsigned int yNumDivs): - OscilloscopePlot(parent, isdBgraph, xNumDivs, yNumDivs), +CapturePlot::CapturePlot(QWidget *parent, bool isdBgraph, unsigned int xNumDivs, unsigned int yNumDivs + ,PrefixFormatter* pfXaxis, PrefixFormatter* pfYaxis): + OscilloscopePlot(parent, isdBgraph, xNumDivs, yNumDivs, pfXaxis, pfYaxis), d_triggerAEnabled(false), d_triggerBEnabled(false), d_measurementsEnabled(false), @@ -189,7 +189,7 @@ CapturePlot::CapturePlot(QWidget *parent, bool isdBgraph, [=]() { double pos = d_timeTriggerHandle->position(); - QwtScaleMap xMap = this->canvasMap(QwtAxisId(QwtPlot::xBottom, 0)); + QwtScaleMap xMap = this->canvasMap(QwtAxisId(QwtAxis::XBottom, 0)); double min = -(xAxisNumDiv() / 2.0) * HorizUnitsPerDiv(); double max = (xAxisNumDiv() / 2.0) * HorizUnitsPerDiv(); @@ -361,7 +361,7 @@ CapturePlot::CapturePlot(QWidget *parent, bool isdBgraph, this, &CapturePlot::onDigitalChannelAdded); installEventFilter(this); - QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::xBottom); + QwtScaleWidget *scaleWidget = axisWidget(QwtAxis::XBottom); const int fmw = QFontMetrics(scaleWidget->font()).width("-XXX.XXX XX"); scaleWidget->setMinBorderDist(fmw / 2 + 30, fmw / 2 + 30); @@ -375,20 +375,20 @@ CapturePlot::CapturePlot(QWidget *parent, bool isdBgraph, /* configure the measurement gates */ leftGate = new QwtPlotShapeItem(); - leftGate->setAxes(QwtPlot::xBottom,QwtPlot::yRight); - leftGateRect.setTop(axisScaleDiv(yRight).upperBound()); - leftGateRect.setBottom(axisScaleDiv(yRight).lowerBound()); - leftGateRect.setLeft(axisScaleDiv(xBottom).lowerBound()); + leftGate->setAxes(QwtAxis::XBottom,QwtAxis::YRight); + leftGateRect.setTop(axisScaleDiv(QwtAxis::YRight).upperBound()); + leftGateRect.setBottom(axisScaleDiv(QwtAxis::YRight).lowerBound()); + leftGateRect.setLeft(axisScaleDiv(QwtAxis::XBottom).lowerBound()); leftGateRect.setRight(d_gateBar1->plotCoord().x()); leftGate->setRect(leftGateRect); leftGate->setBrush(gateBrush); rightGate = new QwtPlotShapeItem(); - rightGate->setAxes(QwtPlot::xBottom,QwtPlot::yRight); - rightGateRect.setTop(axisScaleDiv(yRight).upperBound()); - rightGateRect.setBottom(axisScaleDiv(yRight).lowerBound()); + rightGate->setAxes(QwtAxis::XBottom,QwtAxis::YRight); + rightGateRect.setTop(axisScaleDiv(QwtAxis::YRight).upperBound()); + rightGateRect.setBottom(axisScaleDiv(QwtAxis::YRight).lowerBound()); rightGateRect.setLeft(d_gateBar2->plotCoord().x()); - rightGateRect.setRight(axisScaleDiv(xBottom).upperBound()); + rightGateRect.setRight(axisScaleDiv(QwtAxis::XBottom).upperBound()); rightGate->setRect(rightGateRect); rightGate->setBrush(gateBrush); @@ -431,7 +431,7 @@ void CapturePlot::replot() return; } - const QwtInterval interval = axisInterval(QwtPlot::xBottom); + const QwtInterval interval = axisInterval(QwtAxis::XBottom); if (interval.minValue() != d_xAxisInterval.first || interval.maxValue() != d_xAxisInterval.second) { @@ -442,6 +442,11 @@ void CapturePlot::replot() } } +QList* CapturePlot::getMeasurements() +{ + return &d_measureObjs; +} + HorizBar *CapturePlot::levelTriggerA() { return d_levelTriggerABar; @@ -594,9 +599,9 @@ void CapturePlot::onGateBar1Moved(double value) } //update gate handle - leftGateRect.setTop(axisScaleDiv(yRight).upperBound()); - leftGateRect.setBottom(axisScaleDiv(yRight).lowerBound()); - leftGateRect.setLeft(axisScaleDiv(xBottom).lowerBound()); + leftGateRect.setTop(axisScaleDiv(QwtAxis::YRight).upperBound()); + leftGateRect.setBottom(axisScaleDiv(QwtAxis::YRight).lowerBound()); + leftGateRect.setLeft(axisScaleDiv(QwtAxis::XBottom).lowerBound()); leftGateRect.setRight(value); leftGate->setRect(leftGateRect); @@ -606,8 +611,8 @@ void CapturePlot::onGateBar1Moved(double value) double minTime = 0; if (n == 0) { - maxTime = axisScaleDiv(xBottom).upperBound(); - minTime = axisScaleDiv(xBottom).lowerBound(); + maxTime = axisScaleDiv(QwtAxis::XBottom).upperBound(); + minTime = axisScaleDiv(QwtAxis::XBottom).lowerBound(); } else { maxTime = Curve(d_selected_channel)->data()->sample(n-1).x(); minTime = Curve(d_selected_channel)->data()->sample(0).x(); @@ -623,7 +628,7 @@ void CapturePlot::onGateBar1Moved(double value) value_gateLeft = value; //find the percentage of the gate in relation with plot width - double width = (value - axisScaleDiv(xBottom).lowerBound()) / (axisScaleDiv(xBottom).upperBound() - axisScaleDiv(xBottom).lowerBound()); + double width = (value - axisScaleDiv(QwtAxis::XBottom).lowerBound()) / (axisScaleDiv(QwtAxis::XBottom).upperBound() - axisScaleDiv(QwtAxis::XBottom).lowerBound()); Q_EMIT leftGateChanged(width); d_hGatingHandle1->setTimeValue(d_gateBar1->plotCoord().x()); @@ -638,10 +643,10 @@ void CapturePlot::onGateBar2Moved(double value) } //update gate handle - rightGateRect.setTop(axisScaleDiv(yRight).upperBound()); - rightGateRect.setBottom(axisScaleDiv(yRight).lowerBound()); + rightGateRect.setTop(axisScaleDiv(QwtAxis::YRight).upperBound()); + rightGateRect.setBottom(axisScaleDiv(QwtAxis::YRight).lowerBound()); rightGateRect.setLeft(value); - rightGateRect.setRight(axisScaleDiv(xBottom).upperBound()); + rightGateRect.setRight(axisScaleDiv(QwtAxis::XBottom).upperBound()); rightGate->setRect(rightGateRect); int n = Curve(d_selected_channel)->data()->size(); @@ -650,8 +655,8 @@ void CapturePlot::onGateBar2Moved(double value) double minTime = 0; if (n == 0) { - maxTime = axisScaleDiv(xBottom).upperBound(); - minTime = axisScaleDiv(xBottom).lowerBound(); + maxTime = axisScaleDiv(QwtAxis::XBottom).upperBound(); + minTime = axisScaleDiv(QwtAxis::XBottom).lowerBound(); } else { maxTime = Curve(d_selected_channel)->data()->sample(n-1).x(); minTime = Curve(d_selected_channel)->data()->sample(0).x(); @@ -667,7 +672,7 @@ void CapturePlot::onGateBar2Moved(double value) value_gateRight = value; //find the percentage of the gate in relation with plot width - double width = (axisScaleDiv(xBottom).upperBound() - value) / (axisScaleDiv(xBottom).upperBound() - axisScaleDiv(xBottom).lowerBound()); + double width = (axisScaleDiv(QwtAxis::XBottom).upperBound() - value) / (axisScaleDiv(QwtAxis::XBottom).upperBound() - axisScaleDiv(QwtAxis::XBottom).lowerBound()); Q_EMIT rightGateChanged(width); d_hGatingHandle2->setTimeValue(d_gateBar2->plotCoord().x()); @@ -742,7 +747,7 @@ bool CapturePlot::measurementsEnabled() void CapturePlot::onTimeTriggerHandlePosChanged(int pos) { - QwtScaleMap xMap = this->canvasMap(QwtAxisId(QwtPlot::xBottom, 0)); + QwtScaleMap xMap = this->canvasMap(QwtAxisId(QwtAxis::XBottom, 0)); double min = -(xAxisNumDiv() / 2.0) * HorizUnitsPerDiv(); double max = (xAxisNumDiv() / 2.0) * HorizUnitsPerDiv(); @@ -788,12 +793,12 @@ void CapturePlot::showEvent(QShowEvent *event) void CapturePlot::printWithNoBackground(const QString& toolName, bool editScaleDraw) { QwtPlotMarker detailsMarker; - detailsMarker.setAxes(QwtPlot::xBottom, QwtPlot::yLeft); + detailsMarker.setAxes(QwtAxis::XBottom, QwtAxis::YLeft); detailsMarker.attach(this); - double xMarker = axisInterval(QwtPlot::xBottom).maxValue(); - double length = axisInterval(QwtPlot::xBottom).maxValue() - axisInterval(QwtPlot::xBottom).minValue(); + double xMarker = axisInterval(QwtAxis::XBottom).maxValue(); + double length = axisInterval(QwtAxis::XBottom).maxValue() - axisInterval(QwtAxis::XBottom).minValue(); xMarker -= (0.2 * length); - double yMarker = axisInterval(QwtPlot::yLeft).maxValue(); + double yMarker = axisInterval(QwtAxis::YLeft).maxValue(); yMarker -= (0.1 * yMarker); detailsMarker.setValue(xMarker, yMarker); QwtText text(d_timeBaseLabel->text() + " " + d_sampleRateLabel->text()); @@ -844,11 +849,11 @@ void CapturePlot::enableXaxisLabels() void CapturePlot::enableAxisLabels(bool enabled) { - enableAxis(QwtPlot::xBottom, enabled); + setAxisVisible(QwtAxis::XBottom, enabled); if (!enabled) { - int nrAxes = axesCount(QwtPlot::yLeft); + int nrAxes = axesCount(QwtAxis::YLeft); for (int i = 0; i < nrAxes; ++i) { - setAxisVisible(QwtAxisId(QwtPlot::yLeft, i), + setAxisVisible(QwtAxisId(QwtAxis::YLeft, i), enabled); } } @@ -930,7 +935,7 @@ void CapturePlot::setActiveVertAxis(unsigned int axisIdx, bool selected) DisplayPlot::setActiveVertAxis(axisIdx, selected); updateHandleAreaPadding(d_labelsEnabled); if (d_labelsEnabled) { - enableAxis(QwtPlot::xBottom, true); + setAxisVisible(QwtAxis::XBottom, true); } } @@ -939,21 +944,21 @@ void CapturePlot::showYAxisWidget(unsigned int axisIdx, bool en) if (!d_labelsEnabled) return; - setAxisVisible(QwtAxisId(QwtPlot::yLeft, axisIdx), + setAxisVisible(QwtAxisId(QwtAxis::YLeft, axisIdx), en); - int nrAxes = axesCount(QwtPlot::yLeft); + int nrAxes = axesCount(QwtAxis::YLeft); bool allAxisDisabled = true; for (int i = 0; i < nrAxes; ++i) - if (isAxisVisible(QwtAxisId(QwtPlot::yLeft, i))) + if (isAxisVisible(QwtAxisId(QwtAxis::YLeft, i))) allAxisDisabled = false; if (allAxisDisabled) { - setAxisVisible(QwtPlot::xBottom, false); + setAxisVisible(QwtAxis::XBottom, false); updateHandleAreaPadding(false); } if (en) { - setAxisVisible(QwtPlot::xBottom, true); + setAxisVisible(QwtAxis::XBottom, true); } } @@ -961,16 +966,16 @@ void CapturePlot::updateHandleAreaPadding(bool enabled) { double xAxisBonusWidth = 0.0; - if (axisEnabled(QwtPlot::xBottom)) { - if (!axisEnabled(QwtPlot::yLeft)) { + if (isAxisVisible(QwtAxis::XBottom)) { + if (!isAxisVisible(QwtAxis::YLeft)) { xAxisBonusWidth = 65.0; } } if (enabled) { - d_bottomHandlesArea->setLeftPadding(50 + axisWidget(QwtAxisId(QwtPlot::yLeft, d_activeVertAxis))->width()); - d_topGateHandlesArea->setLeftPadding(90 + axisWidget(QwtAxisId(QwtPlot::yLeft, d_activeVertAxis))->width()); - QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::xBottom); + d_bottomHandlesArea->setLeftPadding(50 + axisWidget(QwtAxisId(QwtAxis::YLeft, d_activeVertAxis))->width()); + d_topGateHandlesArea->setLeftPadding(90 + axisWidget(QwtAxisId(QwtAxis::YLeft, d_activeVertAxis))->width()); + QwtScaleWidget *scaleWidget = axisWidget(QwtAxis::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); @@ -1013,12 +1018,12 @@ void CapturePlot::updateHandleAreaPadding(bool enabled) void CapturePlot::updateGateMargins(){ /* update the size of the gates */ - leftGateRect.setTop(axisScaleDiv(yRight).upperBound()); - leftGateRect.setBottom(axisScaleDiv(yRight).lowerBound()); + leftGateRect.setTop(axisScaleDiv(QwtAxis::YRight).upperBound()); + leftGateRect.setBottom(axisScaleDiv(QwtAxis::YRight).lowerBound()); leftGate->setRect(leftGateRect); - rightGateRect.setTop(axisScaleDiv(yRight).upperBound()); - rightGateRect.setBottom(axisScaleDiv(yRight).lowerBound()); + rightGateRect.setTop(axisScaleDiv(QwtAxis::YRight).upperBound()); + rightGateRect.setBottom(axisScaleDiv(QwtAxis::YRight).lowerBound()); rightGate->setRect(rightGateRect); replot(); @@ -1035,17 +1040,10 @@ 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(); - for (int i = 0; i < d_offsetHandles.size(); ++i) { - d_offsetHandles[i]->triggerMove(); - } - Q_EMIT canvasSizeChanged(); } @@ -1106,7 +1104,7 @@ void CapturePlot::addToGroup(int currentGroup, int toAdd) void CapturePlot::onDigitalChannelAdded(int chnIdx) { setLeftVertAxesCount(d_ydata.size() + d_ref_ydata.size() + chnIdx + 1); - setAxisScale( QwtAxisId(QwtPlot::yLeft, d_ydata.size() + d_ref_ydata.size() + chnIdx), -5, 5); + setAxisScale( QwtAxisId(QwtAxis::YLeft, d_ydata.size() + d_ref_ydata.size() + chnIdx), -5, 5); replot(); QColor chnColor; @@ -1118,14 +1116,14 @@ void CapturePlot::onDigitalChannelAdded(int chnIdx) QwtPlotCurve *curve = getDigitalPlotCurve(chnIdx); GenericLogicPlotCurve *logicCurve = dynamic_cast(curve); - curve->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, d_ydata.size() + d_ref_ydata.size() + chnIdx)); + curve->setAxes(QwtAxis::XBottom, QwtAxisId(QwtAxis::YLeft, d_ydata.size() + d_ref_ydata.size() + chnIdx)); /* Channel offset widget */ HorizBar *chOffsetBar = new HorizBar(this); d_symbolCtrl->attachSymbol(chOffsetBar); chOffsetBar->setCanLeavePlot(true); chOffsetBar->setVisible(false); - chOffsetBar->setMobileAxis(QwtAxisId(QwtPlot::yLeft, d_ydata.size() + d_ref_ydata.size() + chnIdx)); + chOffsetBar->setMobileAxis(QwtAxisId(QwtAxis::YLeft, d_ydata.size() + d_ref_ydata.size() + chnIdx)); d_offsetBars.push_back(chOffsetBar); RoundedHandleV *chOffsetHdl = new RoundedHandleV( @@ -1187,9 +1185,9 @@ void CapturePlot::onDigitalChannelAdded(int chnIdx) // qDebug() << pos; - QwtScaleMap yMap = this->canvasMap(QwtAxisId(QwtPlot::yLeft, chn_id)); + QwtScaleMap yMap = this->canvasMap(QwtAxisId(QwtAxis::YLeft, chn_id)); - auto y = axisInterval(QwtAxisId(QwtPlot::yLeft, chn_id)); + auto y = axisInterval(QwtAxisId(QwtAxis::YLeft, chn_id)); // double min = -(yAxisNumDiv() / 2.0) * VertUnitsPerDiv(0); // double max = (yAxisNumDiv() / 2.0) * VertUnitsPerDiv(0); @@ -1353,8 +1351,8 @@ bool CapturePlot::endGroupSelection(bool moveAnnotationCurvesLast) 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)); + QwtScaleMap yMap = this->canvasMap(QwtAxisId(QwtAxis::YLeft, 0)); + const QwtInterval y = axisInterval(QwtAxisId(QwtAxis::YLeft, 0)); const double min = y.minValue(); const double max = y.maxValue(); yMap.setScaleInterval(min, max); @@ -1366,7 +1364,7 @@ bool CapturePlot::endGroupSelection(bool moveAnnotationCurvesLast) QwtPlotZoneItem *groupMarker = new QwtPlotZoneItem(); d_groupMarkers.push_back(groupMarker); - groupMarker->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, 0)); + groupMarker->setAxes(QwtAxis::XBottom, QwtAxisId(QwtAxis::YLeft, 0)); groupMarker->setPen(QColor(74, 100, 255, 30), 2.0); groupMarker->setBrush(QBrush(QColor(74, 100, 255, 10))); groupMarker->setInterval(y2, y1); @@ -1604,8 +1602,8 @@ void CapturePlot::handleInGroupChangedPosition(int position) } // update plot marker - QwtScaleMap yMap = this->canvasMap(QwtAxisId(QwtPlot::yLeft, 0)); - const QwtInterval y = axisInterval(QwtAxisId(QwtPlot::yLeft, 0)); + QwtScaleMap yMap = this->canvasMap(QwtAxisId(QwtAxis::YLeft, 0)); + const QwtInterval y = axisInterval(QwtAxisId(QwtAxis::YLeft, 0)); const double min = y.minValue(); const double max = y.maxValue(); yMap.setScaleInterval(min, max); @@ -1643,11 +1641,11 @@ void adiscope::CapturePlot::pushBackNewOffsetWidgets(RoundedHandleV *chOffsetHdl d_offsetHandles.insert(indexOfNewChannel, chOffsetHdl); for (int i = 0; i < d_offsetBars.size(); ++i) { - d_offsetBars[i]->setMobileAxis(QwtAxisId(QwtPlot::yLeft, i)); + d_offsetBars[i]->setMobileAxis(QwtAxisId(QwtAxis::YLeft, i)); } for (int i = 0; i < d_logic_curves.size(); ++i) { - d_logic_curves[i]->setAxes(QwtPlot::xBottom, QwtAxisId(QwtPlot::yLeft, d_ydata.size() + d_ref_ydata.size() + i)); + d_logic_curves[i]->setAxes(QwtAxis::XBottom, QwtAxisId(QwtAxis::YLeft, d_ydata.size() + d_ref_ydata.size() + i)); } } @@ -1661,7 +1659,7 @@ void CapturePlot::onChannelAdded(int chnIdx) d_symbolCtrl->attachSymbol(chOffsetBar); chOffsetBar->setCanLeavePlot(true); chOffsetBar->setVisible(false); - chOffsetBar->setMobileAxis(QwtAxisId(QwtPlot::yLeft, chnIdx)); + chOffsetBar->setMobileAxis(QwtAxisId(QwtAxis::YLeft, chnIdx)); RoundedHandleV *chOffsetHdl = new RoundedHandleV( QPixmap(":/icons/handle_right_arrow.svg"), @@ -1679,7 +1677,7 @@ void CapturePlot::onChannelAdded(int chnIdx) if (chn_id < 0) return; - QwtScaleMap yMap = this->canvasMap(QwtAxisId(QwtPlot::yLeft, chn_id)); + QwtScaleMap yMap = this->canvasMap(QwtAxisId(QwtAxis::YLeft, chn_id)); double min = -(yAxisNumDiv() / 2.0) * VertUnitsPerDiv(chn_id); double max = (yAxisNumDiv() / 2.0) * VertUnitsPerDiv(chn_id); @@ -1793,7 +1791,7 @@ void CapturePlot::setOffsetWidgetVisible(int chnIdx, bool visible) // if no group return if (hdlGroup == d_groupHandles.end()) { - qDebug() << "This handle is not in a group!"; + //qDebug() << "This handle is not in a group!"; return; } @@ -1821,7 +1819,7 @@ void CapturePlot::removeOffsetWidgets(int chnIdx) return; HorizBar *bar = d_offsetBars.takeAt(chnIdx); - bar->setMobileAxis(QwtAxisId(QwtPlot::yLeft, 0)); + bar->setMobileAxis(QwtAxisId(QwtAxis::YLeft, 0)); d_symbolCtrl->detachSymbol(bar); delete bar; delete(d_offsetHandles.takeAt(chnIdx)); @@ -1852,28 +1850,30 @@ int CapturePlot::activeMeasurementsCount(int chnIdx) void CapturePlot::onNewDataReceived() { int ref_idx = 0; - for (int i = 0; i < d_measureObjs.size(); i++) { - Measure *measure = d_measureObjs[i]; - int chn = measure->channel(); - if (isReferenceWaveform(Curve(chn))) { - measure->setDataSource(d_ref_ydata[ref_idx], - Curve(chn)->data()->size()); - ref_idx++; - } else { - int count = countReferenceWaveform(chn); - measure->setDataSource(d_ydata[chn - count], - Curve(chn)->data()->size()); - } + if(d_measurementsEnabled) { + for (int i = 0; i < d_measureObjs.size(); i++) { + Measure *measure = d_measureObjs[i]; + int chn = measure->channel(); + if (isReferenceWaveform(Curve(chn))) { + measure->setDataSource(d_ref_ydata[ref_idx], + Curve(chn)->data()->size()); + ref_idx++; + } else { + int count = countReferenceWaveform(chn); + measure->setDataSource(d_ydata[chn - count], + Curve(chn)->data()->size()); + } - if (isMathWaveform(Curve(chn))) { - measure->setAdcBitCount(0); + if (isMathWaveform(Curve(chn))) { + measure->setAdcBitCount(0); + } + + measure->setSampleRate(this->sampleRate()); + measure->measure(); } - measure->setSampleRate(this->sampleRate()); - measure->measure(); + Q_EMIT measurementsAvailable(); } - - Q_EMIT measurementsAvailable(); } QList> CapturePlot::measurements(int chnIdx) @@ -2026,5 +2026,3 @@ void CapturePlot::removeLeftVertAxis(unsigned int axis) DisplayPlot::removeLeftVertAxis(axis); } - - diff --git a/src/oscilloscope_plot.hpp b/src/oscilloscope_plot.hpp index 8d58e9ede4..83a20dbc4f 100644 --- a/src/oscilloscope_plot.hpp +++ b/src/oscilloscope_plot.hpp @@ -22,8 +22,8 @@ #define M2K_OSCILLOSCOPE_PLOT_H #include "TimeDomainDisplayPlot.h" -#include "measure.h" -#include "customplotpositionbutton.h" +#include "gui/measure.h" +#include "gui/customplotpositionbutton.h" #include "graticule.h" #include @@ -42,7 +42,7 @@ namespace adiscope { public: OscilloscopePlot(QWidget *parent, bool isdBgraph = false, unsigned int xNumDivs = 10, - unsigned int yNumDiv = 10); + unsigned int yNumDiv = 10, PrefixFormatter* pfXaxis = nullptr, PrefixFormatter* pfYaxis = nullptr); ~OscilloscopePlot(); }; @@ -63,8 +63,8 @@ namespace adiscope { }; public: - CapturePlot(QWidget *parent, bool isdBgraph = false, unsigned int xNumDivs = 10, - unsigned int yNumDivs = 10); + CapturePlot(QWidget *parent, bool isdBgraph = false, unsigned int xNumDivs = 10, unsigned int yNumDivs = 10, + PrefixFormatter* pfXaxis = nullptr, PrefixFormatter* pfYaxis = nullptr); ~CapturePlot(); void replot(); @@ -86,6 +86,7 @@ namespace adiscope { void removeOffsetWidgets(int chnIdx); void removeLeftVertAxis(unsigned int axis); + QList* getMeasurements(); void measure(); int activeMeasurementsCount(int chnIdx); QList> measurements(int chnIdx); diff --git a/src/patterngenerator/pattern_generator.cpp b/src/patterngenerator/pattern_generator.cpp index 8efe5252ad..a7b3031baa 100644 --- a/src/patterngenerator/pattern_generator.cpp +++ b/src/patterngenerator/pattern_generator.cpp @@ -22,10 +22,11 @@ #include "pattern_generator.h" #include +#include #include "ui_pattern_generator.h" #include "digitalchannel_manager.hpp" -#include "dynamicWidget.hpp" -#include "basemenu.h" +#include "gui/dynamicWidget.hpp" +#include "gui/basemenu.h" #include "../logicanalyzer/logicgroupitem.h" #include "../logicanalyzer/logicdatacurve.h" @@ -69,7 +70,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, false, 16, 10) + , m_plot(this, false, 16, 10, new TimePrefixFormatter, new MetricPrefixFormatter) , m_plotScrollBar(new QScrollBar(Qt::Vertical, this)) , m_selectedChannel(-1) , m_nbChannels(DIGITAL_NR_CHANNELS) @@ -155,6 +156,8 @@ PatternGenerator::PatternGenerator(struct iio_context *ctx, Filter *filt, void PatternGenerator::readPreferences() { + bool showFps = prefPanel->getShow_plot_fps(); + m_plot.setVisibleFpsLabel(showFps); m_ui->instrumentNotes->setVisible(prefPanel->getInstrumentNotesActive()); } @@ -228,25 +231,55 @@ void PatternGenerator::setupUi() // set default menu width to 0 m_ui->rightMenu->setMaximumWidth(0); + + // plot widget + QWidget* centralWidget = new QWidget(this); + QGridLayout* gridLayout = new QGridLayout(centralWidget); + gridLayout->setVerticalSpacing(0); + gridLayout->setHorizontalSpacing(0); + gridLayout->setContentsMargins(25, 0, 25, 0); + centralWidget->setLayout(gridLayout); + QSpacerItem *plotSpacer = new QSpacerItem(0, 5, QSizePolicy::Fixed, QSizePolicy::Fixed); - m_ui->gridLayoutPlot->addWidget(m_plot.topArea(), 0, 0, 1, 4); - m_ui->gridLayoutPlot->addWidget(m_plot.topHandlesArea(), 1, 0, 1, 4); + gridLayout->addWidget(m_plot.topArea(), 0, 0, 1, 4); + gridLayout->addWidget(m_plot.topHandlesArea(), 1, 0, 1, 4); + + gridLayout->addWidget(m_plot.leftHandlesArea(), 0, 0, 4, 1); + gridLayout->addWidget(m_plot.rightHandlesArea(), 0, 3, 4, 1); + + gridLayout->addWidget(&m_plot, 2, 1, 1, 1); + gridLayout->addWidget(m_plotScrollBar, 2, 5, 1, 1); + + gridLayout->addWidget(m_plot.bottomHandlesArea(), 3, 0, 1, 4); + gridLayout->addItem(plotSpacer, 4, 0, 1, 4); - m_ui->gridLayoutPlot->addWidget(m_plot.leftHandlesArea(), 0, 0, 4, 1); - m_ui->gridLayoutPlot->addWidget(m_plot.rightHandlesArea(), 0, 3, 4, 1); + if(prefPanel->getCurrent_docking_enabled()) { + // main window for dock widget + QMainWindow* mainWindow = new QMainWindow(this); + mainWindow->setCentralWidget(0); + mainWindow->setWindowFlags(Qt::Widget); + m_ui->gridLayoutPlot->addWidget(mainWindow, 1, 0, 1, 1); - m_ui->gridLayoutPlot->addWidget(&m_plot, 2, 1, 1, 1); - m_ui->gridLayoutPlot->addWidget(m_plotScrollBar, 2, 5, 1, 1); + QDockWidget* dockWidget = DockerUtils::createDockWidget(mainWindow, centralWidget); + + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget); + +#ifdef PLOT_MENU_BAR_ENABLED + DockerUtils::configureTopBar(dockWidget); +#endif + } else { + m_ui->gridLayoutPlot->addWidget(centralWidget, 0, 0, 1, 1); + } - m_ui->gridLayoutPlot->addWidget(m_plot.bottomHandlesArea(), 3, 0, 1, 4); - m_ui->gridLayoutPlot->addItem(plotSpacer, 4, 0, 1, 4); + // TODO: do we want the buffer previewer in this tool? + m_ui->hLayoutBufferPreview->hide(); - m_plot.enableAxis(QwtPlot::yLeft, false); - m_plot.enableAxis(QwtPlot::xBottom, false); + m_plot.setAxisVisible(QwtAxis::YLeft, false); + m_plot.setAxisVisible(QwtAxis::XBottom, false); m_plot.setUsingLeftAxisScales(false); m_plot.enableLabels(false); @@ -795,7 +828,6 @@ void PatternGenerator::generateBuffer() m_plot.setHorizOffset(1.0 / m_sampleRate * m_bufferSize / 2.0); m_plot.cancelZoom(); m_plot.zoomBaseUpdate(); - m_plot.replot(); for (QPair, PatternUI *> &pattern : m_enabledPatterns) { pattern.second->get_pattern()->generate_pattern(sr, bufferSize, pattern.first.size()); diff --git a/src/patterngenerator/pattern_generator.h b/src/patterngenerator/pattern_generator.h index 3c8a100839..d5f61e50db 100644 --- a/src/patterngenerator/pattern_generator.h +++ b/src/patterngenerator/pattern_generator.h @@ -25,7 +25,7 @@ #include "logic_tool.h" #include "oscilloscope_plot.hpp" #include "buffer_previewer.hpp" -#include "spinbox_a.hpp" +#include "gui/spinbox_a.hpp" #include "scroll_filter.hpp" #include "../logicanalyzer/genericlogicplotcurve.h" diff --git a/src/patterngenerator/patterns/patterns.cpp b/src/patterngenerator/patterns/patterns.cpp index c64c7d905f..9a10145d24 100644 --- a/src/patterngenerator/patterns/patterns.cpp +++ b/src/patterngenerator/patterns/patterns.cpp @@ -34,7 +34,7 @@ #include "../pattern_generator.h" #include "../../logicanalyzer/annotationcurve.h" #include "../../logicanalyzer/annotationdecoder.h" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include diff --git a/src/patterngenerator/patterns/patterns.hpp b/src/patterngenerator/patterns/patterns.hpp index 88717c9947..75b75c89d0 100644 --- a/src/patterngenerator/patterns/patterns.hpp +++ b/src/patterngenerator/patterns/patterns.hpp @@ -32,8 +32,8 @@ #include #include #include -#include "spinbox_a.hpp" -#include "osc_import_settings.h" +#include "gui/spinbox_a.hpp" +#include "gui/osc_import_settings.h" // Generated UI #include "ui_binarycounterpatternui.h" diff --git a/src/power_controller.cpp b/src/power_controller.cpp index 10a069bf58..afee9e3bbe 100644 --- a/src/power_controller.cpp +++ b/src/power_controller.cpp @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include "power_controller.hpp" #include "filter.hpp" diff --git a/src/power_controller.hpp b/src/power_controller.hpp index 8053366f07..0235f259b7 100644 --- a/src/power_controller.hpp +++ b/src/power_controller.hpp @@ -25,7 +25,7 @@ #include #include "apiObject.hpp" -#include "spinbox_a.hpp" +#include "gui/spinbox_a.hpp" #include "tool.hpp" extern "C" { diff --git a/src/preferences.cpp b/src/preferences.cpp index 5c3008c6b1..a648d60c92 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -20,7 +20,7 @@ #include "preferences.h" #include "ui_preferences.h" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include #include @@ -31,10 +31,15 @@ #include #include #include "application_restarter.h" +#include "utils.h" using namespace adiscope; +Preferences* adiscope::pref_ptr; +Preferences* adiscope::getScopyPreferences() { + return pref_ptr; +} Preferences::Preferences(QWidget *parent) : QWidget(parent), @@ -68,9 +73,20 @@ Preferences::Preferences(QWidget *parent) : m_skipCalIfCalibrated(true), automatical_version_checking_enabled(false), first_application_run(true), - check_updates_url("https://swdownloads.analog.com/cse/sw_versions.json"), + check_updates_url("http://swdownloads.analog.com/cse/sw_versions.json"), m_colorEditor(nullptr), - m_logging_enabled(false) + m_logging_enabled(false), + m_show_plot_fps(false), + m_use_open_gl( +// Android/macOS/Windows use OpenGL by default +#if defined __ANDROID__ || defined __APPLE__ || defined __MINGW32__ + true +#else + false +#endif + ), + m_target_fps(30), + m_docking_enabled(false) { ui->setupUi(this); @@ -79,6 +95,9 @@ Preferences::Preferences(QWidget *parent) : ui->debugMessagesCheckbox->setVisible(false); ui->debugMessagesLbl->setVisible(false); +#ifdef __ANDROID__ + ui->doubleClickToDetachWidget->setDisabled(true); +#endif connect(ui->doubleClickCheckBox, &QCheckBox::stateChanged, [=](int state){ double_click_to_detach = (!state ? false : true); Q_EMIT notify(); @@ -211,6 +230,17 @@ Preferences::Preferences(QWidget *parent) : Q_EMIT notify(); }); + connect(ui->showPlotFps, &QCheckBox::stateChanged, [=](int state) { + m_show_plot_fps = state; + Q_EMIT notify(); + }); + + connect(ui->enableDockableWidgetsCheckBox, &QCheckBox::stateChanged, [=](int state){ + m_docking_enabled = (!state ? false : true); + + requestRestart(); + }); + QString preference_ini_file = getPreferenceIniFile(); QSettings settings(preference_ini_file, QSettings::IniFormat); @@ -252,6 +282,21 @@ Preferences::Preferences(QWidget *parent) : Q_EMIT notify(); }); + connect(ui->useOpenGl, &QCheckBox::stateChanged, [=](int state){ + m_use_open_gl = state; + qputenv("SCOPY_USE_OPENGL",QByteArray::number(state)); + + if (m_initialized) { + requestRestart(); + } + Q_EMIT notify(); + }); + + connect(ui->cmbPlotTargetFps, &QComboBox::currentTextChanged, [=](QString fps){ + m_target_fps = fps.toDouble(); + Q_EMIT notify(); + }); + ui->comboBoxTheme->addItem("default"); ui->comboBoxTheme->addItem("light"); ui->comboBoxTheme->addItem("browse"); @@ -269,23 +314,18 @@ Preferences::Preferences(QWidget *parent) : m_colorEditor->setUserStylesheets({filePath}); m_colorEditor->setCurrentStylesheet(filePath); - - requestRestart(); - - } else { m_colorEditor->setCurrentStylesheet(stylesheet); - - // force saving of the ini file as the new Scopy process - // when restarted will start before scopy closes. A race condition - // will appear on who gets to read/write to the .ini file first - QString preference_ini_file = getPreferenceIniFile(); - QSettings settings(preference_ini_file, QSettings::IniFormat); - pref_api->save(settings); - - requestRestart(); } + requestRestart(); }); + pref_ptr = this; +} + +void Preferences::save() { + QString preference_ini_file = getPreferenceIniFile(); + QSettings settings(preference_ini_file, QSettings::IniFormat); + pref_api->save(settings); } void Preferences::requestRestart() @@ -301,7 +341,7 @@ void Preferences::requestRestart() int ret = msgBox.exec(); if (ret == QMessageBox::Ok) { - // restart: + save(); // save before restarting adiscope::ApplicationRestarter::triggerRestart(); } } @@ -391,6 +431,15 @@ void Preferences::showEvent(QShowEvent *event) ui->debugInstrumentCheckbox->setChecked(debugger_enabled); ui->tempLutCalibCheckbox->setChecked(m_attemptTempLutCalib); ui->skipCalCheckbox->setChecked(m_skipCalIfCalibrated); + ui->showPlotFps->setChecked(m_show_plot_fps); + ui->useOpenGl->setChecked(m_use_open_gl); + ui->cmbPlotTargetFps->setCurrentText(QString::number(m_target_fps)); + + // requires restart after stateChanged, we avoid that here + ui->enableDockableWidgetsCheckBox->blockSignals(true); + ui->enableDockableWidgetsCheckBox->setChecked(m_docking_enabled); + ui->enableDockableWidgetsCheckBox->blockSignals(false); + // by this point the preferences menu is initialized m_initialized = true; ui->autoUpdatesCheckBox->setChecked(automatical_version_checking_enabled); @@ -428,6 +477,36 @@ void Preferences::resetScopy() } } +double Preferences::getTarget_fps() const +{ + return m_target_fps; +} + +void Preferences::setTarget_fps(double newTarget_fps) +{ + m_target_fps = newTarget_fps; +} + +bool Preferences::getUse_open_gl() const +{ + return m_use_open_gl; +} + +void Preferences::setUse_open_gl(bool newUse_open_gl) +{ + m_use_open_gl = newUse_open_gl; +} + +bool Preferences::getShow_plot_fps() const +{ + return m_show_plot_fps; +} + +void Preferences::setShow_plot_fps(bool newShow_plot_fps) +{ + m_show_plot_fps = newShow_plot_fps; +} + bool Preferences::getDigital_decoders_enabled() const { return digital_decoders_enabled; @@ -678,7 +757,6 @@ void Preferences::setFirst_application_run(bool value) first_application_run = value; } - void Preferences::setColorEditor(ScopyColorEditor *colorEditor) { m_colorEditor = colorEditor; @@ -700,6 +778,21 @@ void Preferences::setLogging_enabled(bool value) m_logging_enabled = value; } +bool Preferences::getDocking_enabled() const +{ + return m_docking_enabled; +} + +void Preferences::setDocking_enabled(bool value) +{ + m_docking_enabled = value; +} + +bool Preferences::getCurrent_docking_enabled() const +{ + return m_current_docking_state; +} + bool Preferences_API::getAnimationsEnabled() const { return preferencePanel->animations_enabled; @@ -911,7 +1004,18 @@ QStringList Preferences_API::getUserStylesheets() const void Preferences_API::setUserStylesheets(const QStringList &userStylesheets) { -// preferencePanel->m_colorEditor->setUserStylesheets(userStylesheets); + // preferencePanel->m_colorEditor->setUserStylesheets(userStylesheets); +} + +bool Preferences_API::getDockingEnabled() const +{ + return preferencePanel->m_docking_enabled; +} + +void Preferences_API::setDockingEnabled(const bool &first) +{ + preferencePanel->m_docking_enabled = first; + preferencePanel->m_current_docking_state = first; } bool Preferences::hasNativeDialogs() const @@ -992,3 +1096,34 @@ void Preferences_API::setFirstApplicationRun(const bool &first) { preferencePanel->first_application_run = first; } + +bool Preferences_API::getShowPlotFps() const +{ + return preferencePanel->m_show_plot_fps; +} + +void Preferences_API::setShowPlotFps(const bool& fps) +{ + preferencePanel->m_show_plot_fps = fps; +} + +bool Preferences_API::getUseOpenGl() const +{ + return preferencePanel->m_use_open_gl; +} + +void Preferences_API::setUseOpenGl(const bool& val) +{ + preferencePanel->m_use_open_gl = val; + qputenv("SCOPY_USE_OPENGL",QByteArray::number(val)); +} + +double Preferences_API::getTargetFps() const +{ + return preferencePanel->m_target_fps; +} + +void Preferences_API::setTargetFps(const double &val) +{ + preferencePanel->m_target_fps = val; +} diff --git a/src/preferences.h b/src/preferences.h index eedfda6d80..79f145990b 100644 --- a/src/preferences.h +++ b/src/preferences.h @@ -141,6 +141,19 @@ class Preferences : public QWidget bool getLogging_enabled() const; void setLogging_enabled(bool value); + bool getShow_plot_fps() const; + void setShow_plot_fps(bool newShow_plot_fps); + + bool getUse_open_gl() const; + void setUse_open_gl(bool newUse_open_gl); + + double getTarget_fps() const; + void setTarget_fps(double newTarget_fps); + + bool getDocking_enabled() const; + void setDocking_enabled(bool value); + bool getCurrent_docking_enabled() const; + Q_SIGNALS: void notify(); @@ -149,6 +162,7 @@ class Preferences : public QWidget public Q_SLOTS: + void save(); QString loadLanguage(); @@ -190,6 +204,11 @@ private Q_SLOTS: bool m_attemptTempLutCalib; bool m_skipCalIfCalibrated; bool m_logging_enabled; + bool m_show_plot_fps; + bool m_use_open_gl; + int m_target_fps; + bool m_docking_enabled; + bool m_current_docking_state; Preferences_API *pref_api; @@ -228,6 +247,10 @@ class Preferences_API : public ApiObject Q_PROPERTY(bool first_application_run READ getFirstApplicationRun WRITE setFirstApplicationRun) Q_PROPERTY(QString currentStylesheet READ getCurrentStylesheet WRITE setCurrentStylesheet) Q_PROPERTY(QStringList userStylesheets READ getUserStylesheets WRITE setUserStylesheets) + Q_PROPERTY(bool showPlotFps READ getShowPlotFps WRITE setShowPlotFps) + Q_PROPERTY(bool useOpenGl READ getUseOpenGl WRITE setUseOpenGl) + Q_PROPERTY(double targetFps READ getTargetFps WRITE setTargetFps) + Q_PROPERTY(bool docking_enabled READ getDockingEnabled WRITE setDockingEnabled) public: @@ -311,16 +334,32 @@ class Preferences_API : public ApiObject bool getFirstApplicationRun() const; void setFirstApplicationRun(const bool& first); + bool getShowPlotFps() const; + void setShowPlotFps(const bool& first); + + bool getUseOpenGl() const; + void setUseOpenGl(const bool& first); + + double getTargetFps() const; + void setTargetFps(const double& val); + QString getCurrentStylesheet() const; void setCurrentStylesheet(const QString ¤tStylesheet); QStringList getUserStylesheets() const; void setUserStylesheets(const QStringList &userStylesheets); + bool getDockingEnabled() const; + void setDockingEnabled(const bool& first); + private: Preferences *preferencePanel; }; + +extern Preferences* pref_ptr; +Preferences* getScopyPreferences(); + } #endif // PREFERENCE_PANEL_H diff --git a/src/printableplot.cpp b/src/printableplot.cpp index 7e00299a0c..f47325cecb 100644 --- a/src/printableplot.cpp +++ b/src/printableplot.cpp @@ -26,16 +26,16 @@ using namespace adiscope; PrintablePlot::PrintablePlot(QWidget *parent) : - QwtPlot(parent), + BasicPlot(parent), d_plotRenderer(new QwtPlotRenderer(this)), d_useNativeDialog(true) { - dropBackground(true); + dropBackground(true); } void PrintablePlot::dropBackground(bool drop) { - d_plotRenderer.setDiscardFlag(QwtPlotRenderer::DiscardBackground, drop); + d_plotRenderer.setDiscardFlag(QwtPlotRenderer::DiscardBackground, drop); d_plotRenderer.setDiscardFlag(QwtPlotRenderer::DiscardCanvasBackground, drop); } @@ -46,15 +46,15 @@ void PrintablePlot::setUseNativeDialog(bool nativeDialog) void PrintablePlot::printPlot(const QString& toolName) { - legendDisplay = new QwtLegend(this); - legendDisplay->setDefaultItemMode(QwtLegendData::ReadOnly); - insertLegend(legendDisplay, QwtPlot::TopLegend); + legendDisplay = new QwtLegend(this); + legendDisplay->setDefaultItemMode(QwtLegendData::ReadOnly); + insertLegend(legendDisplay, QwtPlot::TopLegend); - updateLegend(); + updateLegend(); - QString date = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss"); + QString date = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss"); - QString fileName = "Scopy-" + toolName + "-" + date; + QString fileName = "Scopy-" + toolName + "-" + date; // https://github.com/osakared/qwt/blob/qwt-6.1-multiaxes/src/qwt_plot_renderer.cpp#L1023 // QwtPlotRenderer does not expose an option to select which file dialog to use @@ -62,33 +62,33 @@ void PrintablePlot::printPlot(const QString& toolName) // call of QFileDialog::getSaveFileName(...) where we take into account the d_useNativeDialog // boolean const QList imageFormats = - QImageWriter::supportedImageFormats(); + QImageWriter::supportedImageFormats(); QStringList filter; filter += QString( "PDF " ) + tr( "Documents" ) + " (*.pdf)"; filter += QString( "SVG " ) + tr( "Documents" ) + " (*.svg)"; filter += QString( "Postscript " ) + tr( "Documents" ) + " (*.ps)"; if ( imageFormats.size() > 0 ) { - for ( int i = 0; i < imageFormats.size(); i++ ) { - filter += (imageFormats[i].toUpper() + " " + for ( int i = 0; i < imageFormats.size(); i++ ) { + filter += (imageFormats[i].toUpper() + " " + tr("Image") + " (*." + imageFormats[i] + ")"); - } + } } - QString selectedFilter = QString( "PDF " ) + tr( "Documents" ) + " (*.pdf)"; + QString selectedFilter = QString( "PDF " ) + tr( "Documents" ) + " (*.pdf)"; fileName = QFileDialog::getSaveFileName( - nullptr, tr( "Export File Name" ), fileName, - filter.join( ";;" ), &selectedFilter, - (d_useNativeDialog ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)); - - if (fileName.split(".").size() <= 1) { - // file name w/o extension. Let's append it - QString ext = selectedFilter.split(".")[1].split(")")[0]; - fileName += "." + ext; - } + nullptr, tr( "Export File Name" ), fileName, + filter.join( ";;" ), &selectedFilter, + (d_useNativeDialog ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)); + + if (fileName.split(".").size() <= 1) { + // file name w/o extension. Let's append it + QString ext = selectedFilter.split(".")[1].split(")")[0]; + fileName += "." + ext; + } - d_plotRenderer.renderDocument(this, fileName, QSizeF( 300, 200 )); + d_plotRenderer.renderDocument(this, fileName, QSizeF( 300, 200 )); - insertLegend(nullptr); + insertLegend(nullptr); } diff --git a/src/printableplot.h b/src/printableplot.h index 2938999495..9adc390335 100644 --- a/src/printableplot.h +++ b/src/printableplot.h @@ -28,23 +28,24 @@ /*Qt includes*/ #include +#include namespace adiscope { -class PrintablePlot : public QwtPlot +class PrintablePlot : public BasicPlot { - Q_OBJECT + Q_OBJECT public: - PrintablePlot(QWidget *parent); + PrintablePlot(QWidget *parent); - void dropBackground(bool drop); + void dropBackground(bool drop); void setUseNativeDialog(bool nativeDialog); public Q_SLOTS: - void printPlot(const QString& toolName = ""); + void printPlot(const QString& toolName = ""); private: - QwtPlotRenderer d_plotRenderer; - QwtLegend *legendDisplay; + QwtPlotRenderer d_plotRenderer; + QwtLegend *legendDisplay; bool d_useNativeDialog; }; } diff --git a/src/qtgui_util.cc b/src/qtgui_util.cc index 78c7507838..0c4658baab 100644 --- a/src/qtgui_util.cc +++ b/src/qtgui_util.cc @@ -170,3 +170,48 @@ bool Util::compareNatural(const std::string& a, const std::string& b) { return (compareNatural(a_new, b_new)); } +QDockWidget *DockerUtils::createDockWidget(QMainWindow *mainWindow, QWidget *widget, const QString &title) +{ + QDockWidget* dockWidget = new QDockWidget(title, mainWindow); + dockWidget->setFeatures(dockWidget->features() & ~QDockWidget::DockWidgetClosable); + dockWidget->setAllowedAreas(Qt::AllDockWidgetAreas); + dockWidget->setWidget(widget); + +#ifdef __ANDROID__ + dockWidget->setFeatures(dockWidget->features() & ~QDockWidget::DockWidgetClosable + & ~QDockWidget::DockWidgetFloatable); +#endif + + return dockWidget; +} + +void DockerUtils::configureTopBar(QDockWidget *docker) +{ + connect(docker, &QDockWidget::topLevelChanged, [=](bool topLevel){ + QString icon_path = ""; + + if (QIcon::themeName() == "scopy-default") { + icon_path +=":/icons"; + } else { + icon_path +=":/icons/scopy-light/icons"; + } + + if(topLevel) { + docker->setWindowFlags(Qt::CustomizeWindowHint | + Qt::Window | + Qt::WindowMinimizeButtonHint | + Qt::WindowMaximizeButtonHint); + docker->show(); + + docker->setStyleSheet("QDockWidget {" + "titlebar-normal-icon: url(" + icon_path + "/sba_cmb_box_arrow.svg);" + "}"); + docker->setContentsMargins(10, 0, 10, 10); + } else { + docker->setStyleSheet("QDockWidget {" + "titlebar-normal-icon: url(" + icon_path + "/sba_cmb_box_arrow_right.svg);" + "}"); + docker->setContentsMargins(0, 0, 0, 0); + } + }); +} diff --git a/src/qtjs.cpp b/src/qtjs.cpp index 4cd1adbacd..ecc8b77088 100644 --- a/src/qtjs.cpp +++ b/src/qtjs.cpp @@ -29,6 +29,8 @@ #include #include +#include + using std::cout; using namespace adiscope; @@ -54,6 +56,19 @@ void QtJs::exit() QApplication::closeAllWindows(); } +void QtJs::returnToApplication() +{ + bool done; + connect(getToolLauncherInstance(), &ToolLauncher::launcherClosed,[&done](){ + done=true; + }); + + while(!done) { + QCoreApplication::processEvents(); + QThread::msleep(1); + } +} + void QtJs::sleep(unsigned long s) { msleep(s * 1000); diff --git a/src/qtjs.hpp b/src/qtjs.hpp index 1e34cef6b7..c2737e5273 100644 --- a/src/qtjs.hpp +++ b/src/qtjs.hpp @@ -40,6 +40,7 @@ class QtJs : public QObject Q_INVOKABLE void msleep(unsigned long ms); Q_INVOKABLE void printToConsole(const QString& text); Q_INVOKABLE QString readFromConsole(const QString& text); + Q_INVOKABLE void returnToApplication(); private: QFutureWatcher watcher; diff --git a/src/scope_sink_f_impl.cc b/src/scope_sink_f_impl.cc index e961923a7c..6ab3b2f5ff 100644 --- a/src/scope_sink_f_impl.cc +++ b/src/scope_sink_f_impl.cc @@ -136,8 +136,8 @@ namespace adiscope { d_qApplication = qApp; } - // initialize update time to 10 times a second - set_update_time(0.1); + // initialize update time to 60 times a second + set_update_time(1/60.0); } void diff --git a/src/signal_generator.cpp b/src/signal_generator.cpp index 9acfa5c148..2a78646bc4 100644 --- a/src/signal_generator.cpp +++ b/src/signal_generator.cpp @@ -19,11 +19,11 @@ */ #include "logging_categories.h" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include "signal_generator.hpp" -#include "spinbox_a.hpp" +#include "gui/spinbox_a.hpp" #include "ui_signal_generator.h" -#include "channel_widget.hpp" +#include "gui/channel_widget.hpp" #include @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,7 @@ #include #include #include "scopyExceptionHandler.h" +#include "gnuradio/blocks/multiply_const.h" #ifdef MATLAB_SUPPORT_SIGGEN #include @@ -83,6 +85,7 @@ #define MULTIPLY_CT 4 #define FREQUENCY_CT 40 + using namespace adiscope; using namespace gr; using namespace libm2k::context; @@ -143,7 +146,7 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, ui->run_button->enableSingleButton(false); this->setAttribute(Qt::WA_DeleteOnClose, true); - this->m_plot = new CapturePlot(this); + this->m_plot = new CapturePlot(this, false, 10, 10 , new TimePrefixFormatter, new MetricPrefixFormatter); QVector iio_channels; @@ -290,6 +293,8 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, {"%",1e0} }, tr("Duty Cycle"), -5, 100, true, false, this); + load = ui->externalLoad; + ui->waveformGrid->addWidget(amplitude, 0, 0, 1, 1); ui->waveformGrid->addWidget(offset, 0, 1, 1, 1); ui->waveformGrid->addWidget(frequency, 1, 0, 1, 1); @@ -412,6 +417,7 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, ptr->file_nr_of_channels=0; ptr->file_channel=0; ptr->lineThickness = 1.0; + ptr->load = ExternalLoadLineEdit::MAX_EXTERNAL_LOAD; ptr->type = SIGNAL_TYPE_CONSTANT; ptr->id = i; @@ -487,7 +493,7 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, ((double) sample_rate * 10.0)); m_plot->setHorizOffset((double) nb_points / ((double) sample_rate * 2.0)); - m_plot->zoomBaseUpdate(); + m_plot->zoomBaseUpdate(true); //ui->plot->insertWidget(0,m_plot, 0, 0); connect(ui->btnAppearanceCollapse, SIGNAL(toggled(bool)),ui->wAppearance, SLOT(setVisible(bool))); @@ -566,6 +572,9 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, connect(ui->cbLineThickness, SIGNAL(currentIndexChanged(int)), this, SLOT(lineThicknessChanged(int))); + connect(load, SIGNAL(valueChanged(double)), + this, SLOT(externalLoadChanged(double))); + connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int))); @@ -583,8 +592,6 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, connect(ui->refreshBtn, SIGNAL(clicked()), this, SLOT(loadFileCurrentChannelData())); - time_block_data->time_block->set_update_time(0.001); - m_plot->addZoomer(0); resetZoom(); @@ -597,18 +604,55 @@ SignalGenerator::SignalGenerator(struct iio_context *_ctx, Filter *filt, m_plot->setOffsetHandleVisible(0,false); m_plot->setOffsetHandleVisible(1,false); - m_plot->enableAxis(QwtPlot::yLeft, false); + m_plot->setAxisVisible(QwtAxis::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); + // plot widget + QWidget* centralWidget = new QWidget(); + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->setVerticalSpacing(0); + gridLayout->setHorizontalSpacing(0); + gridLayout->setContentsMargins(0, 0, 0, 5); + + gridLayout->addWidget(m_plot->topArea(), 0, 0); + gridLayout->addWidget(m_plot->topHandlesArea(), 1, 0); + gridLayout->addWidget(m_plot, 2, 0); + + centralWidget->setLayout(gridLayout); + ui->plot->removeWidget(ui->instrumentNotes); - ui->plot->addWidget(ui->instrumentNotes,3,0,1,4); - ui->plot->addWidget(m_plot, 2, 1, 1, 1); + + if(prefPanel->getCurrent_docking_enabled()) { + + // main window for dock widget + QMainWindow* mainWindow = new QMainWindow(this); + mainWindow->setCentralWidget(0); + mainWindow->setWindowFlags(Qt::Widget); + ui->plot->addWidget(mainWindow, 0, 0); + + QDockWidget* dockWidget = DockerUtils::createDockWidget(mainWindow, centralWidget); + dockWidget->setContentsMargins(0, 0, 0, 10); + + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget); + +#ifdef PLOT_MENU_BAR_ENABLED + DockerUtils::configureTopBar(dockWidget); +#endif + + } else { + ui->plot->addWidget(centralWidget); + } + + connect(ui->toggleMenuBtn, &QPushButton::toggled, [=](bool toggled){ + ui->rightMenu->toggleMenu(toggled); + }); + + ui->plot->addWidget(ui->instrumentNotes, 1, 0); } + SignalGenerator::~SignalGenerator() { disconnect(prefPanel, &Preferences::notify, this, &SignalGenerator::readPreferences); @@ -633,6 +677,8 @@ void SignalGenerator::settingsLoaded() void SignalGenerator::readPreferences() { + bool showFps = prefPanel->getShow_plot_fps(); + m_plot->setVisibleFpsLabel(showFps); double prefered_periods_nr = prefPanel->getSig_gen_periods_nr(); if (nr_of_periods != prefered_periods_nr) { nr_of_periods = prefered_periods_nr; @@ -886,6 +932,7 @@ void SignalGenerator::mathSampleRateChanged(double value) void SignalGenerator::noiseTypeChanged(int index) { + auto ptr = getCurrentData(); gr::analog::noise_type_t value = qvariant_cast(ui->cbNoiseType->itemData(index)); @@ -906,6 +953,17 @@ void SignalGenerator::noiseAmplitudeChanged(double value) } } +void SignalGenerator::externalLoadChanged(double value) { + + auto ptr = getCurrentData(); + + if (ptr->load != value) { + ptr->load = value; + resetZoom(); + } + +} + void SignalGenerator::lineThicknessChanged(int index) { auto ptr = getCurrentData(); @@ -1130,7 +1188,6 @@ void SignalGenerator::updatePreview() timer.start(); top->run(); - qDebug(CAT_SIGNAL_GENERATOR) << "The slow operation took" << timer.elapsed() << "milliseconds"; top->disconnect_all(); if (ui->run_button->runButtonChecked()) { @@ -1456,9 +1513,15 @@ void SignalGenerator::start() auto source = getSource(w, best_rate, top_block); auto head = blocks::head::make(sizeof(float), samples_count); auto vector = blocks::vector_sink_f::make(); + + auto load = getData(w)->load; + auto scaling_factor = ((load + ExternalLoadLineEdit::OUTPUT_AWG_RESISTANCE) / load); + auto load_scaling = blocks::multiply_const_ff::make(scaling_factor); + auto clamp = analog::rail_ff::make(-AMPLITUDE_VOLTS, AMPLITUDE_VOLTS); - top_block->connect(source, 0, clamp, 0); + top_block->connect(source, 0, load_scaling, 0); + top_block->connect(load_scaling, 0,clamp,0); top_block->connect(clamp,0, head,0); top_block->connect(head, 0, vector, 0); top_block->run(); @@ -1593,7 +1656,7 @@ basic_block_sptr SignalGenerator::getSignalSource(gr::top_block_sptr top, } else - src = scopy::trapezoidal::make(samp_rate, data.frequency, amplitude, + src = gr::scopy::trapezoidal::make(samp_rate, data.frequency, amplitude, rise, holdh, fall, holdl, offset, phase*0.01745329); @@ -1875,19 +1938,19 @@ gr::basic_block_sptr SignalGenerator::getSource(QWidget *obj, if(ptr->math_sr < samp_rate) { - auto src = scopy::iio_math_gen::make(ptr->math_sr, str, (uint64_t)ptr->math_sr * ptr->math_record_length); + auto src = gr::scopy::iio_math_gen::make(ptr->math_sr, str, (uint64_t)ptr->math_sr * ptr->math_record_length); auto resamp = displayResampler(samp_rate, ptr->math_sr, top, src, noiseSrc, noiseAdd); top->connect(resamp, 0, skip_head, 0); return skip_head; } else { - auto src = scopy::iio_math_gen::make(samp_rate, str, (uint64_t)samp_rate * ptr->math_record_length); + auto src = gr::scopy::iio_math_gen::make(samp_rate, str, (uint64_t)samp_rate * ptr->math_record_length); top->connect(src, 0, skip_head, 0); generated_wave = skip_head; } } else { - generated_wave = scopy::iio_math_gen::make(samp_rate, str, (uint64_t)samp_rate * ptr->math_record_length); + generated_wave = gr::scopy::iio_math_gen::make(samp_rate, str, (uint64_t)samp_rate * ptr->math_record_length); } break; } @@ -2029,6 +2092,7 @@ void SignalGenerator::updateRightMenuForChn(int chIdx) int lineThicknessIndex = (int)(ptr->lineThickness / 0.5) - 1; ui->cbLineThickness->setCurrentIndex(lineThicknessIndex); + load->setValue(ptr->load); fallTime->setValue(ptr->fall); riseTime->setValue(ptr->rise); @@ -2429,4 +2493,3 @@ size_t SignalGenerator::get_samples_count(unsigned int chnIdx, return size; } - diff --git a/src/signal_generator.hpp b/src/signal_generator.hpp index 16e28a2857..368ad771b7 100644 --- a/src/signal_generator.hpp +++ b/src/signal_generator.hpp @@ -46,6 +46,9 @@ #include #include +#include + + extern "C" { struct iio_context; } @@ -162,6 +165,7 @@ class SignalGenerator : public Tool ScaleSpinButton *holdHighTime, *holdLowTime; ScaleSpinButton *fileSampleRate, *fileAmplitude; ScaleSpinButton *mathRecordLength, *noiseAmplitude, *mathSampleRate; + ExternalLoadLineEdit *load; FileManager *fileManager; @@ -258,6 +262,7 @@ private Q_SLOTS: void noiseAmplitudeChanged(double val); void noiseTypeChanged(int val); void lineThicknessChanged(int index); + void externalLoadChanged(double val); void trapezoidalComputeFrequency(); void riseChanged(double value); void fallChanged(double value); @@ -343,6 +348,7 @@ struct signal_generator_data { gr::analog::noise_type_t noiseType; float noiseAmplitude; float lineThickness; + double load; }; struct time_block_data { diff --git a/src/signal_generator_api.cpp b/src/signal_generator_api.cpp index a339ee4c0c..fc7a38dda0 100644 --- a/src/signal_generator_api.cpp +++ b/src/signal_generator_api.cpp @@ -19,8 +19,8 @@ */ #include "signal_generator_api.hpp" #include "ui_signal_generator.h" -#include "channel_widget.hpp" -#include "spinbox_a.hpp" +#include "gui/channel_widget.hpp" +#include "gui/spinbox_a.hpp" namespace adiscope { void SignalGenerator_API::show() @@ -841,6 +841,40 @@ void SignalGenerator_API::setLineThickness(const QList& list) gen->ui->cbLineThickness->setCurrentIndex(index); } + + +QList SignalGenerator_API::getLoad() const +{ + QList list; + + for (int i = 0; i < gen->channels.size(); i++) { + auto ptr = gen->getData(gen->channels[i]); + + list.append(ptr->load); + } + + return list; +} + +void SignalGenerator_API::setLoad(const QList& list) +{ + if (list.size() != gen->channels.size()) { + return; + } + + for (int i = 0; i < gen->channels.size(); i++) { + auto ptr = gen->getData(gen->channels[i]); + + ptr->load = list.at(i); + if(i == gen->currentChannel){ + gen->resetZoom(); + gen->load->setValue(gen->getCurrentData()->load); + } + } + +} + + bool SignalGenerator_API::getAutoscale() const { return gen->ui->btnSigGenAutoscale->isChecked(); diff --git a/src/signal_generator_api.hpp b/src/signal_generator_api.hpp index 70944548cc..7b93ab843f 100644 --- a/src/signal_generator_api.hpp +++ b/src/signal_generator_api.hpp @@ -94,6 +94,7 @@ class SignalGenerator_API : public ApiObject READ getLineThickness WRITE setLineThickness) Q_PROPERTY(bool autoscale READ getAutoscale WRITE setAutoscale); + Q_PROPERTY(QList load READ getLoad WRITE setLoad); public: @@ -173,6 +174,9 @@ class SignalGenerator_API : public ApiObject QList getLineThickness() const; void setLineThickness(const QList& list); + QList getLoad() const; + void setLoad(const QList& list); + bool getAutoscale() const; void setAutoscale(bool checked); diff --git a/src/sismograph.cpp b/src/sismograph.cpp index 131261eef7..14acac855a 100644 --- a/src/sismograph.cpp +++ b/src/sismograph.cpp @@ -29,19 +29,19 @@ using namespace adiscope; Sismograph::Sismograph(QWidget *parent) : QwtPlot(parent), curve("data"), sampleRate(10.0) { - enableAxis(QwtPlot::xBottom, false); - enableAxis(QwtPlot::xTop, true); + setAxisVisible(QwtAxis::XBottom, false); + setAxisVisible(QwtAxis::XTop, true); - setAxisTitle(QwtPlot::xTop, tr("Voltage (V)")); - setAxisTitle(QwtPlot::yLeft, tr("Time (s)")); + setAxisTitle(QwtAxis::XTop, tr("Voltage (V)")); + setAxisTitle(QwtAxis::YLeft, tr("Time (s)")); - setAxisAutoScale(QwtPlot::yLeft, false); + setAxisAutoScale(QwtAxis::YLeft, false); - setAxisAutoScale(QwtPlot::xTop, false); - setAxisScale(QwtPlot::xTop, -0.1, +0.1); + setAxisAutoScale(QwtAxis::XTop, false); + setAxisScale(QwtAxis::XTop, -0.1, +0.1); QVector divs; - QwtScaleEngine *engine = axisScaleEngine(QwtPlot::xTop); + QwtScaleEngine *engine = axisScaleEngine(QwtAxis::XTop); divs.push_back(engine->divideScale(-0.1, +0.1, 5, 5)); divs.push_back(engine->divideScale(-1.0, +1.0, 5, 5)); divs.push_back(engine->divideScale(-5.0, +5.0, 10, 2)); @@ -57,7 +57,7 @@ Sismograph::Sismograph(QWidget *parent) : QwtPlot(parent), plotLayout()->setAlignCanvasToScales(true); curve.attach(this); - curve.setXAxis(QwtPlot::xTop); + curve.setXAxis(QwtAxis::XTop); } Sismograph::~Sismograph() @@ -91,7 +91,7 @@ void Sismograph::setNumSamples(int num) ydata.resize(numSamples + 1); xdata.reserve(numSamples + 1); - setAxisScale(QwtPlot::yLeft, (double) numSamples / sampleRate, 0.0); + setAxisScale(QwtAxis::YLeft, (double) numSamples / sampleRate, 0.0); setSampleRate(sampleRate); replot(); @@ -125,7 +125,7 @@ void Sismograph::setColor(const QColor& color) void Sismograph::updateScale(const QwtScaleDiv div) { - setAxisScale(QwtPlot::xTop, div.lowerBound(), div.upperBound()); + setAxisScale(QwtAxis::XTop, div.lowerBound(), div.upperBound()); } void Sismograph::setLineWidth(qreal width) diff --git a/src/spectrum_analyzer.cpp b/src/spectrum_analyzer.cpp index 20b5f84bd9..b043f84d15 100644 --- a/src/spectrum_analyzer.cpp +++ b/src/spectrum_analyzer.cpp @@ -34,6 +34,9 @@ #include #include #include +#include +#include +#include /* Local includes */ #include "logging_categories.h" @@ -41,17 +44,26 @@ #include "filter.hpp" #include "math.hpp" #include "fft_block.hpp" -#include "dynamicWidget.hpp" -#include "channel_widget.hpp" -#include "db_click_buttons.hpp" +#include "gui/dynamicWidget.hpp" +#include "gui/channel_widget.hpp" +#include "gui/db_click_buttons.hpp" #include "filemanager.h" #include "spectrum_analyzer_api.hpp" #include "stream_to_vector_overlap.h" +#include "tool_launcher.hpp" + +#ifdef SPECTRAL_MSR +#include "gui/measure.h" +#include "measurement_gui.h" +#include "gui/measure_settings.h" +#endif /* Generated UI */ #include "ui_spectrum_analyzer.h" #include "ui_cursors_settings.h" #include "ui_cursor_readouts.h" +#include "ui_measure_panel.h" +#include "ui_measure_settings.h" #include #include @@ -208,8 +220,17 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, settings_group->addButton(ui->btnMarkers); settings_group->addButton(ui->btnAddRef); settings_group->addButton(ui->btnCursors); + +#ifdef SPECTRAL_MSR + settings_group->addButton(ui->btnMeasure); +#endif settings_group->setExclusive(true); +#ifdef SPECTRAL_MSR + /* Measure panel */ + measure_panel_init(); +#endif + fft_plot = new FftDisplayPlot(m_adc_nb_channels, this); fft_plot->disableLegend(); @@ -217,13 +238,63 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, fft_plot->setXaxisMouseGesturesEnabled(false); for (uint i = 0; i < m_adc_nb_channels; i++) { +// ui->gridLayout_plot->addWidget(measurePanel, 0, 1, 1, 1); fft_plot->setYaxisMouseGesturesEnabled(i, false); } - ui->gridLayout_plot->addWidget(fft_plot->getPlotwithElements(), 1, 0, 1, 1); + connect(fft_plot, SIGNAL(channelAdded(int)), + SLOT(onChannelAdded(int))); + +#ifdef SPECTRAL_MSR + /* Measurements Settings */ + measure_settings_init(); +#endif + + + // plot widget + QWidget* centralWidget = new QWidget(this); + QVBoxLayout* vLayout = new QVBoxLayout(centralWidget); + vLayout->setContentsMargins(20, 0, 20, 20); + vLayout->setSpacing(10); + centralWidget->setLayout(vLayout); + +#ifdef SPECTRAL_MSR + vLayout->addWidget(measurePanel); +#endif + + ui->widgetPlotContainer->layout()->removeWidget(ui->topPlotWidget); + vLayout->addWidget(ui->topPlotWidget); + + vLayout->addWidget(fft_plot->getPlotwithElements()); + + ui->widgetPlotContainer->layout()->removeWidget(ui->markerTable); + vLayout->addWidget(ui->markerTable); + + if(prefPanel->getCurrent_docking_enabled()) { + + // main window for dock widget + QMainWindow* mainWindow = new QMainWindow(this); + mainWindow->setCentralWidget(0); + mainWindow->setWindowFlags(Qt::Widget); + ui->gridLayout_plot->addWidget(mainWindow, 1, 0, 1, 1); + + QDockWidget* dockWidget = DockerUtils::createDockWidget(mainWindow, centralWidget); + + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget); + +#ifdef PLOT_MENU_BAR_ENABLED + DockerUtils::configureTopBar(dockWidget); +#endif + + } else { + ui->gridLayout_plot->addWidget(centralWidget, 1, 0, 1, 1); + } + fft_plot->enableXaxisLabels(); fft_plot->enableYaxisLabels(); + setYAxisUnit(ui->cmb_units->currentText()); + fft_plot->setBtmHorAxisUnit("Hz"); // Initialize spectrum channels for (int i = 0 ; i < m_adc_nb_channels; i++) { @@ -298,7 +369,7 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, startStopRange = new StartStopRangeWidget(0); connect(startStopRange, &StartStopRangeWidget::rangeChanged, [=](double start, double stop){ fft_plot->setStartStop(start, stop); - fft_plot->setAxisScale(QwtPlot::xBottom, start, stop); + fft_plot->setAxisScale(QwtAxis::XBottom, start, stop); fft_plot->replot(); fft_plot->bottomHandlesArea()->repaint(); @@ -363,8 +434,8 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, ui->cmbGainMode->setCurrentIndex(0); // Initialize vertical axis controls - unit_per_div->setMinValue(1); - unit_per_div->setMaxValue(200/10); + unit_per_div->setMinValue(0.01); + unit_per_div->setMaxValue(500/10); // Configure plot peak capabilities for (uint i = 0; i < m_adc_nb_channels; i++) { @@ -439,6 +510,15 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, const bool visible = (channels[crt_channel_id]->averageType() != FftDisplayPlot::AverageType::SAMPLE); setCurrentAverageIndexLabel(crt_channel_id); +#ifdef SPECTRAL_MSR + /* Apply measurements for every new batch of data */ + connect(fft_plot, SIGNAL(newData()), SLOT(onNewDataReceived())); + + for (int i = 0; i < m_adc_nb_channels; i++) { + fft_plot->initChannelMeasurement(i); + } +#endif + connect(top, SIGNAL(valueChanged(double)), SLOT(onTopValueChanged(double))); connect(unit_per_div, SIGNAL(valueChanged(double)), @@ -465,8 +545,8 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, ui->gridSweepControls->addWidget(startStopRange, 0, 0, 2, 2); - unit_per_div->setValue(20); top->setValue(0); + bottom->setValue(-200); marker_freq_pos->setMinValue(1); marker_freq_pos->setMaxValue(startStopRange->getStopValue()); @@ -476,10 +556,21 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, ui->lblMagUnit->setText(ui->cmb_units->currentText()); ui->markerTable->hide(); + for (auto ch: qAsConst(channels)) { ch->setFftWindow(FftWinType::HAMMING, fft_size); } +#ifdef SPECTRAL_MSR + if (!runButton()->isChecked() && measurementsEnabled()) { + measureUpdateValues(); + } + + for (unsigned int i = 0; i < m_adc_nb_channels; i++) { + init_selected_measurements(i, {0, 1, 4, 5}); + } +#endif + connect(ui->logBtn, &QPushButton::toggled, fft_plot, &FftDisplayPlot::useLogFreq); connect(ui->logBtn, &QPushButton::toggled, @@ -623,6 +714,18 @@ SpectrumAnalyzer::SpectrumAnalyzer(struct iio_context *ctx, Filter *filt, readPreferences(); ui->btnHelp->setUrl("https://wiki.analog.com/university/tools/m2k/scopy/spectrumanalyzer"); + +#ifndef SPECTRAL_MSR + // TODO: enable measurements + ui->boxMeasure->setChecked(false); + ui->boxMeasure->setVisible(false); + ui->btnMeasure->setVisible(false); +#endif + +#ifdef __ANDROID__ + ui->btnAddRef->setIconSize(QSize(24, 24)); +#endif + } SpectrumAnalyzer::~SpectrumAnalyzer() @@ -645,6 +748,12 @@ SpectrumAnalyzer::~SpectrumAnalyzer() delete *it; } +#ifdef SPECTRAL_MSR + for (auto it = d_measureObjs.begin(); it != d_measureObjs.end(); ++it) { + delete *it; + } +#endif + if (iio) { bool started = isIioManagerStarted(); @@ -673,6 +782,8 @@ void SpectrumAnalyzer::setNativeDialogs(bool nativeDialogs) } void SpectrumAnalyzer::readPreferences() { + bool showFps = prefPanel->getShow_plot_fps(); + fft_plot->setVisibleFpsLabel(showFps); fft_plot->setVisiblePeakSearch(prefPanel->getSpectrum_visible_peak_search()); ui->instrumentNotes->setVisible(prefPanel->getInstrumentNotesActive()); } @@ -806,9 +917,18 @@ void SpectrumAnalyzer::toggleRightMenu(CustomPushButton *btn, bool checked) index = 3; } else if (btn == ui->btnAddRef) { index = 4; + +#ifdef SPECTRAL_MSR + } else if (btn == ui->btnMeasure) { + index = 5; + } else if (btn == ui->btnCursors) { + index = 6; + } +#else } else if (btn == ui->btnCursors) { index = 5; } +#endif } if (id != -1) { @@ -903,6 +1023,412 @@ void SpectrumAnalyzer::on_btnMarkers_toggled(bool checked) static_cast(QObject::sender()), checked); } +#ifdef SPECTRAL_MSR +void SpectrumAnalyzer::on_btnMeasure_toggled(bool checked) { + triggerRightMenuToggle(static_cast(QObject::sender()), + checked); +} + +void SpectrumAnalyzer::measure_settings_init() +{ + measure_settings = new MeasureSettings(&d_measureObjs, this, false); + int measure_panel = ui->stackedWidget->insertWidget(5, measure_settings); + + ui->btnMeasure->setDisabled(true); + + connect(measure_settings, + SIGNAL(measurementActivated(int, int)), + SLOT(onMeasurementActivated(int, int))); + + connect(measure_settings, + SIGNAL(measurementDeactivated(int, int)), + SLOT(onMeasurementDeactivated(int, int))); + + connect(measure_settings, + SIGNAL(measurementSelectionListChanged()), + SLOT(onMeasurementSelectionListChanged())); + + connect(fft_plot, SIGNAL(channelAdded(int)), + measure_settings, SLOT(onChannelAdded(int))); + + connect(this, SIGNAL(selectedChannelChanged(int)), + measure_settings, SLOT(setSelectedChannel(int))); + + connect(ui->boxMeasure, SIGNAL(toggled(bool)), + SLOT(setMeasuremensEnabled(bool))); + +} + +void SpectrumAnalyzer::onChannelAdded(int chnIdx) +{ + Measure *measure = nullptr; + + if(fft_plot->isReferenceWaveform(chnIdx)) + { + int idx = chnIdx - fft_plot->getYdata_size(); + size_t curve_size = fft_plot->getCurveSize(chnIdx); + double* data = new double [curve_size](); + measure = new Measure(chnIdx, data, curve_size, + nullptr, false); + } + else + { + int64_t numPoints = fft_plot->getNumPoints() / 2; + std::vector scale_factor = fft_plot->getScaleFactor(); + + //std::vector data = fft_plot->getOrginal_data(); + //int count = fft_plot->countReferenceWaveform(chnIdx); + double* data = new double [numPoints](); + measure = new Measure(chnIdx, data, + numPoints, nullptr, false); + } + measure->setAdcBitCount(12); + d_measureObjs.push_back(measure); + +} + + +void SpectrumAnalyzer::update_measure_for_channel(int ch_idx) { + ChannelWidget *chn_widget = getChannelWidgetAt(ch_idx); + + measure_settings->setChannelName(chn_widget->fullName()); + measure_settings->setChannelUnderlineColor(chn_widget->color()); +} + + +void SpectrumAnalyzer::measure_panel_init() { + measurePanel = new QWidget(this); + measure_panel_ui = new Ui::MeasurementsPanel(); + measure_panel_ui->setupUi(measurePanel); + + connect(measure_panel_ui->scrollArea->horizontalScrollBar(), &QScrollBar::rangeChanged, + measure_panel_ui->scrollArea_2->horizontalScrollBar(), &QScrollBar::setRange); + + connect(measure_panel_ui->scrollArea_2->horizontalScrollBar(), &QScrollBar::valueChanged, + measure_panel_ui->scrollArea->horizontalScrollBar(), &QScrollBar::setValue); + connect(measure_panel_ui->scrollArea->horizontalScrollBar(), &QScrollBar::valueChanged, + measure_panel_ui->scrollArea_2->horizontalScrollBar(), &QScrollBar::setValue); + + connect(measure_panel_ui->scrollArea->horizontalScrollBar(), &QScrollBar::rangeChanged, + [=](double v1, double v2){ + measure_panel_ui->scrollArea_2->widget()->setFixedWidth(measure_panel_ui->scrollAreaWidgetContents->width()); + }); + + measurePanel->hide(); + + connect(this, SIGNAL(measurementsAvailable()), + SLOT(onMeasuremetsAvailable())); + +} + +void SpectrumAnalyzer::init_selected_measurements(int chnIdx, + std::vector measureIdx) +{ + auto measurements_val = measurements(chnIdx); + for (int i = 0; i < measureIdx.size(); i++) { + measurements_val[measureIdx[i]]->setEnabled(true); + measure_settings->onMeasurementActivated( + chnIdx, measureIdx[i], true); + } + measure_settings->loadMeasurementStatesFromData(); + onMeasurementSelectionListChanged(); +} + +std::shared_ptr SpectrumAnalyzer::measurement(int id, int chnIdx) +{ + Measure *measure = measureOfChannel(chnIdx); + if (measure) + return measure->measurement(id); + else + return std::shared_ptr(); +} + +void SpectrumAnalyzer::onMeasurementActivated(int id, int chnIdx) +{ + int oldActiveMeasCount = activeMeasurementsCount(chnIdx); + + auto mList = measurements(chnIdx); + mList[id]->setEnabled(true); + measurements_data.push_back(mList[id]); + measureCreateAndAppendGuiFrom(*mList[id]); + + if (oldActiveMeasCount == 0) { + measure(); + } + + measureLabelsRearrange(); +} + +void SpectrumAnalyzer::onMeasurementDeactivated(int id, int chnIdx) +{ + auto mList = measurements(chnIdx); + QString name = mList[id]->name(); + + mList[id]->setEnabled(false); + + auto it = find_if(measurements_data.begin(), measurements_data.end(), + [&](std::shared_ptr const& p) + { return (p->name() == name) && (p->channel() == chnIdx); }); + if (it != measurements_data.end()) { + int i = it - measurements_data.begin(); + measurements_data.removeAt(i); + measurements_gui.removeAt(i); + measureLabelsRearrange(); + } +} + +void SpectrumAnalyzer::onMeasurementSelectionListChanged() +{ + // Clear all measurements in list + for (int i = 0; i < measurements_data.size(); i++) { + measurements_data[i]->setEnabled(false); + } + measurements_data.clear(); + measurements_gui.clear(); + + // Use the new list from MeasureSettings + auto newList = measure_settings->measurementSelection(); + for (int i = 0; i < newList.size(); i++) { + auto pMeasurement = measurement(newList[i].id(), + newList[i].channel_id()); + if (pMeasurement) { + pMeasurement->setEnabled(true); + measurements_data.push_back(pMeasurement); + measureCreateAndAppendGuiFrom(*pMeasurement); + } + } + measureLabelsRearrange(); +} + +void SpectrumAnalyzer::measureCreateAndAppendGuiFrom(const MeasurementData& + measurement) +{ + std::shared_ptr p; + + switch(measurement.unitType()) { + + case MeasurementData::DECIBELS: + p = std::make_shared(); + break; + case MeasurementData::DECIBELS_TO_CARRIER: + p = std::make_shared(); + break; + case MeasurementData::DIMENSIONLESS: + p = std::make_shared(); + break; + default: + break; + } + if (p) + measurements_gui.push_back(p); +} + +void SpectrumAnalyzer::measureLabelsRearrange() +{ + QWidget *container = measure_panel_ui->measurements-> + findChild("container"); + + if (container) { + measure_panel_ui->measurements->layout()->removeWidget(container); + delete container; + } + + container = new QWidget(); + container->setObjectName("container"); + if (!measure_panel_ui->measurements->layout()) { + QVBoxLayout *measurementsLayout = new + QVBoxLayout(measure_panel_ui->measurements); + measurementsLayout->addWidget(container); + measurementsLayout->setContentsMargins(0, 0, 0, 0); + } else { + measure_panel_ui->measurements->layout()->addWidget(container); + } + + QGridLayout *gLayout = new QGridLayout(container); + + gLayout->setContentsMargins(0, 0, 0, 0); + gLayout->setVerticalSpacing(5); + gLayout->setHorizontalSpacing(5); + int max_rows = 4; + int nb_meas_added = 0; + + for (int i = 0; i < measurements_data.size(); i++) { + + int channel = measurements_data[i]->channel(); + if (channel >= m_adc_nb_channels + nb_ref_channels) { + continue; + } + + ChannelWidget *chn_widget = getChannelWidgetAt(channel); + if (!chn_widget->enableButton()->isChecked()) { + continue; + } + + QLabel *name = new QLabel(); + QLabel *value = new QLabel(); + + + int row = nb_meas_added % max_rows; + int col = nb_meas_added / max_rows; + + gLayout->addWidget(name, row, 2 * col); + + QHBoxLayout *value_layout = new QHBoxLayout(); + value_layout->setContentsMargins(0, 0, 10, 0); + value_layout->addWidget(value); + gLayout->addLayout(value_layout, row, 2 * col + 1); + + measurements_gui[i]->init(name, value); + double pb_atten = 1; + measurements_gui[i]->update(*(measurements_data[i]), + pb_atten); + measurements_gui[i]->setLabelsColor(fft_plot->getLineColor(channel)); + + nb_meas_added++; + } +} + +QList> SpectrumAnalyzer::measurements(int chnIdx) +{ + //POATE O SA POT PUNE DIRECT MEASURE OF CHANNALE, IN LOC DE FCT ASTA?? + Measure *measure = measureOfChannel(chnIdx); + + if (measure) + return measure->measurments(); + else + return QList>(); +} + +Measure* SpectrumAnalyzer::measureOfChannel(int chnIdx) const +{ + Measure *measure = nullptr; + + auto it = std::find_if(d_measureObjs.begin(), d_measureObjs.end(), + [&](Measure *m) { return m->channel() == chnIdx; }); + if (it != d_measureObjs.end()) + measure = *it; + + return measure; +} + +int SpectrumAnalyzer::activeMeasurementsCount(int chnIdx) +{ + int count = -1; + Measure *measure = measureOfChannel(chnIdx); + + if (measure) + count = measure->activeMeasurementsCount(); + + return count; +} + +bool SpectrumAnalyzer::measurementsEnabled() +{ + return d_measurementsEnabled; +} + +void SpectrumAnalyzer::setMeasuremensEnabled(bool en) +{ + d_measurementsEnabled = en; + + if (en) { + ui->btnMeasure->setEnabled(true); + } else { + if (ui->btnMeasure->isChecked()) + ui->btnMeasure->setChecked(false); + + ui->btnMeasure->setEnabled(false); + + menuOrder.removeOne(ui->btnMeasure); + } +} + +void SpectrumAnalyzer::computeMeasurementsForChannel(unsigned int chnIdx, unsigned int sampleRate) +{ + if (chnIdx >= d_measureObjs.size()) { + return; + } + + Measure *measure = d_measureObjs[chnIdx]; + measure->setSampleRate(sampleRate); + measure->measure(); + + Q_EMIT measurementsAvailable(); +} + +void SpectrumAnalyzer::measure() +{ + for (int i = 0; i < d_measureObjs.size(); i++) { + Measure *measure = d_measureObjs[i]; + if (measure->activeMeasurementsCount() > 0) { + measure->setSampleRate(fft_plot->sampleRate()); + measure->measure(); + } + } +} + +void SpectrumAnalyzer::onNewDataReceived() +{ + int ref_idx = 0; + for (int i = 0; i < d_measureObjs.size(); i++) { + Measure *measure = d_measureObjs[i]; + int chn = measure->channel(); + if (fft_plot->isReferenceWaveform(chn)) { + size_t curve_size = fft_plot->getCurveSize(chn); + measure->setDataSource(fft_plot->getRef_data()[ref_idx], + curve_size / 2); + ref_idx++; + } + else { + int64_t numPoints = fft_plot->getNumPoints() / 2; + std::vector data = fft_plot->getOrginal_data(); + std::vector scale_factor = fft_plot->getScaleFactor(); + + //int count = fft_plot->countReferenceWaveform(chn); + //chn = chn - count; + for (int s = 0; s < numPoints; s++) { + data[chn][s] = sqrt(data[chn][s]) * scale_factor[chn] / numPoints; + } + measure->setDataSource(data[chn], numPoints); + } + measure->setSampleRate(sample_rate); + measure->measure(); + } + + Q_EMIT measurementsAvailable(); +} + +void SpectrumAnalyzer::onMeasuremetsAvailable() +{ + measureUpdateValues(); +} + +void SpectrumAnalyzer::measureUpdateValues() +{ + + for (int i = 0; i < measurements_data.size(); i++) { + int channel = measurements_data[i]->channel(); + ChannelWidget *chn_widget = getChannelWidgetAt(channel); + if (!chn_widget->enableButton()->isChecked()) { + continue; + } + measurements_gui[i]->update(*(measurements_data[i]), + 1.0f); // de modificat scale-ul + } +} + +void SpectrumAnalyzer::on_boxMeasure_toggled(bool checked) { + if (checked) { + update_measure_for_channel(crt_channel_id); + } else { + if (ui->btnMeasure->isChecked()) + ui->btnMeasure->setChecked(false); + menuOrder.removeOne(ui->btnMeasure); + } + measurePanel->setVisible(checked); +} +#endif + void SpectrumAnalyzer::on_btnAddRef_toggled(bool checked) { triggerRightMenuToggle( @@ -1072,6 +1598,15 @@ QString SpectrumAnalyzer::getReferenceChannelName() const return QString("REF %1").arg(current); } +void SpectrumAnalyzer::setYAxisUnit(const QString& unit) +{ + if (unit == "dBFS" || unit == "dBu" || unit == "dBV") { + fft_plot->setLeftVertAxisUnit("db"); + } else if (unit == "Vpeak" || unit == "Vrms" || unit == "V/√Hz") { + fft_plot->setLeftVertAxisUnit("V"); + } +} + void SpectrumAnalyzer::add_ref_waveform(QVector xData, QVector yData) { if (nb_ref_channels == MAX_REF_CHANNELS) { @@ -1117,6 +1652,12 @@ void SpectrumAnalyzer::add_ref_waveform(QVector xData, QVector y if (nb_ref_channels == MAX_REF_CHANNELS) { ui->btnAddRef->hide(); } + +#ifdef SPECTRAL_MSR + init_selected_measurements(curve_id, {0, 1, 4, 5}); + + computeMeasurementsForChannel(curve_id, sample_rate); +#endif } void SpectrumAnalyzer::add_ref_waveform(unsigned int chIdx) @@ -1132,6 +1673,22 @@ void SpectrumAnalyzer::add_ref_waveform(unsigned int chIdx) add_ref_waveform(xData, yData); } +#ifdef SPECTRAL_MSR +void SpectrumAnalyzer::cleanUpMeasurementsBeforeChannelRemoval(int chnIdx) +{ + Measure *measure = measureOfChannel(chnIdx); + if (measure) { + int pos = d_measureObjs.indexOf(measure); + for (int i = pos + 1; i < d_measureObjs.size(); i++) { + d_measureObjs[i]->setChannel( + d_measureObjs[i]->channel() - 1); + } + d_measureObjs.removeOne(measure); + delete measure; + } +} +#endif + void SpectrumAnalyzer::onReferenceChannelDeleted() { if (nb_ref_channels - 1 < MAX_REF_CHANNELS) { @@ -1141,6 +1698,29 @@ void SpectrumAnalyzer::onReferenceChannelDeleted() ChannelWidget *channelWidget = static_cast(QObject::sender()); QAbstractButton *delBtn = channelWidget->deleteButton(); QString qname = delBtn->property("curve_name").toString(); + int curve_id = channelWidget->id(); + + /*If there are no more channels enabled, we should + disable the measurements.*/ + bool shouldDisable = true; + + for (unsigned int i = 0; i < m_adc_nb_channels + nb_ref_channels; i++) { + ChannelWidget *cw = static_cast( + ui->channelsList->itemAt(i)->widget()); + if (curve_id == cw->id()) + continue; + if (cw->enableButton()->isChecked()) + shouldDisable = false; + } + +#ifdef SPECTRAL_MSR + if (shouldDisable) + measure_settings->disableDisplayAll(); + + measure_settings->onChannelRemoved(channelWidget->id()); + + cleanUpMeasurementsBeforeChannelRemoval(channelWidget->id()); +#endif fft_plot->unregisterReferenceWaveform(qname); ui->channelsList->removeWidget(channelWidget); @@ -1164,6 +1744,11 @@ void SpectrumAnalyzer::onReferenceChannelDeleted() if (channelWidget->id() < crt_channel_id) { crt_channel_id--; Q_EMIT selectedChannelChanged(crt_channel_id); + +#ifdef SPECTRAL_MSR + update_measure_for_channel(crt_channel_id); +#endif + } else if (channelWidget->id() == crt_channel_id) { for (int i = 0; i < m_adc_nb_channels + nb_ref_channels; ++i) { auto cw = getChannelWidgetAt(i); @@ -1173,10 +1758,24 @@ void SpectrumAnalyzer::onReferenceChannelDeleted() if (cw->enableButton()->isChecked()) { channelsEnabled = true; Q_EMIT selectedChannelChanged(0); + +#ifdef SPECTRAL_MSR + update_measure_for_channel(0); +#endif + cw->nameButton()->setChecked(true); + Q_EMIT selectedChannelChanged(cw->id()); +#ifdef SPECTRAL_MSR + update_measure_for_channel(cw->id()); +#endif + break; } } + if (!channelsEnabled) { + crt_channel_id = 0; + Q_EMIT selectedChannelChanged(0); + } } if (ui->btnMarkers->isChecked() && !channelsEnabled) { @@ -1196,6 +1795,9 @@ void SpectrumAnalyzer::onReferenceChannelDeleted() menuOrder.removeAll(static_cast(channelWidget->menuButton())); } +#ifdef SPECTRAL_MSR + onMeasurementSelectionListChanged(); +#endif delete channelWidget; } @@ -1211,19 +1813,11 @@ void SpectrumAnalyzer::stop() void SpectrumAnalyzer::runStopToggled(bool checked) { - ui->comboBox_line_thickness->setEnabled(!checked); - ui->comboBox_line_thickness->setCurrentIndex(1); - if (checked) { if (iio) { writeAllSettingsToHardware(); } - for(int i = 0;i < channels.size();i++) - { - fft_plot->setLineWidth(i, 1); - } - fft_plot->presetSampleRate(sample_rate); fft_sink->set_samp_rate(sample_rate); m_time_start = std::chrono::system_clock::now(); @@ -1237,6 +1831,7 @@ void SpectrumAnalyzer::runStopToggled(bool checked) if (!checked) { fft_plot->resetAverageHistory(); } + fft_plot->startStop(checked); m_running = checked; } @@ -1247,6 +1842,9 @@ void SpectrumAnalyzer::build_gnuradio_block_chain() (QObject *)fft_plot); fft_sink->set_trigger_mode(TRIG_MODE_TAG, 0, "buffer_start"); + double targetFps = getScopyPreferences()->getTarget_fps(); + fft_sink->set_update_time(1.0/targetFps); + bool started = isIioManagerStarted(); if (started) { @@ -1289,6 +1887,9 @@ void SpectrumAnalyzer::build_gnuradio_block_chain_no_ctx() "Osc Frequency", m_adc_nb_channels, (QObject *)fft_plot); + double targetFps = getScopyPreferences()->getTarget_fps(); + fft_sink->set_update_time(1.0/targetFps); + top_block = gr::make_top_block("spectrum_analyzer"); for (int i = 0; i < m_adc_nb_channels; i++) { @@ -1417,22 +2018,20 @@ void SpectrumAnalyzer::on_comboBox_window_currentIndexChanged(const QString& s) void SpectrumAnalyzer::on_comboBox_line_thickness_currentIndexChanged(int index) { - int crt_channel = channelIdOfOpenedSettings(); + int crt_channel = channelIdOfOpenedSettings(); - if (crt_channel < 0) { - qDebug(CAT_SPECTRUM_ANALYZER) << "invalid channel ID for the opened Settings menu"; - return; - } + if (crt_channel < 0) { + qDebug(CAT_SPECTRUM_ANALYZER) << "invalid channel ID for the opened Settings menu"; + return; + } - qreal width = 0.5 * (index + 1); + qreal width = 0.5 * (index + 1); - if (width != channels[crt_channel]->lineWidth()) { - channels[crt_channel]->setLinewidth(width); - if(!isRunning()) { + if (width != channels[crt_channel]->lineWidth()) { + channels[crt_channel]->setLinewidth(width); fft_plot->setLineWidth(crt_channel, width); fft_plot->replot(); } - } } void SpectrumAnalyzer::on_spinBox_averaging_valueChanged(int n) @@ -1613,6 +2212,12 @@ void SpectrumAnalyzer::onChannelSelected(bool en) triggerRightMenuToggle( static_cast(ui->btnMarkers), en); } + +#ifdef SPECTRAL_MSR + if (measurementsEnabled()) { + update_measure_for_channel(chIdx); + } +#endif } void SpectrumAnalyzer::updateMarkerMenu(unsigned int id) @@ -1662,17 +2267,42 @@ void SpectrumAnalyzer::onChannelEnabled(bool en) ui->btnMarkers->setEnabled(true); ui->btnMarkers->blockSignals(false); } + + bool shouldActivate = true; + if (cw->enableButton()->isChecked()) { + shouldActivate = false; + } + + if (shouldActivate) { + //nu trebe asta + Q_EMIT selectedChannelChanged(cw->id()); + +#ifdef SPECTRAL_MSR + update_measure_for_channel(cw->id()); + measure_settings->activateDisplayAll(); +#endif + } + } else { bool allDisabled = true; + bool shouldDisable = true; for (int i = 0; i < channels.size() + nb_ref_channels; i++) { ChannelWidget *cw = getChannelWidgetAt(i); if (cw->enableButton()->isChecked()) { cw->nameButton()->setChecked(true); allDisabled = false; + shouldDisable = false; break; } } + +#ifdef SPECTRAL_MSR + if (shouldDisable) { + measure_settings->disableDisplayAll(); + } +#endif + if (allDisabled) { QSignalBlocker(ui->btnMarkers); if (!ui->btnSweep->isChecked()) { @@ -1694,6 +2324,9 @@ void SpectrumAnalyzer::onChannelEnabled(bool en) } } +#ifdef SPECTRAL_MSR + measureLabelsRearrange(); +#endif fft_plot->replot(); updateRunButton(en); @@ -1808,6 +2441,19 @@ void SpectrumAnalyzer::on_btnMaxPeak_clicked() void SpectrumAnalyzer::on_cmb_rbw_currentIndexChanged(int index) { + double update_time = 1.0/getScopyPreferences()->getTarget_fps(); + switch(bin_sizes[index]) { + case 1<<17: + fft_sink->set_update_time(update_time * 2); + break; + case 1<<18: + fft_sink->set_update_time(update_time * 4); + break; + default: + fft_sink->set_update_time(update_time); + break; + } + uint new_fft_size = bin_sizes[index]; if (new_fft_size != fft_size) { @@ -2230,7 +2876,12 @@ void SpectrumAnalyzer::on_cmb_units_currentIndexChanged(const QString& unit) ui->divisionWidget->setCurrentIndex(stackedWidgetCurrentIdx); top_scale->setValue(2.5E1); bottom_scale->setValue(1E-12); - fft_plot->setAxisScale(QwtPlot::yLeft, bottom_scale->value(), top_scale->value()); + fft_plot->setAxisScale(QwtAxis::YLeft, bottom_scale->value(), top_scale->value()); + + fft_plot->replot(); + fft_plot->setYaxisMajorTicksPos(fft_plot->axisScaleDiv(QwtAxis::YLeft).ticks(2)); + fft_plot->leftHandlesArea()->repaint(); + break; default: ui->divisionWidget->setVisible(true); @@ -2243,6 +2894,8 @@ void SpectrumAnalyzer::on_cmb_units_currentIndexChanged(const QString& unit) fft_plot->setMagnitudeType((*it).second); fft_plot->recalculateMagnitudes(); + setYAxisUnit(unit); + fft_plot->replot(); fft_plot->leftHandlesArea()->repaint(); @@ -2256,19 +2909,19 @@ void SpectrumAnalyzer::on_cmb_units_currentIndexChanged(const QString& unit) switch (magType) { case FftDisplayPlot::VPEAK: case FftDisplayPlot::VRMS: - unit_per_div->setValue(2); bottom->setValue(-10); - fft_plot->setAxisScale(QwtPlot::yLeft, bottom->value(), top->value()); + unit_per_div->setValue(2); + fft_plot->setAxisScale(QwtAxis::YLeft, bottom->value(), top->value()); break; case FftDisplayPlot::VROOTHZ: top_scale->setValue(2.5E1); bottom_scale->setValue(1E-12); - fft_plot->setAxisScale(QwtPlot::yLeft, bottom_scale->value(), top_scale->value()); + fft_plot->setAxisScale(QwtAxis::YLeft, bottom_scale->value(), top_scale->value()); break; default: - unit_per_div->setValue(20); + top->setValue(0); bottom->setValue(-200); - fft_plot->setAxisScale(QwtPlot::yLeft, bottom->value(), top->value()); + fft_plot->setAxisScale(QwtAxis::YLeft, bottom->value(), top->value()); break; } }); @@ -2301,20 +2954,20 @@ void SpectrumAnalyzer::on_btnMarkerTable_toggled(bool checked) ui->markerTable->setVisible(checked); // Set the Plot 3 times taller than the Marker Table (when visible) - QGridLayout *layout = static_cast( - ui->widgetPlotContainer->layout()); - int row1 = getGridLayoutPosFromIndex(layout, - layout->indexOf(ui->markerTable)).first; - int row2 = getGridLayoutPosFromIndex(layout, - layout->indexOf(ui->gridLayout_plot)).first; - - if (checked) { - layout->setRowStretch(row1, 1); - layout->setRowStretch(row2, 3); - } else { - layout->setRowStretch(row1, 0); - layout->setRowStretch(row2, 0); - } +// QGridLayout *layout = static_cast( +// ui->widgetPlotContainer->layout()); +// int row1 = getGridLayoutPosFromIndex(layout, +// layout->indexOf(ui->markerTable)).first; +// int row2 = getGridLayoutPosFromIndex(layout, +// layout->indexOf(ui->gridLayout_plot)).first; + +// if (checked) { +// layout->setRowStretch(row1, 1); +// layout->setRowStretch(row2, 3); +// } else { +// layout->setRowStretch(row1, 0); +// layout->setRowStretch(row2, 0); +// } } QPair SpectrumAnalyzer::getGridLayoutPosFromIndex(QGridLayout *layout, @@ -2335,19 +2988,23 @@ QPair SpectrumAnalyzer::getGridLayoutPosFromIndex(QGridLayout *layout, void SpectrumAnalyzer::onTopValueChanged(double top_value) { bool isScaleBtn = ui->topWidget->currentIndex(); - double perDiv = unit_per_div->value(); - double bottomValue = top_value - perDiv * 10; + double bottom_value; if (!isScaleBtn) { - bottom->blockSignals(true); - bottom->setValue(bottomValue); - bottom->blockSignals(false); - fft_plot->setAxisScale(QwtPlot::yLeft, bottom->value(), top->value()); + bottom_value = bottom->value(); + + unit_per_div->blockSignals(true); + unit_per_div->setValue(abs((top_value - bottom_value)/10)); + unit_per_div->blockSignals(false); + } else { - fft_plot->setAxisScale(QwtPlot::yLeft, bottom_scale->value(), top_value); + bottom_value = bottom_scale->value(); } + + fft_plot->setAxisScale(QwtAxis::YLeft, bottom_value, top_value); + fft_plot->replot(); - auto div = fft_plot->axisScaleDiv(QwtPlot::yLeft); + auto div = fft_plot->axisScaleDiv(QwtAxis::YLeft); fft_plot->setYaxisMajorTicksPos(div.ticks(2)); fft_plot->leftHandlesArea()->repaint(); } @@ -2355,44 +3012,57 @@ void SpectrumAnalyzer::onTopValueChanged(double top_value) void SpectrumAnalyzer::onScalePerDivValueChanged(double perDiv) { bool isScaleBtn = ui->topWidget->currentIndex(); + double topValue, bottomValue; + if (isScaleBtn) { - double topValue = bottom_scale->value() + perDiv * 10; + + bottomValue = bottom_scale->value(); + topValue = bottomValue + perDiv * 10; + + top_scale->blockSignals(true); top_scale->setValue(topValue); + top_scale->blockSignals(false); - double bottomValue = top_scale->value() - perDiv * 10; - if (bottomValue != bottom_scale->value()) { - bottom_scale->setValue(bottomValue); - } } else { bottom->setMaxValue(m_mag_min_max.second - perDiv * 10); top->setMinValue(m_mag_min_max.first + perDiv * 10); - double topValue = bottom->value() + perDiv * 10; - top->setValue(topValue); + bottomValue = bottom->value(); + topValue = bottomValue + perDiv * 10; - double bottomValue = top->value() - perDiv * 10; - if (bottomValue != bottom->value()) { - bottom->setValue(bottomValue); - } + top->blockSignals(true); + top->setValue(topValue); + top->blockSignals(false); } + + fft_plot->setAxisScale(QwtAxis::YLeft, bottomValue, topValue); + + fft_plot->replot(); + auto div = fft_plot->axisScaleDiv(QwtAxis::YLeft); + fft_plot->setYaxisMajorTicksPos(div.ticks(2)); + fft_plot->leftHandlesArea()->repaint(); } void SpectrumAnalyzer::onBottomValueChanged(double bottom_value) { bool isScaleBtn = ui->topWidget->currentIndex(); - double perDiv = unit_per_div->value(); - double topValue = bottom_value + perDiv * 10; + double top_value; if (!isScaleBtn) { - top->blockSignals(true); - top->setValue(topValue); - top->blockSignals(false); - fft_plot->setAxisScale(QwtPlot::yLeft, bottom->value(), top->value()); + top_value = top->value(); + + unit_per_div->blockSignals(true); + unit_per_div->setValue(abs((top_value - bottom_value)/10)); + unit_per_div->blockSignals(false); + } else { - fft_plot->setAxisScale(QwtPlot::yLeft, bottom_value, top_scale->value()); + top_value = top_scale->value(); } + + fft_plot->setAxisScale(QwtAxis::YLeft, bottom_value, top_value); + fft_plot->replot(); - auto div = fft_plot->axisScaleDiv(QwtPlot::yLeft); + auto div = fft_plot->axisScaleDiv(QwtAxis::YLeft); fft_plot->setYaxisMajorTicksPos(div.ticks(2)); fft_plot->leftHandlesArea()->repaint(); } diff --git a/src/spectrum_analyzer.hpp b/src/spectrum_analyzer.hpp index 938e39bf05..5d5a08bdc1 100644 --- a/src/spectrum_analyzer.hpp +++ b/src/spectrum_analyzer.hpp @@ -32,9 +32,13 @@ #include "FftDisplayPlot.h" #include "tool.hpp" #include "plot_utils.hpp" -#include "spinbox_a.hpp" -#include "customPushButton.hpp" -#include "startstoprangewidget.h" +#include "gui/spinbox_a.hpp" +#include "gui/customPushButton.hpp" +#include "gui/startstoprangewidget.h" + +#ifdef SPECTRAL_MSR +#include "gui/measure.h" +#endif #include #include @@ -56,6 +60,10 @@ namespace Ui { class SpectrumAnalyzer; class CursorReadouts; class CursorsSettings; + +#ifdef SPECTRAL_MSR +class MeasurementsPanel; +#endif } namespace adiscope { @@ -63,6 +71,11 @@ class SpectrumChannel; class Filter; class ChannelWidget; class DbClickButtons; + +#ifdef SPECTRAL_MSR +class MeasurementData; +class MeasurementGui; +#endif } class QPushButton; @@ -74,6 +87,10 @@ class SpectrumAnalyzer_API; class SpectrumChannel_API; class SpectrumMarker_API; +#ifdef SPECTRAL_MSR +class MeasureSettings; +#endif + class SpectrumAnalyzer: public Tool { friend class SpectrumChannel_API; @@ -115,6 +132,10 @@ public Q_SLOTS: void showTool(); void selectedChannelChanged(int); +#ifdef SPECTRAL_MSR + void measurementsAvailable(); +#endif + private Q_SLOTS: void on_btnHistory_toggled(bool checked); void onCurrentAverageIndexChanged(uint chnIdx, uint avgIdx); @@ -123,6 +144,20 @@ private Q_SLOTS: void on_btnSweep_toggled(bool checked); void on_btnMarkers_toggled(bool checked); +#ifdef SPECTRAL_MSR + void on_btnMeasure_toggled(bool); + void on_boxMeasure_toggled(bool); + + void onMeasuremetsAvailable(); + void onMeasurementActivated(int id, int chnIdx); + void onMeasurementDeactivated(int id, int chnIdx); + void onMeasurementSelectionListChanged(); + + void setMeasuremensEnabled(bool en); + void onChannelAdded(int); + void onNewDataReceived(); +#endif + void on_boxCursors_toggled(bool on); void on_btnCursors_toggled(bool); void onCursorReadoutsChanged(struct cursorReadoutsText); @@ -184,6 +219,7 @@ private Q_SLOTS: void add_ref_waveform(QVector xData, QVector yData); void add_ref_waveform(unsigned int chIdx); QString getReferenceChannelName() const; + void setYAxisUnit(const QString& type); QList ch_api; QList marker_api; @@ -207,6 +243,15 @@ private Q_SLOTS: libm2k::analog::GenericAnalogIn* m_generic_analogin; Ui::SpectrumAnalyzer *ui; +#ifdef SPECTRAL_MSR + QWidget *measurePanel; + Ui::MeasurementsPanel *measure_panel_ui; + adiscope::MeasureSettings *measure_settings; + QList> measurements_data; + QList> measurements_gui; + QList d_measureObjs; + bool d_measurementsEnabled; +#endif Ui::CursorReadouts *cursor_readouts_ui; QWidget *cursorReadouts; @@ -276,6 +321,31 @@ private Q_SLOTS: void fillCursorReadouts(const struct cursorReadoutsText &); bool canSwitchAverageHistory(FftDisplayPlot::AverageType avg_type); + +#ifdef SPECTRAL_MSR + //din capture plot + QList> measurements(int chnIdx); + std::shared_ptr measurement(int id, int chnIdx); + void measure(); + int activeMeasurementsCount(int chnIdx); + Measure* measureOfChannel(int chnIdx) const; + bool measurementsEnabled(); + void computeMeasurementsForChannel(unsigned int chnIdx, unsigned int sampleRate); + + void cleanUpMeasurementsBeforeChannelRemoval(int chnIdx); + + //functii normale + void settings_panel_update(int id); + void settings_panel_size_adjust(); + void update_measure_for_channel(int ch_idx); + + void measure_panel_init(); + void measure_settings_init(); + void init_selected_measurements(int, std::vector); + void measureUpdateValues(); + void measureLabelsRearrange(); + void measureCreateAndAppendGuiFrom(const MeasurementData&); +#endif }; class SpectrumChannel: public QObject diff --git a/src/spectrum_analyzer_api.cpp b/src/spectrum_analyzer_api.cpp index fc15c2612e..58f00d48eb 100644 --- a/src/spectrum_analyzer_api.cpp +++ b/src/spectrum_analyzer_api.cpp @@ -20,8 +20,8 @@ #include "spectrum_analyzer_api.hpp" #include "ui_spectrum_analyzer.h" #include "ui_cursors_settings.h" -#include "channel_widget.hpp" -#include "db_click_buttons.hpp" +#include "gui/channel_widget.hpp" +#include "gui/db_click_buttons.hpp" namespace adiscope { int SpectrumChannel_API::type() diff --git a/src/spectrum_marker.cpp b/src/spectrum_marker.cpp index d97175b29a..d67f17d952 100644 --- a/src/spectrum_marker.cpp +++ b/src/spectrum_marker.cpp @@ -27,8 +27,8 @@ using namespace adiscope; SpectrumMarker::SpectrumMarker(const QString &title, bool movable) : - QwtPlotMarker(title), m_xAxis(QwtPlot::xBottom), - m_yAxis(QwtPlot::yLeft), m_movable(movable), m_selected(false) + QwtPlotMarker(title), m_xAxis(QwtAxis::XBottom), + m_yAxis(QwtAxis::YLeft), m_movable(movable), m_selected(false) { } diff --git a/src/statistic_widget.cpp b/src/statistic_widget.cpp index 4ece129e9a..a567597333 100644 --- a/src/statistic_widget.cpp +++ b/src/statistic_widget.cpp @@ -19,7 +19,7 @@ */ #include "statistic_widget.h" -#include "measure.h" +#include "gui/measure.h" #include "plot_utils.hpp" #include "ui_statistic.h" diff --git a/src/symbol.cpp b/src/symbol.cpp index 0fb36f36e4..dd4c3e9a71 100644 --- a/src/symbol.cpp +++ b/src/symbol.cpp @@ -225,7 +225,7 @@ void Symbol::updateSurfacePos() QwtInterval interval = plot()->axisInterval(d_mobileAxis); if (d_within_plot) { - if (d_mobileAxis.pos == QwtPlot::yLeft) { + if (d_mobileAxis.pos == QwtAxis::YLeft) { if (plotCoord.y() < interval.minValue()) plotCoord.setY(interval.minValue()); else if (plotCoord.y() > interval.maxValue()) @@ -298,7 +298,7 @@ void Symbol::onMobileScaleChanged() VertDebugSymbol::VertDebugSymbol(QObject *parent, const QSize& size, bool opposedToFixed, bool floats): - Symbol(parent, size, QwtPlot::xBottom, QwtPlot::yLeft, opposedToFixed, + Symbol(parent, size, QwtAxis::XBottom, QwtAxis::YLeft, opposedToFixed, floats) { int x = opposedToFixed ? surface().width() : 0; @@ -390,7 +390,7 @@ void VertDebugSymbol::onBasePixelPositionChanged(int x, int y) HorizDebugSymbol::HorizDebugSymbol(QObject *parent, const QSize& size, bool opposedToFixed, bool floats): - Symbol(parent, size, QwtPlot::yLeft, QwtPlot::xBottom, opposedToFixed, + Symbol(parent, size, QwtAxis::YLeft, QwtAxis::XBottom, opposedToFixed, floats) { int y = opposedToFixed ? 0 : surface().height(); diff --git a/src/tool.cpp b/src/tool.cpp index 8fc02f6b07..e430a11f16 100644 --- a/src/tool.cpp +++ b/src/tool.cpp @@ -20,7 +20,7 @@ #include "tool.hpp" #include "tool_launcher.hpp" -#include "detachedwindowsmanager.h" +#include "gui/detachedwindowsmanager.h" #include @@ -51,6 +51,7 @@ Tool::Tool(struct iio_context *ctx, ToolMenuItem *toolMenuItem, readPreferences(); +#ifndef __ANDROID__ if (api) { connect(api, &ApiObject::loadingFinished, this, &Tool::loadState); @@ -58,8 +59,13 @@ Tool::Tool(struct iio_context *ctx, ToolMenuItem *toolMenuItem, connect(toolMenuItem, &ToolMenuItem::detach, this, &Tool::detached); +#endif connect(this, &Tool::detachedState, toolMenuItem, &ToolMenuItem::setDetached); + + // fixes bad ui rendering when dock->minimize->maximize + // TODO: may be removed after ToolLauncher refactoring + this->setVisible(false); } Tool::~Tool() @@ -123,6 +129,8 @@ void Tool::saveState() settings->sync(); } + +#ifndef __ANDROID__ void Tool::loadState() { bool isDetached = settings->value(name + "/detached").toBool(); @@ -160,6 +168,7 @@ void Tool::detached() this->window = window; } } +#endif void Tool::run() { diff --git a/src/tool.hpp b/src/tool.hpp index 70112e706b..ac9b509f5d 100644 --- a/src/tool.hpp +++ b/src/tool.hpp @@ -70,13 +70,17 @@ public Q_SLOTS: virtual void stop(); virtual void single(); virtual bool isRunning(); +#ifndef __ANDROID__ virtual void attached(); virtual void detached(); +#endif virtual void readPreferences(); private Q_SLOTS: void saveState(); +#ifndef __ANDROID__ void loadState(); +#endif protected: struct iio_context *ctx; diff --git a/src/tool_launcher.cpp b/src/tool_launcher.cpp index 373d4f050e..e7ada7db1e 100644 --- a/src/tool_launcher.cpp +++ b/src/tool_launcher.cpp @@ -20,21 +20,21 @@ #include "logging_categories.h" #include "config.h" -#include "connectDialog.hpp" -#include "dynamicWidget.hpp" +#include "gui/connectDialog.hpp" +#include "gui/dynamicWidget.hpp" #include "oscilloscope.hpp" #include "spectrum_analyzer.hpp" #include "tool_launcher.hpp" #include "qtjs.hpp" #include "jsfileio.h" -#include "dragzone.h" +#include "gui/dragzone.h" #include "debugger.h" #include "manualcalibration.h" #include "apiobjectmanager.h" #include "device_widget.hpp" -#include "user_notes.hpp" +#include "gui/user_notes.hpp" #include "external_script_api.hpp" -#include "animationmanager.h" +#include "gui/animationmanager.h" #include "singletone_wrapper.h" #include "phonehome.h" @@ -55,6 +55,11 @@ #include #include #include +#include +#if __ANDROID__ +#include +#include +#endif #include @@ -70,6 +75,9 @@ #include #include #include "scopyExceptionHandler.h" +#ifdef __ANDROID__ +#include +#endif #define TIMER_TIMEOUT_MS 5000 #define ALIVE_TIMER_TIMEOUT_MS 5000 @@ -78,6 +86,11 @@ using namespace adiscope; using namespace libm2k::context; using namespace libm2k::digital; +ToolLauncher* adiscope::tl_ptr; +ToolLauncher* adiscope::getToolLauncherInstance() { + return tl_ptr; +} + ToolLauncher::ToolLauncher(QString prevCrashDump, QWidget *parent) : QMainWindow(parent), ui(new Ui::ToolLauncher), ctx(nullptr), @@ -105,12 +118,24 @@ ToolLauncher::ToolLauncher(QString prevCrashDump, QWidget *parent) : skip_calibration_if_already_calibrated(true), m_adc_tools_failed(false), m_dac_tools_failed(false), - about(nullptr) + about(nullptr), + openGlLoaded(false) + #ifdef __ANDROID__ + ,jnienv(new QAndroidJniEnvironment()) + #endif { if (!isatty(STDIN_FILENO)) notifier.setEnabled(false); ui->setupUi(this); +#ifdef __ANDROID__ // LIBUSB WEAK_AUTHORITY + libusb_set_option(NULL,LIBUSB_OPTION_ANDROID_JAVAVM,jnienv->javaVM()); + libusb_set_option(NULL,LIBUSB_OPTION_WEAK_AUTHORITY,NULL); +#endif + +#ifdef __ANDROID__ // JNI hooks + registerNativeMethods(); +#endif setWindowIcon(QIcon(":/icon.ico")); QApplication::setWindowIcon(QIcon(":/icon.ico")); @@ -155,7 +180,7 @@ ToolLauncher::ToolLauncher(QString prevCrashDump, QWidget *parent) : connect(ui->btnHomepage, SIGNAL(toggled(bool)), this, SLOT(btnHomepage_toggled(bool))); tl_api->setObjectName(QString::fromStdString(Filter::tool_name( - TOOL_LAUNCHER))); + TOOL_LAUNCHER))); //option background connect(ui->btnHome, SIGNAL(toggled(bool)), this, @@ -177,7 +202,7 @@ ToolLauncher::ToolLauncher(QString prevCrashDump, QWidget *parent) : #endif QtJs *js_object = new QtJs(&js_engine); js_engine.globalObject().setProperty("fileIO", - js_engine.newQObject(new JsFileIo(this))); + js_engine.newQObject(new JsFileIo(this))); tl_api->js_register(&js_engine); connect(¬ifier, SIGNAL(activated(int)), this, SLOT(hasText())); @@ -233,19 +258,27 @@ ToolLauncher::ToolLauncher(QString prevCrashDump, QWidget *parent) : msgBox->setText("Do you want to automatically check for newer Scopy and m2k-firmware versions?"); msgBox->setInformativeText("You can change this anytime from the Preferences menu."); - msgBox->setStandardButtons(msgBox->Yes | msgBox->No); + + QPushButton* yesButton = new QPushButton("Yes"); + msgBox->addButton(yesButton ,QMessageBox::AcceptRole); + + QPushButton* noButton = new QPushButton("No"); + msgBox->addButton(noButton ,QMessageBox::RejectRole); + msgBox->setModal(false); msgBox->show(); msgBox->activateWindow(); msgBox->move( QPoint( screenRect.x() + screenRect.width()/2 - mSize.width()/2, - screenRect.y() + screenRect.height()/2 - mSize.height()/2 ) ); - connect(msgBox->button(QMessageBox::Yes), &QAbstractButton::pressed, [&] () { + screenRect.y() + screenRect.height()/2 - mSize.height()/2 ) ); + + connect(yesButton, &QAbstractButton::clicked, [&] () { prefPanel->setAutomatical_version_checking_enabled(true); prefPanel->setFirst_application_run(false); }); - connect(msgBox->button(QMessageBox::No), &QAbstractButton::pressed, [&] () { + connect(noButton, &QAbstractButton::clicked, [&] () { prefPanel->setFirst_application_run(false); }); + } connect(prefPanel, &Preferences::requestUpdateCheck, [=]() { m_phoneHome->versionsRequest(true);}); connect(about, &ScopyAboutDialog::forceCheckForUpdates,[=](){ @@ -259,7 +292,12 @@ ToolLauncher::ToolLauncher(QString prevCrashDump, QWidget *parent) : setupAddPage(); readPreferences(); this->installEventFilter(this); - ui->btnConnect->hide(); + ui->btnConnect->hide(); + // Read preferences and then decide if we load OpenGL + auto openGLEnvVar = qgetenv("SCOPY_USE_OPENGL"); + if( (bool)openGLEnvVar.toInt()) { + loadOpenGL(); + } _setupToolMenu(); @@ -292,6 +330,26 @@ ToolLauncher::ToolLauncher(QString prevCrashDump, QWidget *parent) : } else { } +#if __ANDROID__ + const QVector permissions({"android.permission.READ_EXTERNAL_STORAGE", + "android.permission.WRITE_EXTERNAL_STORAGE", + "android.permission.INTERNET"}); + + for(const QString &permission : permissions) { + auto result = QtAndroid::checkPermission(permission); + if(result == QtAndroid::PermissionResult::Denied) { + auto resultHash = QtAndroid::requestPermissionsSync(QStringList({permission})); + if(resultHash[permission] == QtAndroid::PermissionResult::Denied) + return; + } + } +#endif + // skip_calibration=true; + + // QFile f("/sdcard/gnuradio/bla.txt"); + // f.open(QIODevice::ReadWrite); + // f.write("blabla"); + // f.close(); // TO DO: Remove temporary spaces // set home icon @@ -299,6 +357,11 @@ ToolLauncher::ToolLauncher(QString prevCrashDump, QWidget *parent) : ui->btnHome->setIcon(QIcon::fromTheme("house")); ui->btnHome->setIconSize(QSize(32,32)); + // f.open(QIODevice::ReadOnly); + // qDebug()<getButtonGroup()->addButton(ui->btnNotes); infoWidget = new InfoWidget(this); + +#ifndef __ANDROID__ connect(ui->homeWidget, &DetachDragZone::changeText, infoWidget, &InfoWidget::setText); +#endif + connect(menu, &ToolMenu::enableInfoWidget, infoWidget, &InfoWidget::enable); } @@ -332,6 +399,7 @@ void ToolLauncher::_setupToolMenu() void ToolLauncher::_toolSelected(enum tool tool) { Tool *selectedTool = nullptr; + selectedToolId = tool; switch(tool) { case TOOL_OSCILLOSCOPE: selectedTool = oscilloscope; @@ -386,7 +454,7 @@ void ToolLauncher::readPreferences() allowExternalScript(prefPanel->getExternal_script_enabled()); if (manual_calibration) { manual_calibration->allowManualCalibScript(manual_calibration_enabled, - prefPanel->getManual_calib_script_enabled()); + prefPanel->getManual_calib_script_enabled()); } AnimationManager::getInstance().toggleAnimations(prefPanel->getAnimations_enabled()); @@ -435,8 +503,10 @@ void ToolLauncher::saveSession() { if (ctx) { QString fileName = QFileDialog::getSaveFileName(this, - tr("Save session"), "", tr("Scopy-Files (*.ini)"), - nullptr, (m_useNativeDialogs ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)); + tr("Save session"), "", tr("Scopy-Files (*.ini)"), + nullptr, (m_useNativeDialogs ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)); + QFileInfo fi(fileName); + qDebug()<tl_api->save(fileName); } @@ -479,8 +549,8 @@ void ToolLauncher::setNativeDialogs(bool nativeDialogs) void ToolLauncher::loadSession() { QString fileName = QFileDialog::getOpenFileName(this, - tr("Load session"), "", tr("Scopy-Files (*.ini)"), - nullptr, (m_useNativeDialogs ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)); + tr("Load session"), "", tr("Scopy-Files (*.ini)"), + nullptr, (m_useNativeDialogs ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog)); if (!fileName.isEmpty()) { this->tl_api->load(fileName); updateHomepage(); @@ -695,13 +765,14 @@ ToolLauncher::~ToolLauncher() tl_api->ApiObject::save(*settings); m_sessionInfo.save(*settings); - delete settings; + delete settings; SingleToneWrapper::getInstance().setWrapped(nullptr); delete tl_api; delete ui; saveSettings(); + tl_ptr = nullptr; } void ToolLauncher::forgetDeviceBtn_clicked(QString uri) @@ -764,10 +835,10 @@ QPushButton *ToolLauncher::addContext(const QString& uri) DeviceWidget *deviceWidget = nullptr; if (tempFilter->hw_name().compare("M2K") == 0) { deviceWidget = DeviceBuilder::newDevice(DeviceBuilder::M2K, - uri, tempFilter->hw_name(), this); + uri, tempFilter->hw_name(), this); } else { deviceWidget = DeviceBuilder::newDevice(DeviceBuilder::GENERIC, - uri, tempFilter->hw_name(), this); + uri, tempFilter->hw_name(), this); } delete tempFilter; @@ -778,7 +849,7 @@ QPushButton *ToolLauncher::addContext(const QString& uri) if (connectBtn) { connect(connectBtn, SIGNAL(clicked(bool)), - this, SLOT(connectBtn_clicked(bool))); + this, SLOT(connectBtn_clicked(bool)), Qt::QueuedConnection); } connect(deviceWidget, SIGNAL(forgetDevice(QString)), @@ -791,7 +862,7 @@ QPushButton *ToolLauncher::addContext(const QString& uri) this, SLOT(stopSearching(bool))); ui->devicesList->insertWidget(ui->devicesList->count() - 1, - deviceWidget); + deviceWidget); ui->stackedWidget->addWidget(deviceWidget->infoPage()); devices_btn_group->addButton(deviceWidget->deviceButton()); devices.push_back(deviceWidget); @@ -877,8 +948,8 @@ void ToolLauncher::setupHomepage() //versionLabel->setText(tr("Unable to check update server!")); } else if (m_phoneHome->getScopyVersion() != QString("v" + QString(PROJECT_VERSION))) { versionLabel->setText(tr("Version ") + m_phoneHome->getScopyVersion() + " of Scopy was released. " + - "getScopyLink() + - tr("\">Click to update ")); + "getScopyLink() + + tr("\">Click to update ")); versionLabel->setTextFormat(Qt::RichText); versionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); versionLabel->setOpenExternalLinks(true); @@ -1099,9 +1170,9 @@ void adiscope::ToolLauncher::disconnect() ui->btnHome->click(); QObject::disconnect(this, SIGNAL(calibrationFailed()), - this, SLOT(calibrationFailedCallback())); + this, SLOT(calibrationFailedCallback())); QObject::disconnect(this, SIGNAL(calibrationDone()), - this, SLOT(restartToolsAfterCalibration())); + this, SLOT(restartToolsAfterCalibration())); if (ctx) { if (calibrating) { @@ -1135,10 +1206,14 @@ void adiscope::ToolLauncher::disconnect() void adiscope::ToolLauncher::ping() { - int ret = iio_context_get_version(ctx, nullptr, nullptr, nullptr); + auto dev = iio_context_get_device(ctx, 0); + const iio_device* test_device = nullptr; - if (ret < 0) + int ret = iio_device_get_trigger(dev, &test_device); + + if (ret < 0 && ret != -ENOENT && ret!=-19) { disconnect(); + } } void adiscope::ToolLauncher::connectBtn_clicked(bool pressed) @@ -1164,7 +1239,7 @@ void adiscope::ToolLauncher::connectBtn_clicked(bool pressed) /* Disconnect connected device, if any */ if (ctx) { QObject::disconnect(connectedDev->calibrateButton(), - SIGNAL(clicked()),this, SLOT(requestCalibration())); + SIGNAL(clicked()),this, SLOT(requestCalibration())); QObject::disconnect(&calibration_thread_watcher, SIGNAL(finished()), this, SLOT(calibrationThreadWatcherFinished())); connectedDev->setConnected(false, false); @@ -1371,6 +1446,7 @@ void adiscope::ToolLauncher::stopToolsBeforeCalibration() for(Tool* tool : qAsConst(calibration_saved_tools)) tool->stop(); } + void adiscope::ToolLauncher::restartToolsAfterCalibration() { menu->getToolMenuItemFor(TOOL_DMM)->setCalibrating(false); @@ -1402,7 +1478,7 @@ void adiscope::ToolLauncher::requestCalibration() stopToolsBeforeCalibration(); calibration_thread = QtConcurrent::run(std::bind(&ToolLauncher::calibrate, - this)); + this)); } void adiscope::ToolLauncher::requestCalibrationCancel() @@ -1433,6 +1509,15 @@ QPair adiscope::ToolLauncher::initialCalibration() initialCalibrationFlag = false; } + // if (okc.first) { + // Q_EMIT adcCalibrationDone(); + // Q_EMIT dacCalibrationDone(); + // Q_EMIT calibrationDone(); + // } + // else { + // Q_EMIT calibrationFailed(); + // } + return okc; } @@ -1464,7 +1549,6 @@ QPair adiscope::ToolLauncher::calibrate() ok = true; } } - ok = calib->calibrateAll(); } QMetaObject::invokeMethod(selectedDev->infoPage(), "setCalibrationStatusLabel", @@ -1623,7 +1707,6 @@ bool adiscope::ToolLauncher::switchContext(const QString& uri) || filter->compatible(TOOL_DIGITALIO)) { dioManager = new DIOManager(ctx, filter); } - if (filter->compatible(TOOL_LOGIC_ANALYZER) || filter->compatible(TOOL_PATTERN_GENERATOR)) { @@ -1634,8 +1717,8 @@ bool adiscope::ToolLauncher::switchContext(const QString& uri) info.setText(tr("Digital decoders support is disabled. Some features may be missing")); info.exec(); } else { - bool success = loadDecoders(QCoreApplication::applicationDirPath() + - "/decoders"); + + bool success = loadDecoders(QCoreApplication::applicationDirPath() + "/decoders"); if (!success) { search_timer->stop(); @@ -1644,6 +1727,7 @@ bool adiscope::ToolLauncher::switchContext(const QString& uri) error.setText(tr("There was a problem initializing libsigrokdecode. Some features may be missing")); error.exec(); } + } } @@ -1690,8 +1774,8 @@ bool adiscope::ToolLauncher::switchContext(const QString& uri) } connect(menu->getToolMenuItemFor(TOOL_NETWORK_ANALYZER)->getToolStopBtn(), - &QPushButton::toggled, - [=](bool en) { + &QPushButton::toggled, + [=](bool en) { if(en) { if(!menu->getToolMenuItemFor(TOOL_SIGNAL_GENERATOR)->getToolStopBtn()->isChecked()) return; @@ -1699,8 +1783,8 @@ bool adiscope::ToolLauncher::switchContext(const QString& uri) } }); connect(menu->getToolMenuItemFor(TOOL_SIGNAL_GENERATOR)->getToolStopBtn(), - &QPushButton::toggled, - [=](bool en) { + &QPushButton::toggled, + [=](bool en) { if(en) { if(adc_users_group.checkedId() == adc_users_group.id(menu->getToolMenuItemFor(TOOL_NETWORK_ANALYZER)->getToolStopBtn())){ auto btn = dynamic_cast( @@ -1734,7 +1818,7 @@ bool adiscope::ToolLauncher::switchContext(const QString& uri) selectedDev->infoPage()->setCalibrationStatusLabel(tr("Calibrating")); calibration_thread = QtConcurrent::run(std::bind(&ToolLauncher::initialCalibration, - this)); + this)); calibration_thread_watcher.setFuture(calibration_thread); connect(&calibration_thread_watcher, SIGNAL(finished()), this, SLOT(calibrationThreadWatcherFinished())); @@ -1745,9 +1829,9 @@ bool adiscope::ToolLauncher::switchContext(const QString& uri) void ToolLauncher::calibrationThreadWatcherFinished() { QObject::disconnect(this, SIGNAL(adcCalibrationDone()), - this, SLOT(enableAdcBasedTools())); + this, SLOT(enableAdcBasedTools())); QObject::disconnect(this, SIGNAL(dacCalibrationDone()), - this, SLOT(enableDacBasedTools())); + this, SLOT(enableDacBasedTools())); auto dev = getConnectedDevice(); if (dev) { @@ -1803,8 +1887,8 @@ void ToolLauncher::checkIp(const QString& ip) if (!found) QMetaObject::invokeMethod(this, "addContext", - Qt::QueuedConnection, - Q_ARG(const QString&, uri)); + Qt::QueuedConnection, + Q_ARG(const QString&, uri)); } else { previousIp = ""; } @@ -1827,6 +1911,12 @@ void ToolLauncher::toolDetached(bool detached) tool->setMinimumSize(910, 490); } +enum tool ToolLauncher::getSelectedToolId() const { + return selectedToolId; +} + + + void ToolLauncher::closeEvent(QCloseEvent *event) { // Notify tools that the launcher is closing @@ -1888,5 +1978,88 @@ bool ToolLauncher::eventFilter(QObject *watched, QEvent *event) return true; } } + +#ifdef __ANDROID__ + else if(event->type() == QEvent::KeyRelease) { + QKeyEvent *ke = static_cast(event); + if (ke->key() == Qt::Key_Back) { + + QMessageBox* msgBox = new QMessageBox(this); + QSize mSize = msgBox->sizeHint(); // here's what you want, not m.width()/height() + QRect screenRect = QDesktopWidget().screenGeometry(); + + msgBox->setText("Are you sure you want to close Scopy?"); + + QPushButton* yesButton = new QPushButton("Yes"); + msgBox->addButton(yesButton ,QMessageBox::AcceptRole); + + QPushButton* noButton = new QPushButton("No"); + msgBox->addButton(noButton ,QMessageBox::RejectRole); + + msgBox->setModal(false); + msgBox->show(); + msgBox->activateWindow(); + msgBox->move( QPoint( screenRect.x() + screenRect.width()/2 - mSize.width()/2, + screenRect.y() + screenRect.height()/2 - mSize.height()/2 ) ); + + connect(yesButton, &QAbstractButton::clicked, [&] () { + // TODO: call save preferences + qApp->exit(); + }); + + connect(noButton, &QAbstractButton::clicked, [&] () { + event->ignore(); + }); + } + return true; + } +#endif + return QObject::eventFilter(watched, event); } + +#ifdef __ANDROID__ + +void ToolLauncher::saveSessionJavaHelper(JNIEnv *env, jobject /*thiz*/) { + qDebug()<<"-- Saving session"; + ToolLauncher* tl = getToolLauncherInstance(); + if(tl) + { + getToolLauncherInstance()->tl_api->sync(); + getToolLauncherInstance()->saveSettings(); + } +} + +void ToolLauncher::registerNativeMethods() +{ + JNINativeMethod methods[] = {{"saveSessionJavaHelper", "()V", reinterpret_cast(saveSessionJavaHelper) }}; + + QAndroidJniObject activity = QtAndroid::androidActivity(); + QAndroidJniEnvironment env; + jclass objectClass = env->GetObjectClass(activity.object()); + + env->RegisterNatives(objectClass, + methods, + sizeof(methods) / sizeof(methods[0])); + env->DeleteLocalRef(objectClass); +} +#endif + +bool ToolLauncher::isOpenGlLoaded() const { + return openGlLoaded; +} + +void ToolLauncher::loadOpenGL() { + // set surfaceFormat as in Qt example: HelloGL2 - https://code.qt.io/cgit/qt/qtbase.git/tree/examples/opengl/hellogl2/main.cpp?h=5.15#n81 + QSurfaceFormat fmt; + fmt.setDepthBufferSize(24); + QSurfaceFormat::setDefaultFormat(fmt); + + // This acts as a loader for the OpenGL context, our plots load and draw in the OpenGL context + // at the same time which causes some race condition and causes the app to hang + // with this workaround, the app loads the OpenGL context before any plots are created + // Probably there's a better way to do this + auto a = new QOpenGLWidget(this); + delete a; + openGlLoaded = true; +} diff --git a/src/tool_launcher.hpp b/src/tool_launcher.hpp index 865c94621c..36b7e9bc9a 100644 --- a/src/tool_launcher.hpp +++ b/src/tool_launcher.hpp @@ -32,9 +32,12 @@ #include #include #include -#include #include +#ifdef __ANDROID__ +#include +#endif + #include "apiObject.hpp" #include "dmm.hpp" #include "filter.hpp" @@ -49,16 +52,17 @@ #include "network_analyzer.hpp" #include "digitalio.hpp" -#include "detachedWindow.hpp" +#include "gui/detachedWindow.hpp" #include "preferences.h" -#include "info_page.hpp" +#include "gui/info_page.hpp" +#include #include "device_widget.hpp" -#include "connectDialog.hpp" +#include "gui/connectDialog.hpp" #include "toolmenu.h" #include "session_info.h" extern "C" { - struct iio_context; +struct iio_context; } namespace Ui { @@ -73,6 +77,9 @@ class Debugger; class ManualCalibration; class UserNotes; +extern ToolLauncher* tl_ptr; +ToolLauncher* getToolLauncherInstance(); + class ToolLauncher : public QMainWindow { friend class ToolLauncher_API; @@ -97,6 +104,9 @@ class ToolLauncher : public QMainWindow void setNativeDialogs(bool nativeDialogs); PhoneHome *getPhoneHome() const; + enum tool getSelectedToolId() const; + + bool isOpenGlLoaded() const; Q_SIGNALS: void connectionDone(bool success); @@ -190,6 +200,11 @@ private Q_SLOTS: DeviceWidget* getDevice(QString uri); void setupAddPage(); void allowExternalScript(bool); + void loadOpenGL(); +#ifdef __ANDROID__ + void registerNativeMethods(); + static void saveSessionJavaHelper(JNIEnv *env, jobject /*thiz*/); +#endif private: Ui::ToolLauncher *ui; @@ -202,6 +217,9 @@ private Q_SLOTS: QVector position; QVector debugInstances; QVector debugWindows; +#if __ANDROID__ + QAndroidJniEnvironment *jnienv; +#endif std::vector devices; QVector toolList; @@ -277,6 +295,10 @@ private Q_SLOTS: PhoneHome* m_phoneHome; SessionInfo m_sessionInfo; + enum tool selectedToolId; + + bool openGlLoaded; + }; } #endif // M2K_TOOL_LAUNCHER_H diff --git a/src/tool_launcher_api.cpp b/src/tool_launcher_api.cpp index adaade2851..61caa31f83 100644 --- a/src/tool_launcher_api.cpp +++ b/src/tool_launcher_api.cpp @@ -19,7 +19,7 @@ */ #include "tool_launcher_api.hpp" #include "ui_tool_launcher.h" -#include "user_notes.hpp" +#include "gui/user_notes.hpp" #include "spectrum_analyzer.hpp" #include "apiobjectmanager.h" #include "debugger.h" @@ -89,6 +89,17 @@ bool ToolLauncher_API::calibration_skipped() return tl->skip_calibration; } +int ToolLauncher_API::focused_instrument() { + return static_cast(tl->getSelectedToolId()); +} + +void ToolLauncher_API::focus_instrument(int inst) { + if(inst >= 0 ) { + tl->_toolSelected(static_cast(inst)); + } + +} + QList ToolLauncher_API::usb_uri_list() { QList uri_list; @@ -244,35 +255,44 @@ bool ToolLauncher_API::reset() return did_reconnect; } -void ToolLauncher_API::save(const QString& file) -{ - QSettings settings(file, QSettings::IniFormat); +void ToolLauncher_API::sync() { + + QSettings settings; + save(&settings); +} - this->ApiObject::save(settings); - this->tl->m_sessionInfo.save(settings); +void ToolLauncher_API::save(QSettings *settings) { + this->ApiObject::save(*settings); + this->tl->m_sessionInfo.save(*settings); if (tl->notesPanel) - tl->notesPanel->api()->save(settings); + tl->notesPanel->api()->save(*settings); if (tl->oscilloscope) - tl->oscilloscope->getApi()->save(settings); + tl->oscilloscope->getApi()->save(*settings); if (tl->dmm) - tl->dmm->getApi()->save(settings); + tl->dmm->getApi()->save(*settings); if (tl->power_control) - tl->power_control->getApi()->save(settings); + tl->power_control->getApi()->save(*settings); if (tl->signal_generator) - tl->signal_generator->getApi()->save(settings); + tl->signal_generator->getApi()->save(*settings); if (tl->logic_analyzer) - tl->logic_analyzer->getApi()->save(settings); + tl->logic_analyzer->getApi()->save(*settings); if (tl->dio) - tl->dio->getApi()->save(settings); + tl->dio->getApi()->save(*settings); if (tl->pattern_generator) - tl->pattern_generator->getApi()->save(settings); + tl->pattern_generator->getApi()->save(*settings); if (tl->network_analyzer) - tl->network_analyzer->getApi()->save(settings); + tl->network_analyzer->getApi()->save(*settings); if (tl->spectrum_analyzer) - tl->spectrum_analyzer->getApi()->save(settings); + tl->spectrum_analyzer->getApi()->save(*settings); + + ApiObjectManager::getInstance().save(*settings); +} - ApiObjectManager::getInstance().save(settings); +void ToolLauncher_API::save(const QString& file) +{ + QSettings settings(file, QSettings::IniFormat); + save(&settings); } void ToolLauncher::addDebugWindow() diff --git a/src/tool_launcher_api.hpp b/src/tool_launcher_api.hpp index 16fc246c78..c031dab1cc 100644 --- a/src/tool_launcher_api.hpp +++ b/src/tool_launcher_api.hpp @@ -31,6 +31,8 @@ class ToolLauncher_API: public ApiObject Q_PROPERTY(bool menu_opened READ menu_opened WRITE open_menu STORED false); + Q_PROPERTY(int focused_instrument READ focused_instrument WRITE focus_instrument ); + Q_PROPERTY(bool hidden READ hidden WRITE hide STORED false); Q_PROPERTY(QString previous_ip READ getPreviousIp WRITE addIp @@ -64,6 +66,9 @@ class ToolLauncher_API: public ApiObject bool calibration_skipped(); void skip_calibration(bool); + int focused_instrument(); + void focus_instrument(int); + bool debugger_enabled(); void enable_debugger(bool); @@ -105,6 +110,8 @@ class ToolLauncher_API: public ApiObject Q_INVOKABLE void load(const QString& file); Q_INVOKABLE void save(const QString& file); + Q_INVOKABLE void save(QSettings *settings); + Q_INVOKABLE void sync(); Q_INVOKABLE bool reset(); Q_INVOKABLE bool enableExtern(bool); Q_INVOKABLE bool enableCalibScript(bool); diff --git a/src/toolmenu.cpp b/src/toolmenu.cpp index d57b7f33d9..f5e3610f21 100644 --- a/src/toolmenu.cpp +++ b/src/toolmenu.cpp @@ -54,11 +54,12 @@ ToolMenu::ToolMenu(Preferences *preferences, QWidget *parent): connect(this, &ToolMenu::itemMovedFromTo, this, &ToolMenu::_updateToolList); - +#ifndef __ANDROID__ connect(preferences, &Preferences::notify, this, &ToolMenu::_readPreferences); _readPreferences(); +#endif } ToolMenu::~ToolMenu() @@ -197,6 +198,8 @@ void ToolMenu::_loadState() settings.endArray(); } + +#ifndef __ANDROID__ void ToolMenu::_readPreferences() { for (int i = 0; i < d_tools.size(); ++i) { @@ -204,3 +207,4 @@ void ToolMenu::_readPreferences() item->enableDoubleClickToDetach(d_preferences->getDouble_click_to_detach()); } } +#endif diff --git a/src/toolmenu.h b/src/toolmenu.h index 5f8e82d98c..d622b6e633 100644 --- a/src/toolmenu.h +++ b/src/toolmenu.h @@ -21,7 +21,7 @@ #ifndef TOOLMENU_H #define TOOLMENU_H -#include "basemenu.h" +#include "gui/basemenu.h" #include "filter.hpp" #include "toolmenuitem.h" #include "preferences.h" @@ -56,7 +56,10 @@ private Q_SLOTS: void _buildAllAvailableTools(); void _saveState(); void _loadState(); + +#ifndef __ANDROID__ void _readPreferences(); +#endif private: QStringList d_availableTools; diff --git a/src/toolmenuitem.cpp b/src/toolmenuitem.cpp index 063b3eb77d..6a39e8150c 100644 --- a/src/toolmenuitem.cpp +++ b/src/toolmenuitem.cpp @@ -26,8 +26,7 @@ #include #include #include -#include "dynamicWidget.hpp" -#include "dynamicWidget.hpp" +#include "gui/dynamicWidget.hpp" #include "utils.h" using namespace adiscope; @@ -53,6 +52,10 @@ ToolMenuItem::ToolMenuItem(QString name, QString iconPath, QWidget *parent): setDynamicProperty(this, "selected", on); } }); + +#ifdef __ANDROID__ + setDynamicProperty(this, "allowHover", false); +#endif } ToolMenuItem::~ToolMenuItem() @@ -145,32 +148,42 @@ void ToolMenuItem::setDisabled(bool disabled) void ToolMenuItem::mouseMoveEvent(QMouseEvent *event) { +#ifndef __ANDROID__ BaseMenuItem::mouseMoveEvent(event); setDynamicProperty(this, "allowHover", false); +#endif } void ToolMenuItem::enterEvent(QEvent *event) { +#ifndef __ANDROID__ setDynamicProperty(this, "allowHover", true); event->accept(); +#endif } void ToolMenuItem::leaveEvent(QEvent *event) { +#ifndef __ANDROID__ setDynamicProperty(this, "allowHover", false); event->accept(); +#endif } void ToolMenuItem::dragMoveEvent(QDragMoveEvent *event) { +#ifndef __ANDROID__ setDynamicProperty(this, "allowHover", false); BaseMenuItem::dragMoveEvent(event); +#endif } void ToolMenuItem::dragLeaveEvent(QDragLeaveEvent *event) { +#ifndef __ANDROID__ setDynamicProperty(this, "allowHover", true); BaseMenuItem::dragLeaveEvent(event); +#endif } void ToolMenuItem::_buildUI() diff --git a/src/toolmenuitem.h b/src/toolmenuitem.h index 44776a57b7..9ea7bd2094 100644 --- a/src/toolmenuitem.h +++ b/src/toolmenuitem.h @@ -21,8 +21,8 @@ #ifndef TOOLMENUITEM_H #define TOOLMENUITEM_H -#include "basemenuitem.h" -#include "customPushButton.hpp" +#include "gui/basemenuitem.h" +#include "gui/customPushButton.hpp" namespace adiscope { class ToolMenuItem : public BaseMenuItem diff --git a/src/trigger_settings.cpp b/src/trigger_settings.cpp index ff4f152c3c..77f08a99fb 100644 --- a/src/trigger_settings.cpp +++ b/src/trigger_settings.cpp @@ -26,7 +26,7 @@ #include #include "trigger_settings.hpp" -#include "spinbox_a.hpp" +#include "gui/spinbox_a.hpp" #include "scroll_filter.hpp" #include "ui_trigger_settings.h" diff --git a/src/utils.h b/src/utils.h index 405189f961..b2d431cad6 100644 --- a/src/utils.h +++ b/src/utils.h @@ -25,6 +25,8 @@ #include #include #include +#include +#include class QwtDblClickPlotPicker: public QwtPlotPicker { @@ -64,4 +66,13 @@ class Util static bool compareNatural(const std::string &a, const std::string &b); }; +#define PLOT_MENU_BAR_ENABLED + +class DockerUtils : public QObject +{ +public: + static QDockWidget* createDockWidget(QMainWindow* mainWindow, QWidget* widget, const QString& title = ""); + static void configureTopBar(QDockWidget* docker); +}; + #endif /* M2K_UTILS_H */ diff --git a/src/x_axis_scale_zoomer.cpp b/src/x_axis_scale_zoomer.cpp index 86582c087c..608adb5446 100644 --- a/src/x_axis_scale_zoomer.cpp +++ b/src/x_axis_scale_zoomer.cpp @@ -51,7 +51,7 @@ QwtText XAxisScaleZoomer::trackerText(const QPoint &p) const QPointF dp = QwtPlotZoomer::invTransform(p); const dBgraph *plt = dynamic_cast(plot()); - t.setText(plt->getScaleValueFormat(dp.x(), QwtPlot::xTop, 4) + ", " + - plt->getScaleValueFormat(dp.y(), QwtPlot::yLeft)); + t.setText(plt->getScaleValueFormat(dp.x(), QwtAxis::XTop, 4) + ", " + + plt->getScaleValueFormat(dp.y(), QwtAxis::YLeft)); return t; } diff --git a/src/xy_sink_c_impl.cc b/src/xy_sink_c_impl.cc index 9e47b2c1d0..2be3875b4e 100644 --- a/src/xy_sink_c_impl.cc +++ b/src/xy_sink_c_impl.cc @@ -118,8 +118,7 @@ namespace adiscope { d_qApplication = qApp; } - // initialize update time to 10 times a second - set_update_time(0.1); + set_update_time(1/60.0); } void diff --git a/ui/channel.ui b/ui/channel.ui index 9ed812c8a1..420d5811ca 100644 --- a/ui/channel.ui +++ b/ui/channel.ui @@ -198,7 +198,7 @@ adiscope::CustomPushButton QPushButton -
customPushButton.hpp
+
gui/customPushButton.hpp
diff --git a/ui/channel_settings.ui b/ui/channel_settings.ui index 071b2dcbdd..83db850463 100644 --- a/ui/channel_settings.ui +++ b/ui/channel_settings.ui @@ -815,37 +815,12 @@ - Probe -Attenuation + Probe Attenuation - - - 1 - - - - 0.1X - - - - - 1X - - - - - 10X - - - - - 100X - - - + @@ -1321,7 +1296,7 @@ AC Coupling
adiscope::CustomSwitch QPushButton -
customSwitch.hpp
+
gui/customSwitch.hpp
diff --git a/ui/cursor_readouts.ui b/ui/cursor_readouts.ui index ef1a1381b3..4cfc262383 100644 --- a/ui/cursor_readouts.ui +++ b/ui/cursor_readouts.ui @@ -419,9 +419,6 @@ 0 - - color: rgba(255, 255, 255, 153); - ΔV = diff --git a/ui/cursors_settings.ui b/ui/cursors_settings.ui index f831c36fba..a08c755f35 100644 --- a/ui/cursors_settings.ui +++ b/ui/cursors_settings.ui @@ -776,12 +776,12 @@ color: rgba(255,255,255,51); adiscope::CustomSwitch QPushButton -
customSwitch.hpp
+
gui/customSwitch.hpp
adiscope::SmallOnOffSwitch QPushButton -
smallOnOffSwitch.hpp
+
gui/smallOnOffSwitch.hpp
diff --git a/ui/custom_menu_button.ui b/ui/custom_menu_button.ui new file mode 100644 index 0000000000..d5bd44d2d1 --- /dev/null +++ b/ui/custom_menu_button.ui @@ -0,0 +1,52 @@ + + + CustomMenuButton + + + + 0 + 0 + 141 + 50 + + + + Form + + + + + + + + + + + + + Trigger + + + + + + + + + + true + + + + + + + + adiscope::CustomPushButton + QPushButton +
gui/customPushButton.hpp
+
+
+ + +
diff --git a/ui/debugger.ui b/ui/debugger.ui index 9cd85849e5..87577303cd 100644 --- a/ui/debugger.ui +++ b/ui/debugger.ui @@ -907,7 +907,7 @@ background-color: transparent; adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
diff --git a/ui/digitalIoChannel.ui b/ui/digitalIoChannel.ui index 88c8ffb8d8..926367e74f 100644 --- a/ui/digitalIoChannel.ui +++ b/ui/digitalIoChannel.ui @@ -364,12 +364,12 @@ background-color: red; adiscope::CustomSwitch QPushButton -
customSwitch.hpp
+
gui/customSwitch.hpp
adiscope::SmallOnOffSwitch QPushButton -
smallOnOffSwitch.hpp
+
gui/smallOnOffSwitch.hpp
diff --git a/ui/digitalIoElement.ui b/ui/digitalIoElement.ui index 1120a30827..3be9abafaa 100644 --- a/ui/digitalIoElement.ui +++ b/ui/digitalIoElement.ui @@ -145,7 +145,7 @@ width: 1310px; } - 0 + 1 @@ -441,7 +441,7 @@ QSlider::handle:horizontal:enabled { adiscope::CustomSwitch QPushButton -
customSwitch.hpp
+
gui/customSwitch.hpp
diff --git a/ui/digitalio.ui b/ui/digitalio.ui index 2b31a9361c..cf3a52c33b 100644 --- a/ui/digitalio.ui +++ b/ui/digitalio.ui @@ -260,19 +260,19 @@ background-color: grey; adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
adiscope::InstrumentNotes QWidget -
instrumentnotes.h
+
gui/instrumentnotes.h
1
adiscope::LinkedButton QPushButton -
linked_button.hpp
+
gui/linked_button.hpp
diff --git a/ui/dmm.ui b/ui/dmm.ui index 2b568c2960..eee40ddc13 100644 --- a/ui/dmm.ui +++ b/ui/dmm.ui @@ -351,17 +351,20 @@ text-align:center; - + 0 0 - 130 + 0 0 + + font-size:35pt; + MAX @@ -370,17 +373,20 @@ text-align:center; - + 0 0 - 130 + 0 0 + + font-size:35pt; + MIN @@ -467,20 +473,21 @@ text-align:center; - + 0 0 - 130 - 105 + 0 + 0 QLabel[ac=false] { qproperty-text: "VDC"; } -QLabel[ac=true] { qproperty-text: "VRMS"; } +QLabel[ac=true] { qproperty-text: "VRMS"; } +QLabel{font-size:35pt;} VDC @@ -631,17 +638,20 @@ text-align:center; - + 0 0 - 130 + 0 0 + + font-size:35pt; + MIN @@ -719,17 +729,20 @@ text-align:center; - + 0 0 - 130 + 0 0 + + font-size:35pt; + MAX @@ -803,20 +816,21 @@ text-align:center; - + 0 0 - 130 - 105 + 0 + 0 QLabel[ac=false] { qproperty-text: "VDC"; } -QLabel[ac=true] { qproperty-text: "VRMS"; } +QLabel[ac=true] { qproperty-text: "VRMS"; } +QLabel{font-size:35pt;} VDC @@ -1976,24 +1990,24 @@ line-height: 14px; adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
adiscope::InstrumentNotes QWidget -
instrumentnotes.h
+
gui/instrumentnotes.h
1
- adiscope::LinkedButton + adiscope::CustomSwitch QPushButton -
linked_button.hpp
+
gui/customSwitch.hpp
- adiscope::CustomSwitch + adiscope::LinkedButton QPushButton -
customSwitch.hpp
+
gui/linked_button.hpp
QwtThermo diff --git a/ui/logic_analyzer.ui b/ui/logic_analyzer.ui index 1579a8795e..8922fd8606 100644 --- a/ui/logic_analyzer.ui +++ b/ui/logic_analyzer.ui @@ -266,6 +266,18 @@ true
+ + 0 + + + 0 + + + 0 + + + 0 + @@ -276,7 +288,7 @@ 20
- 0 + 5 20 @@ -390,13 +402,13 @@ - 25 + 0 0 - 25 + 0 0 @@ -514,8 +526,8 @@ 0 0 - 200 - 329 + 400 + 474 @@ -1318,7 +1330,7 @@ color: rgba(255,255,255,51);
- + 0 0 @@ -1350,6 +1362,12 @@ color: rgba(255,255,255,51); + + + 0 + 0 + + QFrame::NoFrame @@ -1369,7 +1387,7 @@ color: rgba(255,255,255,51); - + 0 0 @@ -1437,9 +1455,15 @@ color: rgba(255,255,255,51); 0 + + + 300 + 30 + + - 400 + 300 30 @@ -1450,8 +1474,8 @@ color: rgba(255,255,255,51); QPushButton { min-height: 30px; max-height: 30px; -min-width: 400px; -max-width: 400px; +min-width: 300px; +max-width: 300px; background-color: black; border-radius: 4px; } @@ -1463,8 +1487,8 @@ background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.501, y2:0, stop QWidget#handle { min-height: 30px; max-height: 30px; -min-width: 200px; -max-width: 200px; +min-width: 150px; +max-width: 150px; background-color: #4a64ff; border-radius: 2px; } @@ -1483,8 +1507,8 @@ QLabel#on { margin-top: 0px; min-height:30px; max-height:30px; -min-width:200px; -max-width:200px; +min-width:150px; +max-width:150px; qproperty-alignment: AlignCenter AlignCenter; margin-left: 0px; color: white; @@ -1498,9 +1522,9 @@ QLabel#off { margin-top: 0px; min-height:30px; max-height:30px; -min-width:200px; -max-width:200px; -margin-left: 200px; +min-width:150px; +max-width:150px; +margin-left: 150px; color: white; qproperty-alignment: AlignCenter AlignCenter; } @@ -1540,7 +1564,7 @@ color: rgba(255,255,255,51); - 400 + 200 20 @@ -1952,49 +1976,52 @@ QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } + + adiscope::CustomPushButton + QPushButton +
gui/customPushButton.hpp
+
adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
adiscope::MenuAnim QWidget -
menu_anim.hpp
+
gui/menu_anim.hpp
1
- - adiscope::CustomPushButton - QPushButton -
customPushButton.hpp
-
adiscope::InstrumentNotes QWidget -
instrumentnotes.h
+
gui/instrumentnotes.h
1
adiscope::RunSingleWidget QWidget -
runsinglewidget.h
+
gui/runsinglewidget.h
1
- adiscope::CustomSwitch + adiscope::LinkedButton QPushButton -
customSwitch.hpp
+
gui/linked_button.hpp
- adiscope::LinkedButton + adiscope::CustomSwitch QPushButton -
linked_button.hpp
+
gui/customSwitch.hpp
+ + + diff --git a/ui/manualcalibration.ui b/ui/manualcalibration.ui index 1f01ff5ec2..255903aaf3 100644 --- a/ui/manualcalibration.ui +++ b/ui/manualcalibration.ui @@ -291,7 +291,7 @@ QListWidget{ adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
diff --git a/ui/measure_panel.ui b/ui/measure_panel.ui index 2292f4a1c8..97d5c78a77 100644 --- a/ui/measure_panel.ui +++ b/ui/measure_panel.ui @@ -28,7 +28,10 @@ - + + + 0 + 0 @@ -41,10 +44,48 @@ 0 - - 0 - - + + + + + 0 + 0 + + + + + 16777215 + 10 + + + + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAsNeeded + + + true + + + + + 0 + 0 + 348 + 16 + + + + + + @@ -190,23 +231,7 @@
- - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 0 - 20 - - - - - + @@ -228,54 +253,13 @@ - - - - - 0 - 0 - - - - - 16777215 - 10 - - - - - - - QFrame::NoFrame - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAsNeeded - - - true - - - - - 0 - 0 - 348 - 16 - - - - -
adiscope::OscCustomScrollArea QScrollArea -
osc_custom_scroll.h
+
gui/osc_custom_scroll.h
1
diff --git a/ui/measure_settings.ui b/ui/measure_settings.ui index f0a465b591..5c2f2255cc 100644 --- a/ui/measure_settings.ui +++ b/ui/measure_settings.ui @@ -6,10 +6,16 @@ 0 0 - 284 - 588 + 281 + 727 + + + 0 + 0 + + Form @@ -21,7 +27,7 @@ 18 - 0 + 10 8 @@ -126,6 +132,12 @@ + + + 0 + 0 + + QFrame::NoFrame @@ -140,10 +152,16 @@ 0 0 - 252 - 563 + 311 + 674 + + + 0 + 0 + + 0 @@ -627,14 +645,88 @@ - + + + 25 + + + 15 + + + 6 + + + 16 + + + + + QFrame::Sunken + + + MEASUREMENT PARAMETERS + + + true + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + true + + + + + + + Harmonitc Number + + + + + + + + 0 + 0 + + + + true + + + + + + + Qt::Vertical + + QSizePolicy::Expanding + - 0 - 197 + 10 + 10 @@ -643,22 +735,6 @@ - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 0 - 10 - - - - @@ -667,7 +743,7 @@ adiscope::CustomSwitch QPushButton -
customSwitch.hpp
+
gui/customSwitch.hpp
diff --git a/ui/menu_header.ui b/ui/menu_header.ui new file mode 100644 index 0000000000..80d20436c8 --- /dev/null +++ b/ui/menu_header.ui @@ -0,0 +1,105 @@ + + + MenuHeader + + + + 0 + 0 + 278 + 67 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 10 + + + + + 10 + + + 0 + + + 15 + + + + + TextLabel + + + true + + + + + + + + + + true + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 10 + + + + + + + + + 0 + 2 + + + + Qt::Horizontal + + + + + + + + adiscope::CustomSwitch + QPushButton +
gui/customSwitch.hpp
+
+
+ + +
diff --git a/ui/network_analyzer.ui b/ui/network_analyzer.ui index 8e04fbbf07..cbfd3f6ede 100644 --- a/ui/network_analyzer.ui +++ b/ui/network_analyzer.ui @@ -262,6 +262,18 @@ 0 + + 0 + + + 0 + + + 0 + + + 0 + @@ -796,7 +808,7 @@ border: 5px solid white; - 2 + 0 @@ -2055,8 +2067,8 @@ padding-left: 20px; 0 0 - 300 - 531 + 261 + 529 @@ -3124,43 +3136,43 @@ QLabel { - adiscope::CustomSwitch + adiscope::CustomPushButton QPushButton -
customSwitch.hpp
+
gui/customPushButton.hpp
adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
- adiscope::InstrumentNotes + adiscope::MenuAnim QWidget -
instrumentnotes.h
+
gui/menu_anim.hpp
1
- adiscope::LinkedButton - QPushButton -
linked_button.hpp
-
- - adiscope::MenuAnim + adiscope::InstrumentNotes QWidget -
menu_anim.hpp
+
gui/instrumentnotes.h
1
adiscope::RunSingleWidget QWidget -
runsinglewidget.h
+
gui/runsinglewidget.h
1
- adiscope::CustomPushButton + adiscope::CustomSwitch + QPushButton +
gui/customSwitch.hpp
+
+ + adiscope::LinkedButton QPushButton -
customPushButton.hpp
+
gui/linked_button.hpp
adiscope::dBgraph @@ -3177,13 +3189,13 @@ QLabel { adiscope::CustomPlotPositionButton QWidget -
customplotpositionbutton.h
+
gui/customplotpositionbutton.h
1
adiscope::SmallOnOffSwitch QPushButton -
smallOnOffSwitch.hpp
+
gui/smallOnOffSwitch.hpp
diff --git a/ui/osc_export_settings.ui b/ui/osc_export_settings.ui index 2268971dec..354f11ef6f 100644 --- a/ui/osc_export_settings.ui +++ b/ui/osc_export_settings.ui @@ -292,7 +292,7 @@ adiscope::CustomSwitch QPushButton -
customSwitch.hpp
+
gui/customSwitch.hpp
diff --git a/ui/osc_general_settings.ui b/ui/osc_general_settings.ui index ffec3aff2b..5fc6ffc2bb 100644 --- a/ui/osc_general_settings.ui +++ b/ui/osc_general_settings.ui @@ -504,7 +504,7 @@ adiscope::CustomSwitch QPushButton -
customSwitch.hpp
+
gui/customSwitch.hpp
diff --git a/ui/oscilloscope.ui b/ui/oscilloscope.ui index e08ae438c0..14e6b7b2c2 100644 --- a/ui/oscilloscope.ui +++ b/ui/oscilloscope.ui @@ -259,12 +259,33 @@ Signal View true + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + 0 + + 5 + + + 0 + @@ -283,6 +304,9 @@ Signal View 0 + + 0 + @@ -336,13 +360,13 @@ Signal View - 25 + 0 0 - 25 + 0 0 @@ -353,43 +377,45 @@ Signal View - - - 0 - - - 0 - - - 0 - - - 3 - - - - - 15 - - - 10 - - - - - - - Qt::Horizontal - - - - 0 - 15 - - - - - + + + + 0 + + + 1 + + + 0 + + + 3 + + + + + 15 + + + 10 + + + + + + + Qt::Horizontal + + + + 0 + 15 + + + + + +
@@ -424,86 +450,103 @@ Signal View + + + - - - 0 - - - 20 - - - 20 + + + + 16777215 + 100 + - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - - 0 - 0 - - - - - 20 - 0 - - - - - 0 + + + 0 + + + 20 + + + 9 + + + 20 + + + + + Qt::Horizontal - - 0 + + QSizePolicy::Fixed - - 0 + + + 20 + 20 + - - 0 + + + + + + + 0 + 0 + - - 0 + + + 20 + 0 + - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - + + + 16777215 + 70 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + @@ -984,44 +1027,47 @@ QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } + + adiscope::CustomPushButton + QPushButton +
gui/customPushButton.hpp
+
adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
adiscope::MenuAnim QWidget -
menu_anim.hpp
+
gui/menu_anim.hpp
1
- - adiscope::CustomPushButton - QPushButton -
customPushButton.hpp
-
adiscope::InstrumentNotes QWidget -
instrumentnotes.h
+
gui/instrumentnotes.h
1
adiscope::RunSingleWidget QWidget -
runsinglewidget.h
+
gui/runsinglewidget.h
1
adiscope::LinkedButton QPushButton -
linked_button.hpp
+
gui/linked_button.hpp
+ + + diff --git a/ui/pattern_generator.ui b/ui/pattern_generator.ui index f5fd868151..a99ce4db06 100644 --- a/ui/pattern_generator.ui +++ b/ui/pattern_generator.ui @@ -288,7 +288,7 @@ 20 - 20 + 10 @@ -337,7 +337,7 @@ 20 - 20 + 10 @@ -386,13 +386,13 @@ - 25 + 0 0 - 25 + 0 0 @@ -469,7 +469,7 @@ - 3 + 0 @@ -519,8 +519,8 @@ 0 0 - 200 - 300 + 300 + 474 @@ -1381,8 +1381,8 @@ color: rgba(255,255,255,51); 0 0 - 280 - 474 + 220 + 134 @@ -1782,44 +1782,44 @@ QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } + + adiscope::CustomPushButton + QPushButton +
gui/customPushButton.hpp
+
adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
adiscope::MenuAnim QWidget -
menu_anim.hpp
+
gui/menu_anim.hpp
1
- - adiscope::CustomPushButton - QPushButton -
customPushButton.hpp
-
adiscope::InstrumentNotes QWidget -
instrumentnotes.h
+
gui/instrumentnotes.h
1
adiscope::RunSingleWidget QWidget -
runsinglewidget.h
+
gui/runsinglewidget.h
1
- adiscope::CustomSwitch + adiscope::LinkedButton QPushButton -
customSwitch.hpp
+
gui/linked_button.hpp
- adiscope::LinkedButton + adiscope::CustomSwitch QPushButton -
linked_button.hpp
+
gui/customSwitch.hpp
diff --git a/ui/patterns/i2cpatternui.ui b/ui/patterns/i2cpatternui.ui index df60fefddc..806d09e773 100644 --- a/ui/patterns/i2cpatternui.ui +++ b/ui/patterns/i2cpatternui.ui @@ -176,7 +176,7 @@ adiscope::SmallOnOffSwitch QPushButton -
smallOnOffSwitch.hpp
+
gui/smallOnOffSwitch.hpp
diff --git a/ui/patterns/spipatternui.ui b/ui/patterns/spipatternui.ui index 40ea4441b5..978fde7730 100644 --- a/ui/patterns/spipatternui.ui +++ b/ui/patterns/spipatternui.ui @@ -6,7 +6,7 @@ 0 0 - 262 + 282 391 @@ -283,7 +283,7 @@ adiscope::SmallOnOffSwitch QPushButton -
smallOnOffSwitch.hpp
+
gui/smallOnOffSwitch.hpp
diff --git a/ui/powercontrol.ui b/ui/powercontrol.ui index 021506bc68..dd9fc66502 100644 --- a/ui/powercontrol.ui +++ b/ui/powercontrol.ui @@ -123,23 +123,33 @@ - - + + + + QLabel { color: #444444; qproperty-alignment: 'AlignBottom | AlignLeft'; font-size: 30pt; font-weight: bold; } + + + VDC + + + + + - + 0 0 - 220 + 0 0 - 220 + 16777215 16777215 @@ -154,55 +164,38 @@ QLabel { color: #444444; qproperty-alignment: 'AlignBottom | AlignLeft'; font-size: 30pt; font-weight: bold; } - Set + Measure - - - - Qt::Horizontal - - - - 42 - 20 - - - - - - + + - + 0 0 - 220 - 0 + 210 + 80 - - - 220 - 16777215 - + + QLCDNumber { +background-color: transparent; +color: #ff7200; +} - - - 30 - 75 - true - + + QFrame::NoFrame - - QLabel { color: #444444; qproperty-alignment: 'AlignBottom | AlignLeft'; font-size: 30pt; font-weight: bold; } + + 5 - - Measure + + QLCDNumber::Flat @@ -244,65 +237,72 @@ color: #ff7200; - - + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + - + 0 0 - 210 - 80 + 0 + 0 - - QLCDNumber { -background-color: transparent; -color: #ff7200; -} - - - QFrame::NoFrame - - - 5 + + + 16777215 + 16777215 + - - QLCDNumber::Flat + + + 30 + 75 + true + - - - - - QLabel { color: #444444; qproperty-alignment: 'AlignBottom | AlignLeft'; font-size: 30pt; font-weight: bold; } + QLabel { color: #444444; qproperty-alignment: 'AlignBottom | AlignLeft'; font-size: 30pt; font-weight: bold; } - VDC + Set - - + + Qt::Horizontal - - QSizePolicy::Fixed - - 20 + 42 20 - - + + Qt::Horizontal @@ -335,25 +335,25 @@ color: #ff7200; - 7 + 6 - + 0 0 - 220 + 0 0 - 220 + 16777215 16777215 @@ -382,7 +382,7 @@ color: #ff7200; - 252 + 210 80 @@ -396,7 +396,7 @@ color: #9013fe; QFrame::NoFrame - 6 + 5 QLCDNumber::Flat @@ -406,20 +406,20 @@ color: #9013fe; - + 0 0 - 220 + 0 0 - 220 + 16777215 16777215 @@ -445,7 +445,7 @@ color: #9013fe; - 0 + 42 20 @@ -461,7 +461,7 @@ color: #9013fe; - 252 + 210 80 @@ -475,7 +475,7 @@ color: #9013fe; QFrame::NoFrame - 6 + 5 QLCDNumber::Flat @@ -1091,27 +1091,27 @@ QPushButton:disabled { - - adiscope::CustomSwitch - QPushButton -
customSwitch.hpp
-
adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
adiscope::InstrumentNotes QWidget -
instrumentnotes.h
+
gui/instrumentnotes.h
1
+ + adiscope::CustomSwitch + QPushButton +
gui/customSwitch.hpp
+
adiscope::LinkedButton QPushButton -
linked_button.hpp
+
gui/linked_button.hpp
QwtThermo @@ -1127,6 +1127,9 @@ QPushButton:disabled { + + + diff --git a/ui/preferences.ui b/ui/preferences.ui index 12be93daf1..f6308ac150 100644 --- a/ui/preferences.ui +++ b/ui/preferences.ui @@ -74,7 +74,7 @@ 0 0 1068 - 760 + 849 @@ -225,151 +225,27 @@ 10 - - - - 6 - - - 0 - - - 0 - - - - - 0 - - - - - - 0 - 0 - - - - LOGIC ANALYZER - - - true - - - - - - - - 16777215 - 1 - - - - Qt::Horizontal - - - true - - - - - - - - - - - - - - - - - - Display sampling points when zoomed - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 15 - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 15 - - - - - - + + - - - - 0 - 0 - - + - - true - - + - Save session when closing Scopy + Enable user notes in main page + + + 0 - + Qt::Horizontal @@ -383,98 +259,27 @@ - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - Scriptable manual calibration - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 15 - + + + + 0 - - - - - + - - true - - + - Enable digital decoders + Enable automatic update checking - + Qt::Horizontal @@ -488,10 +293,10 @@ - - + + - 6 + 10 0 @@ -500,23 +305,17 @@ 0 - - - 6 - - - 0 - + - + - + 0 0 - SPECTRUM ANALYZER + DEBUG true @@ -524,7 +323,7 @@ - + 0 @@ -548,35 +347,26 @@ - + + + 0 + - + - - true - - - - - 0 - 0 - - + - Only search marker peaks in visible domain - - - 0 + Show plot FPS - + Qt::Horizontal @@ -590,42 +380,213 @@ - - - - - - 0 - - - - - - + + + + + + + + + + + + + + Enable Session Logging (Only for Debugging, Bugreporting) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + color:red + + + Currently unavailable: libm2k logging system is disabled + + + + - - - Enable automatic update checking + + + 0 - + + + + + + + + + + + Enable IIO Debug Instrument (Requires Scopy restart) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - Qt::Horizontal + + + 0 - - - 40 - 20 - + + + + + + + + + + + Enable Debug Messages (Only for Debugging, Bugreporting) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 - + + + + + + + + + + + Use hardware accelerated plotting - OpenGL (EXPERIMENTAL) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + Run external scripts (Experimental) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + @@ -657,58 +618,128 @@ - - + + + + 6 + + + 0 + + + 0 + - - - + + + 6 - - - - - - Show advanced device information + + 0 - - + + + + + 0 + 0 + + + + SPECTRUM ANALYZER + + + true + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + true + + + + + - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + + + + + true + + + + + + + + 0 + 0 + + + + Only search marker peaks in visible domain + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - + + - + - + - Enable user notes in main page - - - 0 + Attempt temperature-based calibration (EXPERIMENTAL) - + Qt::Horizontal @@ -722,9 +753,12 @@ - - - + + + + + 0 + 0 @@ -737,30 +771,27 @@ 0 - - 0 - - - 10 - - - + + - + - + - Enable graticule + Scriptable manual calibration + + + 0 - + Qt::Horizontal @@ -774,108 +805,148 @@ - - - - - + + + + + + + 0 + + + 10 + + + 10 + + + + + Language (requires app restart) + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + 0 + - + + + + 0 + 0 + + - Enable sample rate filters + SIGNAL GENERATOR + + + true - - - Qt::Horizontal + + + + 0 + 1 + - + - 40 - 20 + 16777215 + 1 - - - - - - - - - - + + Qt::Horizontal + + + true - - - - Enable mini histogram - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - + + Qt::Vertical + + QSizePolicy::Fixed + - 0 - 0 + 20 + 5 - - - - - + + - + - Show ADC digital filter config + Number of displayed periods - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - + 0 @@ -883,22 +954,23 @@ - - - - + +QLineEdit[invalid=true] { +border-color: red; +color: red; +} +QLineEdit[valid=true] { +border-color: grey; +color: white; +} - - - - - Enable labels on the plot + 1 - + Qt::Horizontal @@ -912,136 +984,46 @@ - - - - 0 + + + + Qt::Vertical - - 0 + + QSizePolicy::Expanding - - - - - 0 - 0 - - - - OSCILLOSCOPE - - - true - - - - - - - - 0 - 1 - - - - - 16777215 - 1 - - - - Qt::Horizontal - - - true - - - - - - - - - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - Run external scripts (Experimental) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + 0 + 0 + + + - - + + - + + + true + - + - Double click to detach a tool - - - 0 + Enable animations - + Qt::Horizontal @@ -1055,27 +1037,49 @@ - - - - 0 + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 15 + + + + + - + + + + 0 + 0 + + + + true + - + - Skip calibration if already calibrated (needs FW >= 0.26) + Save session when closing Scopy - + Qt::Horizontal @@ -1089,12 +1093,9 @@ - - - - - 6 - + + + 0 @@ -1107,103 +1108,168 @@ 0 - - - - 6 - - - 0 - + + 0 + + + 10 + + + - - - - 0 - 0 - - + - NETWORK ANALYZER + - - true + + + + + + Enable graticule - - + + + Qt::Horizontal + + - 200 - 1 + 40 + 20 - + + + + + + + + + + + + + Enable sample rate filters + + + + + + + Qt::Horizontal + + - 16777215 - 1 + 40 + 20 + + + + + + + + + + + + + + + + + Enable mini histogram + + + + + Qt::Horizontal - - true + + + 40 + 20 + - + - - + + Qt::Vertical - - QSizePolicy::Fixed - - 20 - 15 + 0 + 0 - - + + - - - - 16777215 - 16777215 - - + + + + - + Show ADC digital filter config - + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + - + 0 0 + + + - Always display 0db value on graph + - - 0 + + + + + + Enable labels on the plot - + Qt::Horizontal @@ -1217,94 +1283,16 @@ - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 5 - - - - - - - - - - - 0 - - - - - - - - - - - - true - - - - - - - Enable animations - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - + + - 6 + 0 0 - + 0 @@ -1312,7 +1300,7 @@ - SIGNAL GENERATOR + OSCILLOSCOPE true @@ -1320,7 +1308,7 @@ - + 0 @@ -1343,82 +1331,186 @@ - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 5 - + + + + + + + 6 + + + 0 + + + 0 + + + + + 0 + + + + + + 0 + 0 + + + + LOGIC ANALYZER + + + true + + + + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + true + + + + + + + + + + + + + + + + + + Display sampling points when zoomed + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 15 + + + + + + + + + + + + + + + true + + + + + + + Enable digital decoders + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + - + - - - - - Number of displayed periods - - - - - - - - 0 - 0 - - - - -QLineEdit[invalid=true] { -border-color: red; -color: red; -} -QLineEdit[valid=true] { -border-color: grey; -color: white; -} - - - 1 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + Double click to detach a tool + + + 0 + + - + - Qt::Vertical - - - QSizePolicy::Expanding + Qt::Horizontal - 0 - 0 + 40 + 20 @@ -1426,24 +1518,24 @@ color: white; - - + + - + - + - Attempt temperature-based calibration (EXPERIMENTAL) + Show advanced device information - + Qt::Horizontal @@ -1457,11 +1549,11 @@ color: white; - - - + + + - 0 + 6 0 @@ -1476,55 +1568,227 @@ color: white; 0 - + - 0 + 6 - 10 - - - 10 + 0 - + + + + 0 + 0 + + - Language (requires app restart) + NETWORK ANALYZER + + + true - - - Qt::Horizontal + + + + 200 + 1 + + + + + 16777215 + 1 + - - QSizePolicy::Fixed + + Qt::Horizontal - + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 15 + + + + + + + + + - 40 - 20 + 16777215 + 16777215 - + + + + - + - + 0 0 + + Always display 0db value on graph + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Plotting refresh rate + + + + + + + + 60 + + + + + 30 + + + + + 15 + + + + + 10 + + + + + 5 + + + + + + + + + + + + + + + + + + Enable dockable widgets + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + @@ -1538,171 +1802,37 @@ color: white; - - - - 10 - + + 0 - - 0 - - - - - - - - 0 - 0 - - - - DEBUG - - - true - - - - - - - - 0 - 1 - - - - - 16777215 - 1 - - - - Qt::Horizontal - - - true - - - - - - - - - - - - - - - - - - - Enable Session Logging (Only for Debugging, Bugreporting) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - color:red - - - Currently unavailable: libm2k logging system is disabled - - - - + + + + + - - - 0 + + + Skip calibration if already calibrated (needs FW >= 0.26) - - - - - - - - - - - Enable IIO Debug Instrument (Requires Scopy restart) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + - - - 0 + + + Qt::Horizontal - - - - - - - - - - - Enable Debug Messages (Only for Debugging, Bugreporting) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + 40 + 20 + + + diff --git a/ui/settings_pair_widget.ui b/ui/settings_pair_widget.ui new file mode 100644 index 0000000000..4ea377013e --- /dev/null +++ b/ui/settings_pair_widget.ui @@ -0,0 +1,93 @@ + + + SettingsPairWidget + + + + 0 + 0 + 100 + 42 + + + + + 0 + 0 + + + + + 100 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + true + + + true + + + true + + + + + + + + + + + + + true + + + true + + + true + + + + + + + + adiscope::CustomPushButton + QPushButton +
gui/customPushButton.hpp
+
+
+ + +
diff --git a/ui/signal_generator.ui b/ui/signal_generator.ui index 66f6bd9ef3..d47683b58c 100644 --- a/ui/signal_generator.ui +++ b/ui/signal_generator.ui @@ -109,6 +109,25 @@
+ + + + + + + true + + + true + + + true + + + true + + +
@@ -134,6 +153,9 @@ 0 + + 0 + @@ -209,7 +231,7 @@ 0 0 314 - 604 + 592 @@ -252,7 +274,7 @@ - 0 + 3 false @@ -974,19 +996,19 @@ background-repeat: no-repeat; - 6 + 10 - 9 + 0 - 9 + 0 - 9 + 0 - 9 + 0 @@ -1137,6 +1159,21 @@ background-repeat: no-repeat; + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -1214,7 +1251,7 @@ background-repeat: no-repeat; - 0 + 10 0 @@ -1225,33 +1262,59 @@ background-repeat: no-repeat; 0 + + 0 + - + 0 - + 0 - - - 0 + + + Load (Ohm) - - 0 + + + + + + Qt::Horizontal - - 0 + + + 90 + 20 + - - - - Line thickness - - - - + + + + + + + + + + + 0 + + + 0 + + + 0 + + + + + Line thickness + + @@ -1319,20 +1382,13 @@ background-repeat: no-repeat; - - - Qt::Horizontal + + + 0 - - - 40 - 20 - + + 0 - - - - @@ -1414,36 +1470,36 @@ background-repeat: no-repeat; adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
adiscope::MenuAnim QWidget -
menu_anim.hpp
+
gui/menu_anim.hpp
1
adiscope::InstrumentNotes QWidget -
instrumentnotes.h
+
gui/instrumentnotes.h
1
adiscope::RunSingleWidget QWidget -
runsinglewidget.h
+
gui/runsinglewidget.h
1
- adiscope::LinkedButton + adiscope::CustomSwitch QPushButton -
linked_button.hpp
+
gui/customSwitch.hpp
- adiscope::CustomSwitch + adiscope::LinkedButton QPushButton -
customSwitch.hpp
+
gui/linked_button.hpp
adiscope::Math @@ -1451,6 +1507,11 @@ background-repeat: no-repeat;
math.hpp
1
+ + ExternalLoadLineEdit + QLineEdit +
gui/externalloadlineedit.h
+
diff --git a/ui/spectrum_analyzer.ui b/ui/spectrum_analyzer.ui index fec2e2c3a7..8bc6629fbf 100644 --- a/ui/spectrum_analyzer.ui +++ b/ui/spectrum_analyzer.ui @@ -6,7 +6,7 @@ 0 0 - 989 + 1003 661
@@ -296,16 +296,16 @@ min-width: 6em;
- 50 + 0 - 50 + 0 - 50 + 0 - 20 + 0 0 @@ -314,126 +314,24 @@ min-width: 6em; 10 - - - - - - 0 - - - - - - - - 200 - 200 - - - - - - - - 0 + + + 6 - - - - dBFS - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 0 - - - - - - - - - 200 - 0 - - - - - 200 - 16777215 - - - - Sample: - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 0 - - - - - - - - Average Sample: - - - - - - - Qt::Horizontal - - - - 0 - 10 - - - - - - - - Marker_n 0.000 Hz 0dB - - - - - - - - + + + + 0 + 0 + + + - 200 - 200 + 16777215 + 120 @@ -448,6 +346,103 @@ min-width: 6em; + + + + + 0 + + + 0 + + + + + dBFS + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 0 + + + + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + Sample: + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 0 + + + + + + + + Average Sample: + + + + + + + Qt::Horizontal + + + + 0 + 10 + + + + + + + + Marker_n 0.000 Hz 0dB + + + + + +
@@ -1027,7 +1022,7 @@ min-width: 64px; 0 0 298 - 428 + 356 @@ -2262,6 +2257,13 @@ border-width: 0px;
+ + + + Measure + + + @@ -2288,6 +2290,32 @@ QPushButton:hover:!pressed:!checked { border-image: url(:/icons/setup_btn_hover. QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } + + + + + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 10 + + + + @@ -2391,44 +2419,44 @@ QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } + + adiscope::CustomSwitch + QPushButton +
gui/customSwitch.hpp
+
+ + adiscope::CustomPushButton + QPushButton +
gui/customPushButton.hpp
+
adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
adiscope::MenuAnim QWidget -
menu_anim.hpp
+
gui/menu_anim.hpp
1
- - adiscope::CustomPushButton - QPushButton -
customPushButton.hpp
-
adiscope::InstrumentNotes QWidget -
instrumentnotes.h
+
gui/instrumentnotes.h
1
adiscope::RunSingleWidget QWidget -
runsinglewidget.h
+
gui/runsinglewidget.h
1
- - adiscope::CustomSwitch - QPushButton -
customSwitch.hpp
-
adiscope::LinkedButton QPushButton -
linked_button.hpp
+
gui/linked_button.hpp
adiscope::MarkerTable @@ -2439,13 +2467,16 @@ QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } adiscope::ImportSettings QWidget -
osc_import_settings.h
+
gui/osc_import_settings.h
1
+ + + diff --git a/ui/spinbox_a.ui b/ui/spinbox_a.ui index a7ee78cac8..3293311d09 100644 --- a/ui/spinbox_a.ui +++ b/ui/spinbox_a.ui @@ -6,8 +6,8 @@ 0 0 - 180 - 65 + 274 + 74 @@ -138,7 +138,7 @@ adiscope::CompletionCircle QDial -
completion_circle.h
+
gui/completion_circle.h
diff --git a/ui/statistics_panel.ui b/ui/statistics_panel.ui index 483c36e71f..ef7a37e233 100644 --- a/ui/statistics_panel.ui +++ b/ui/statistics_panel.ui @@ -190,7 +190,7 @@ QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { adiscope::OscCustomScrollArea QScrollArea -
osc_custom_scroll.h
+
gui/osc_custom_scroll.h
1
diff --git a/ui/subsection_separator.ui b/ui/subsection_separator.ui new file mode 100644 index 0000000000..a30c73598c --- /dev/null +++ b/ui/subsection_separator.ui @@ -0,0 +1,135 @@ + + + SubsectionSeparator + + + + 0 + 0 + 399 + 75 + + + + + 0 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 4 + + + QLayout::SetMinimumSize + + + 0 + + + 25 + + + 15 + + + + + + + + + :/icons/sba_cmb_box_arrow_right.svg + :/icons/sba_cmb_box_arrow.svg:/icons/sba_cmb_box_arrow_right.svg + + + true + + + + + + + + 0 + 0 + + + + TextLabel + + + + + + + + 16777215 + 1 + + + + QFrame::Sunken + + + 1 + + + Qt::Horizontal + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + diff --git a/ui/tool_launcher.ui b/ui/tool_launcher.ui index 64a7fe0dd4..8d86212e02 100644 --- a/ui/tool_launcher.ui +++ b/ui/tool_launcher.ui @@ -314,24 +314,43 @@
- - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 633 + 416 + - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + @@ -1631,31 +1650,34 @@ border-width: 0px; adiscope::DetachDragZone QWidget -
detachdragzone.h
+
gui/detachdragzone.h
1
adiscope::MenuAnim QWidget -
menu_anim.hpp
+
gui/menu_anim.hpp
1
adiscope::OscCustomScrollArea QScrollArea -
osc_custom_scroll.h
+
gui/osc_custom_scroll.h
1
adiscope::StackedHomepage QStackedWidget -
stacked_homepage.h
+
gui/stacked_homepage.h
1
+ + + diff --git a/ui/tool_view.ui b/ui/tool_view.ui new file mode 100644 index 0000000000..6576571344 --- /dev/null +++ b/ui/tool_view.ui @@ -0,0 +1,653 @@ + + + ToolView + + + + 0 + 0 + 1280 + 654 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 40 + + + QLayout::SetDefaultConstraint + + + 15 + + + 40 + + + 9 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 10 + + + + + + + + + + + false + + + + + + + Qt::RightToLeft + + + QPushButton{ + width: 80px; + height: 40px; + + text-align: left; + font-weight: bold; + padding-left: 15px; + padding-right: 15px; +} + + + Print + + + + :/icons/common/ic printer.svg:/icons/common/ic printer.svg + + + + 10 + 10 + + + + true + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 40 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 5 + + + + + + + + + + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 190 + 0 + + + + + 190 + 16777215 + + + + + 0 + + + 10 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 1 + + + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + 0 + + + + + + + + + + + + + + 0 + + + QLayout::SetDefaultConstraint + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 340 + 0 + + + + -1 + + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + + + 1 + + + 1 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 510 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 40 + 20 + + + + + + + + + + + + 40 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 48 + + + + QPushButton { + width: 40px; + height: 20px; + background-color: transparent; +} +QPushButton:pressed { border-image: url(:/icons/common/setup_btn_checked.svg); } +QPushButton:!pressed { border-image: url(:/icons/common/setup_btn_unchecked.svg); } +QPushButton:hover:!pressed:!checked { border-image: url(:/icons/common/setup_btn_hover.svg); } +QPushButton:checked { border-image: url(:/icons/common/setup_btn_checked.svg); } + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + adiscope::MenuAnim + QWidget +
gui/menu_anim.hpp
+ 1 +
+ + adiscope::InstrumentNotes + QWidget +
gui/instrumentnotes.h
+ 1 +
+ + adiscope::RunSingleWidget + QWidget +
gui/runsinglewidget.h
+ 1 +
+ + adiscope::LinkedButton + QPushButton +
gui/linked_button.hpp
+
+ + adiscope::gui::SettingsPairWidget + QWidget +
gui/settings_pair_widget.hpp
+ 1 +
+
+ + +
diff --git a/ui/trigger_settings.ui b/ui/trigger_settings.ui index 83445a51cb..efd179e848 100644 --- a/ui/trigger_settings.ui +++ b/ui/trigger_settings.ui @@ -110,7 +110,7 @@ 0 - -18 + 0 266 958 @@ -958,7 +958,7 @@ color: rgba(255,255,255,51); adiscope::CustomSwitch QPushButton -
customSwitch.hpp
+
gui/customSwitch.hpp
diff --git a/ui/user_notes.ui b/ui/user_notes.ui index 6996283c7b..3923473c08 100644 --- a/ui/user_notes.ui +++ b/ui/user_notes.ui @@ -519,20 +519,21 @@ border-width: 0px; - adiscope::StackedHomepage - QStackedWidget -
stacked_homepage.h
+ adiscope::OscCustomScrollArea + QScrollArea +
gui/osc_custom_scroll.h
1
- adiscope::OscCustomScrollArea - QScrollArea -
osc_custom_scroll.h
+ adiscope::StackedHomepage + QStackedWidget +
gui/stacked_homepage.h
1
+