From dee6a2db6060532a4174057c29acff2664edbfb5 Mon Sep 17 00:00:00 2001 From: IonutMuthi Date: Tue, 26 Nov 2024 02:57:21 -0500 Subject: [PATCH 1/2] generic: what's new carousel popup Signed-off-by: IonutMuthi --- CMakeLists.txt | 7 + cmake/Modules/ScopyWhatsNew.cmake | 45 ++++ core/include/core/scopymainwindow.h | 1 + core/include/core/whatsnewoverlay.h | 55 ++++ core/src/scopymainwindow.cpp | 18 +- core/src/whatsnewoverlay.cpp | 252 ++++++++++++++++++ .../qss/properties/button/whatsNewButton.qss | 27 ++ 7 files changed, 404 insertions(+), 1 deletion(-) create mode 100644 cmake/Modules/ScopyWhatsNew.cmake create mode 100644 core/include/core/whatsnewoverlay.h create mode 100644 core/src/whatsnewoverlay.cpp create mode 100644 gui/style/qss/properties/button/whatsNewButton.qss diff --git a/CMakeLists.txt b/CMakeLists.txt index d8e6a51af5..c9d4ccc2c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,13 @@ file(GLOB UI_LIST *.ui) set(PROJECT_SOURCES ${SRC_LIST} ${HEADER_LIST} ${UI_LIST}) +include(ScopyWhatsNew) +set(FOLDER ${CMAKE_SOURCE_DIR}/resources/whatsnew/) +set(RESOURCE_FILE ${CMAKE_SOURCE_DIR}/resources/whatsnew/whatsnew.qrc) +generate_whats_new("${RESOURCE_FILE}" "${FOLDER}") +file(GLOB WHATS_NEW_RESOURCES resources/whatsnew/whatsnew.qrc) +qt_add_resources(SCOPY_RESOURCES ${WHATS_NEW_RESOURCES}) + include(ScopyAbout) configure_about(./resources/about) file(GLOB SCOPY_RESOURCE_FILES gui/res/resources.qrc resources/aboutpage.qrc) diff --git a/cmake/Modules/ScopyWhatsNew.cmake b/cmake/Modules/ScopyWhatsNew.cmake new file mode 100644 index 0000000000..4655369e81 --- /dev/null +++ b/cmake/Modules/ScopyWhatsNew.cmake @@ -0,0 +1,45 @@ +# +# Copyright (c) 2024 Analog Devices Inc. +# +# This file is part of Scopy +# (see https://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 . +# + +if(DEFINED __INCLUDED_SCOPY_WHATS_NEW_CMAKE) + return() +endif() +set(__INCLUDED_SCOPY_WHATS_NEW_CMAKE TRUE) + +function(generate_whats_new RESOURCE_FILE FOLDER) + # Specify the folder containing resources Create the list of HTML files recursively + + file(GLOB_RECURSE HTML_FILES "${FOLDER}*.html") + + # Start writing to the resource file + file(WRITE "${RESOURCE_FILE}" "\n \n") + + # Loop through each HTML file and add it to the resource file + foreach(HTML_FILE ${HTML_FILES}) + # Convert the file path to a resource path + file(RELATIVE_PATH relative ${FOLDER} ${HTML_FILE}) + + # Write the file to the resource file + file(APPEND "${RESOURCE_FILE}" " ${relative}\n") + endforeach() + + # End the resource file + file(APPEND "${RESOURCE_FILE}" " \n\n") +endfunction() diff --git a/core/include/core/scopymainwindow.h b/core/include/core/scopymainwindow.h index 5e4263e017..5ba6b34546 100644 --- a/core/include/core/scopymainwindow.h +++ b/core/include/core/scopymainwindow.h @@ -108,6 +108,7 @@ public Q_SLOTS: void handleScanner(); void enableScanner(); void deviceAutoconnect(); + void showWhatsNew(); protected: void closeEvent(QCloseEvent *event) override; diff --git a/core/include/core/whatsnewoverlay.h b/core/include/core/whatsnewoverlay.h new file mode 100644 index 0000000000..0332cfb50b --- /dev/null +++ b/core/include/core/whatsnewoverlay.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://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 . + * + */ + +#ifndef WHATSNEWOVERLAY_H +#define WHATSNEWOVERLAY_H + +#include +#include +#include +#include "scopy-core_export.h" +#include +#include +#include + +namespace scopy { +class SCOPY_CORE_EXPORT WhatsNewOverlay : public QWidget +{ + Q_OBJECT +public: + explicit WhatsNewOverlay(QWidget *parent = nullptr); + ~WhatsNewOverlay(); + + void showOverlay(); + void enableTintedOverlay(bool enable = true); + +private: + PopupWidget *m_popupWidget; + QString getHtmlPageContent(QString fileName); + void initCarousel(); + void generateVersionPage(QString filePath); + + QStackedWidget *m_carouselWidget; + QComboBox *m_versionCb; + gui::TintedOverlay *m_tintedOverlay; +}; +} // namespace scopy +#endif // WHATSNEWOVERLAY_H diff --git a/core/src/scopymainwindow.cpp b/core/src/scopymainwindow.cpp index f3c6b3f016..ffc4fe563c 100644 --- a/core/src/scopymainwindow.cpp +++ b/core/src/scopymainwindow.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "logging_categories.h" #include "qmessagebox.h" @@ -254,6 +255,13 @@ void ScopyMainWindow::deviceAutoconnect() } } +void ScopyMainWindow::showWhatsNew() +{ + WhatsNewOverlay *whatsNew = new WhatsNewOverlay(this); + whatsNew->move(this->rect().center() - whatsNew->rect().center()); + QMetaObject::invokeMethod(whatsNew, &WhatsNewOverlay::showOverlay, Qt::QueuedConnection); +} + void ScopyMainWindow::save() { QString selectedFilter; @@ -351,6 +359,7 @@ void ScopyMainWindow::setupPreferences() if(p->get("general_show_status_bar").toBool()) { StatusBarManager::GetInstance()->setEnabled(true); } + if(p->get("general_first_run").toBool()) { license = new LicenseOverlay(this); auto versionCheckInfo = new VersionCheckMessage(this); @@ -358,9 +367,15 @@ void ScopyMainWindow::setupPreferences() StatusBarManager::pushWidget(versionCheckInfo, "Should Scopy check for online versions?"); QMetaObject::invokeMethod(license, &LicenseOverlay::showOverlay, Qt::QueuedConnection); + + connect(license->getContinueBtn(), &QPushButton::clicked, this, &ScopyMainWindow::showWhatsNew, + Qt::QueuedConnection); } -} + if(p->get("general_show_whats_new").toBool() && !p->get("general_first_run").toBool()) { + showWhatsNew(); + } +} void ScopyMainWindow::initPreferences() { QElapsedTimer timer; @@ -374,6 +389,7 @@ void ScopyMainWindow::initPreferences() p->init("general_save_session", true); p->init("general_save_attached", true); p->init("general_doubleclick_attach", true); + p->init("general_show_whats_new", true); #if defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) p->init("general_use_opengl", false); #else diff --git a/core/src/whatsnewoverlay.cpp b/core/src/whatsnewoverlay.cpp new file mode 100644 index 0000000000..c3aad3e528 --- /dev/null +++ b/core/src/whatsnewoverlay.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2024 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://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 . + * + */ + +#include "whatsnewoverlay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace scopy; + +WhatsNewOverlay::WhatsNewOverlay(QWidget *parent) + : m_tintedOverlay(nullptr) + , QWidget{parent} +{ + // main layout vertical + this->resize(400, 600); + QVBoxLayout *mainLayout = new QVBoxLayout(); + this->setLayout(mainLayout); + + m_carouselWidget = new QStackedWidget(this); + + // bottom of main layout has controll widget + + QWidget *overlayControllWidget = new QWidget(this); + QVBoxLayout *overlayControllWidgetLayout = new QVBoxLayout(overlayControllWidget); + + QWidget *optionsoverlayControllWidget = new QWidget(overlayControllWidget); + overlayControllWidgetLayout->addWidget(optionsoverlayControllWidget); + QHBoxLayout *optionsControllLayout = new QHBoxLayout(optionsoverlayControllWidget); + optionsoverlayControllWidget->setLayout(optionsControllLayout); + + QCheckBox *showAgain = new QCheckBox("Show this again", optionsoverlayControllWidget); + showAgain->setChecked(true); + optionsControllLayout->addWidget(showAgain); + + connect(showAgain, &QCheckBox::toggled, this, [=](bool en) { + Preferences *p = Preferences::GetInstance(); + p->set("general_show_whats_new", en); + }); + + // version picker + m_versionCb = new QComboBox(optionsoverlayControllWidget); + optionsControllLayout->addWidget(m_versionCb); + + connect(m_versionCb, qOverload(&QComboBox::currentIndexChanged), this, + [=](int idx) { m_carouselWidget->setCurrentIndex(idx); }); + + QPushButton *okButton = new QPushButton("Ok", optionsoverlayControllWidget); + connect(okButton, &QPushButton::clicked, this, [=]() { this->deleteLater(); }); + Style::setStyle(okButton, style::properties::button::basicButton, true, true); + optionsControllLayout->addWidget(okButton); + + mainLayout->addWidget(m_carouselWidget); + mainLayout->addWidget(overlayControllWidget); + Style::setBackgroundColor(this, json::theme::background_primary); + + initCarousel(); + enableTintedOverlay(true); +} + +WhatsNewOverlay::~WhatsNewOverlay() +{ + // TODO + if(m_tintedOverlay != nullptr) { + m_tintedOverlay->deleteLater(); + } +} + +void WhatsNewOverlay::showOverlay() +{ + raise(); + show(); +} + +void WhatsNewOverlay::enableTintedOverlay(bool enable) +{ + if(enable) { + delete m_tintedOverlay; + + m_tintedOverlay = new gui::TintedOverlay(parentWidget()); + m_tintedOverlay->show(); + raise(); + show(); + } else { + delete m_tintedOverlay; + m_tintedOverlay = nullptr; + } +} + +void WhatsNewOverlay::initCarousel() +{ + QDir dir(":/whatsnew"); + + // Get a list of all entries in the directory + QFileInfoList entries = dir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name); + + // Iterate through the list and print the folder names + + for(int i = entries.count() - 1; i >= 0; i--) { + QFileInfo fileInfo = entries.at(i); + if(fileInfo.isDir()) { + // add option to combo + m_versionCb->addItem(fileInfo.fileName()); + // create page and button for page + generateVersionPage(fileInfo.absoluteFilePath()); + } + } +} + +void WhatsNewOverlay::generateVersionPage(QString filePath) +{ + QWidget *carouselContent = new QWidget(m_carouselWidget); + QVBoxLayout *carouselContentLayout = new QVBoxLayout(carouselContent); + carouselContentLayout->setMargin(2); + carouselContentLayout->setSpacing(0); + + QStackedWidget *versionCarouselWithControlls = new QStackedWidget(m_carouselWidget); + carouselContentLayout->addWidget(versionCarouselWithControlls, 9); + + QDir versionDir(filePath); + QFileInfoList fileList = versionDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot); + + for(const QFileInfo &page : fileList) { + + QWidget *scrollWidget = new QWidget(); + scrollWidget->setLayout(new QVBoxLayout()); + QScrollArea *scrollArea = new QScrollArea(); + scrollArea->setWidgetResizable(true); + scrollArea->setWidget(scrollWidget); + + QTextBrowser *htmlPage = new QTextBrowser(scrollWidget); + QString filePath(page.absoluteFilePath()); + htmlPage->setHtml(getHtmlPageContent(filePath)); + htmlPage->setProperty("openExternalLinks", true); + + scrollWidget->layout()->addWidget(htmlPage); + versionCarouselWithControlls->addWidget(scrollArea); + Style::setStyle(scrollWidget, style::properties::widget::border_interactive), true, true; + } + + int numberOfPages = fileList.count(); + + if(numberOfPages > 1) { + // carousel control contains buttons for changeing info page + QWidget *carouselControllWidget = new QWidget(carouselContent); + + QButtonGroup *m_carouselButtons = new QButtonGroup(carouselControllWidget); + m_carouselButtons->setExclusive(true); + + QHBoxLayout *carouselControllLayout = new QHBoxLayout(carouselControllWidget); + carouselControllWidget->setLayout(carouselControllLayout); + carouselControllLayout->setContentsMargins(0, 0, 0, 4); + + QPushButton *previous = new QPushButton(carouselControllWidget); + + StyleHelper::BlueIconButton(previous, + Style::getPixmap(":/gui/icons/handle_left_arrow.svg", + Style::getColor(json::theme::content_inverse)), + "previousButton"); + + carouselControllLayout->addWidget(previous); + carouselControllLayout->addSpacerItem( + new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding)); + + for(int i = 0; i < numberOfPages; i++) { + + QPushButton *htmlPageButton = new QPushButton("", carouselControllWidget); + htmlPageButton->setCheckable(true); + + if(i == 0) { + htmlPageButton->setChecked(true); + } + + connect(htmlPageButton, &QPushButton::toggled, this, [=](bool toggled) { + if(toggled) { + versionCarouselWithControlls->setCurrentIndex(i); + } + }); + + carouselControllLayout->addWidget(htmlPageButton, 0, Qt::AlignBottom); + // carouselControllLayout->setAlignment(htmlPageButton, Qt::AlignBottom); + m_carouselButtons->addButton(htmlPageButton, i); + Style::setStyle(htmlPageButton, style::properties::button::whatsNewButton, true, true); + htmlPageButton->setFixedHeight(Style::getAttribute(json::global::radius_2).toInt()); + } + + QPushButton *next = new QPushButton(carouselControllWidget); + StyleHelper::BlueIconButton(next, + Style::getPixmap(":/gui/icons/handle_right_arrow.svg", + Style::getColor(json::theme::content_inverse)), + "nextButton"); + + carouselControllLayout->addSpacerItem( + new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding)); + carouselControllLayout->addWidget(next); + + connect(previous, &QPushButton::clicked, this, [=]() { + int currentIndex = m_carouselButtons->checkedId(); + int previousIndex = (currentIndex - 1 + numberOfPages) % numberOfPages; + m_carouselButtons->button(previousIndex)->setChecked(true); + }); + + connect(next, &QPushButton::clicked, this, [=]() { + int currentIndex = m_carouselButtons->checkedId(); + int nextIndex = (currentIndex + 1) % numberOfPages; + m_carouselButtons->button(nextIndex)->setChecked(true); + }); + + carouselContentLayout->addWidget(carouselControllWidget, 1); + } + + m_carouselWidget->addWidget(carouselContent); +} + +QString WhatsNewOverlay::getHtmlPageContent(QString fileName) +{ + QFile file(fileName); + file.open(QIODevice::ReadOnly); + QString text = QString(file.readAll()); + file.close(); + + return text; +} + +#include "moc_whatsnewoverlay.cpp" + +#include diff --git a/gui/style/qss/properties/button/whatsNewButton.qss b/gui/style/qss/properties/button/whatsNewButton.qss new file mode 100644 index 0000000000..0afd9de96b --- /dev/null +++ b/gui/style/qss/properties/button/whatsNewButton.qss @@ -0,0 +1,27 @@ +QPushButton[&&property&&=true] { + height: &radius_1&; + width: &radius_1&; + border-radius: &radius_1&; + background-color: &content_silent&; + color: &content_inverse&; + font-weight: 700; + /* qproperty-iconSize: &unit_4&px; */ +} +QPushButton[&&property&&=true]:hover { + background-color: &content_default&; + color: &content_inverse&; +} + +QPushButton[&&property&&=true]:pressed { + background-color: &content_silent&; + color: &content_inverse&; +} + +QPushButton[&&property&&=true]:disabled { + background-color: &interactive_subtle_disabled&; +} + +QPushButton[&&property&&=true]:checked { + background-color: &content_default&; + color: &content_inverse&; +} From 594e9360c0f80545bbfa1b1a539c29c23f0ba11f Mon Sep 17 00:00:00 2001 From: IonutMuthi Date: Thu, 28 Nov 2024 08:56:48 -0500 Subject: [PATCH 2/2] generic: whats new pages for v2.0.0 Signed-off-by: IonutMuthi --- resources/whatsnew/V2.0.0/1.html | 18 ++++++++++++++++++ resources/whatsnew/V2.0.0/2.html | 13 +++++++++++++ resources/whatsnew/V2.0.0/3.html | 14 ++++++++++++++ resources/whatsnew/V2.0.0/4.html | 26 ++++++++++++++++++++++++++ resources/whatsnew/V2.0.0/5.html | 12 ++++++++++++ 5 files changed, 83 insertions(+) create mode 100644 resources/whatsnew/V2.0.0/1.html create mode 100644 resources/whatsnew/V2.0.0/2.html create mode 100644 resources/whatsnew/V2.0.0/3.html create mode 100644 resources/whatsnew/V2.0.0/4.html create mode 100644 resources/whatsnew/V2.0.0/5.html diff --git a/resources/whatsnew/V2.0.0/1.html b/resources/whatsnew/V2.0.0/1.html new file mode 100644 index 0000000000..57cc439a54 --- /dev/null +++ b/resources/whatsnew/V2.0.0/1.html @@ -0,0 +1,18 @@ + + + + +

Register Map

+

The Register Map allows access to reading and writing registers for devices connected to Scopy.

+
    +
  • You can perform a register dump saving all currently read data in a local file
  • +
  • You can load saved data from a file
  • +
  • If provided with an .xml file of the register map that follows the format detailed in the documentation the plugin will generate an table view matching the .xml file contents
  • + +
+ +

More Information

+

For more detailed information, please visit the official documentation.

+ + + diff --git a/resources/whatsnew/V2.0.0/2.html b/resources/whatsnew/V2.0.0/2.html new file mode 100644 index 0000000000..db8764b166 --- /dev/null +++ b/resources/whatsnew/V2.0.0/2.html @@ -0,0 +1,13 @@ + + + + +

ADC plugin

+

The ADC plugin is used to interface with IIO ADCs that implement an IIO buffer mechanism. The plugin implements two instruments for data acquisition and visualization in time and frequency domain. + The plugin is compatible with contexts that have at least an IIO device that implements an IIO buffer interface.

+ +

More Information

+

For more detailed information, please visit the official documentation.

+ + + diff --git a/resources/whatsnew/V2.0.0/3.html b/resources/whatsnew/V2.0.0/3.html new file mode 100644 index 0000000000..3029980086 --- /dev/null +++ b/resources/whatsnew/V2.0.0/3.html @@ -0,0 +1,14 @@ + + + + +

DAC plugin

+

The DAC plugin is used to interface with IIO DACs that implement the IIO buffer mechanism or a DDS mechanism. The plugin consists of an instrument with two data generation modes. + + The plugin is compatible with contexts that have at least one IIO device that implements an output IIO buffer or at least one DDS (ALTVOLTAGE) output channel.

+ +

More Information

+

For more detailed information, please visit the official documentation.

+ + + diff --git a/resources/whatsnew/V2.0.0/4.html b/resources/whatsnew/V2.0.0/4.html new file mode 100644 index 0000000000..7a0a05755f --- /dev/null +++ b/resources/whatsnew/V2.0.0/4.html @@ -0,0 +1,26 @@ + + + + +

PQM

+

The PQM (power quality module) plugin adds support for Scopy PQM and the following components

+
    +
  • +

    RMS

    +

    The main purpose of this instrument is to display and graphically represent the RMS and the angle of each phase (for both voltage and current). At the same time, information such as voltage and current unbalance or flicker data can also be inferred from here. Each time new data is available, the tool updates accordingly.

    +
  • +
  • +

    Harmonics

    +

    The main purpose of this instrument is to display and graphically represent the voltage and current harmonics or inter harmonics. Each time new data is available, the tool updates accordingly.

    +
  • +
  • +

    Waveform

    +

    The main purpose of this instrument is to display the waveform of the voltage and current for each phase. In one second, 10 cycles should be displayed at a frequency of 50 Hz, or 12 cycles at a frequency of 60 Hz.

    +
  • +
+ +

More Information

+

For more detailed information, please visit the official documentation.

+ + + diff --git a/resources/whatsnew/V2.0.0/5.html b/resources/whatsnew/V2.0.0/5.html new file mode 100644 index 0000000000..083ccaf800 --- /dev/null +++ b/resources/whatsnew/V2.0.0/5.html @@ -0,0 +1,12 @@ + + + + +

AD-SWIOT1L-SL

+

The Scopy AD-SWIOT1L-SL plugin is responsible with the operation and control of the AD-SWIOT1L-SL platform. The Scopy AD-SWIOT1L-SL plugin, while based on the Scopy application infrastructure, is tailored to provide all the specific functionalities of this system.

+ +

More Information

+

For more detailed information, please visit the official documentation.

+ + +