diff --git a/plugins/regmap/resources/resources.qrc b/plugins/regmap/resources/resources.qrc index 07194af9d2..7dfe61e630 100644 --- a/plugins/regmap/resources/resources.qrc +++ b/plugins/regmap/resources/resources.qrc @@ -1,3 +1,5 @@ - + + tutorial_chapters.json + diff --git a/plugins/regmap/resources/tutorial_chapters.json b/plugins/regmap/resources/tutorial_chapters.json new file mode 100644 index 0000000000..b31c746092 --- /dev/null +++ b/plugins/regmap/resources/tutorial_chapters.json @@ -0,0 +1,161 @@ +{ + "simple_registermap" : [ + { + "index": 1, + "names": ["DEVICE_LIST"], + "description": "Select the device", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": 10 + }, + { + "index": 2, + "names": ["SETTINGS_BUTTON"], + "description": "Settings", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": 10, + "x_offset": -120 + } + ], + "simple_register_controller" : [ + { + "index": 1, + "names": ["READ_WIDGET"], + "description": "Read value for selected device", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": -5 + }, + { + "index": 2, + "names": ["WRITE_WIDGET"], + "description": "Write value to selected register. After writing a the register will automatically read value from selected register.", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": -5 + } + ], + "register_controller" : [ + { + "index": 1, + "names": ["READ_WIDGET"], + "description": "Read value for selected device", + "anchor": "HP_TOP", + "content": "HP_TOP", + "y_offset": -5 + }, + { + "index": 2, + "names": ["WRITE_WIDGET"], + "description": "Write value to selected register. After writing a the register will automatically read value from selected register.", + "anchor": "HP_TOP", + "content": "HP_TOP", + "y_offset": -5 + + }, + { + "index": 3, + "names": ["TOGGLE_DETAILED_BUTTON"], + "description": "Show/hide detailed bitfields", + "anchor": "HP_TOP", + "content": "HP_TOP", + "y_offset": -5, + "x_offset": -120 + } + ], + "registermap": [ + { + "index": 1, + "names": ["DEVICE_LIST"], + "description": "Select the device", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": 10 + }, + { + "index": 2, + "names": ["SEARCH_BAR"], + "description": "Search register by name or address of register or bitfields of register", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": 10 + }, + { + "index": 3, + "names": ["SETTINGS_BUTTON"], + "description": "Settings", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": 10, + "x_offset": -120 + } + + ], + "settings" : [ + { + "index": 1, + "names": ["AUTOREAD"], + "description": "When enabled each time a new register is selected a read is automatically done.", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": 10, + "x_offset": -120 + }, + { + "index": 2, + "names": ["READ_INTERVAL"], + "description": "Provide a start and end interval values to be able to read all registers in that interval.", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": 10, + "x_offset": -120 + }, + { + "index": 3, + "names": ["FIND_PATH"], + "description": "Select a file that will be used for Write Values and Register Dump actions.", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": 10, + "x_offset": -120 + }, + { + "index": 4, + "names": ["WRITE_VALUES"], + "description": "Write all values from provided files to registers.", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": 10, + "x_offset": -120 + }, + { + "index": 5, + "names": ["REGISTER_DUMP"], + "description": "Save all read registers to selected file.", + "anchor": "HP_BOTTOM", + "content": "HP_BOTTOM", + "y_offset": 10, + "x_offset": -120 + } + ], + "device_register_map": [ + { + "index": 1, + "names": ["DETAILED_BITFIELDS"], + "description": "Detailed bitfields where you can change individual bitfields values", + "anchor": "HP_TOP", + "content": "HP_TOP", + "y_offset": 10 + }, + { + "index": 2, + "names": ["REGISTER_MAP"], + "description": "Map of all registers where you can see values and information", + "anchor": "HP_TOP", + "content": "HP_TOP", + "y_offset": 300, + "x_offset": 500 + } + ] +} diff --git a/plugins/regmap/src/deviceregistermap.cpp b/plugins/regmap/src/deviceregistermap.cpp index 880c570827..807da275d9 100644 --- a/plugins/regmap/src/deviceregistermap.cpp +++ b/plugins/regmap/src/deviceregistermap.cpp @@ -131,7 +131,9 @@ DeviceRegisterMap::DeviceRegisterMap(RegisterMapTemplate *registerMapTemplate, R tableHeadWidgetLayout->addWidget(registerTableHead, 1); tableHeadWidgetLayout->addWidget(colBitCount, 8); registerMapTableLayout->addWidget(tableHeadWidget); + registerMapTableWidget = new RegisterMapTable(registerMapTemplate->getRegisterList(), this); + registerMapTable->setProperty("tutorial_name", "REGISTER_MAP"); QWidget *aux = registerMapTableWidget->getWidget(); if(aux) { @@ -180,12 +182,17 @@ DeviceRegisterMap::DeviceRegisterMap(RegisterMapTemplate *registerMapTemplate, R tool->addWidgetToCentralContainerHelper(controllerWidget); controllerLayout->addWidget(registerController); + initSimpleTutorial(); if(registerMapTemplate) { registerChanged(registerMapTemplate->getRegisterList()->first()); + initTutorial(); + } else { tool->centralContainer()->layout()->addItem( new QSpacerItem(10, 10, QSizePolicy::Preferred, QSizePolicy::Expanding)); } + + connect(this, &DeviceRegisterMap::tutorialAborted, this, &DeviceRegisterMap::abortTutorial); } DeviceRegisterMap::~DeviceRegisterMap() @@ -212,6 +219,7 @@ void DeviceRegisterMap::registerChanged(RegisterModel *regModel) } registerDetailedWidget = new RegisterDetailedWidget(regModel, tool->bottomContainer()); + registerDetailedWidget->setProperty("tutorial_name", "DETAILED_BITFIELDS"); registerDetailedWidget->setMaximumHeight(140); tool->bottomCentral()->layout()->addWidget(registerDetailedWidget); @@ -251,6 +259,8 @@ bool DeviceRegisterMap::hasTemplate() } bool DeviceRegisterMap::getAutoread() { return autoread; } +void DeviceRegisterMap::startTutorial() { registerController->startTutorial(); } +void DeviceRegisterMap::startSimpleTutorial() { registerController->startSimpleTutorial(); } void DeviceRegisterMap::initSettings() { @@ -259,3 +269,27 @@ void DeviceRegisterMap::initSettings() &RegisterMapValues::registerDump); QObject::connect(this, &DeviceRegisterMap::requestWrite, registerMapValues, &RegisterMapValues::requestWrite); } + +void DeviceRegisterMap::initTutorial() +{ + + controllerTutorialFinish = connect(registerController, &RegisterController::tutorialFinished, this, [=]() { + QWidget *parent = Util::findContainingWindow(this); + tutorial = new gui::TutorialBuilder(this, ":/registermap/tutorial_chapters.json", "device_register_map", + parent); + + connect(tutorial, &gui::TutorialBuilder::finished, this, [=]() { Q_EMIT tutorialFinished(); }); + connect(tutorial, &gui::TutorialBuilder::aborted, this, &DeviceRegisterMap::tutorialAborted); + tutorial->setTitle("Tutorial"); + tutorial->start(); + }); +} + +void DeviceRegisterMap::initSimpleTutorial() +{ + connect(registerController, &RegisterController::tutorialAborted, this, &DeviceRegisterMap::tutorialAborted); + connect(registerController, &RegisterController::simpleTutorialFinished, this, + &DeviceRegisterMap::simpleTutorialFinished); +} + +void DeviceRegisterMap::abortTutorial() { disconnect(controllerTutorialFinish); } diff --git a/plugins/regmap/src/deviceregistermap.hpp b/plugins/regmap/src/deviceregistermap.hpp index 72818babdf..d483f3afb3 100644 --- a/plugins/regmap/src/deviceregistermap.hpp +++ b/plugins/regmap/src/deviceregistermap.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "scopy-regmap_export.h" class QVBoxLayout; @@ -57,6 +58,16 @@ class SCOPY_REGMAP_EXPORT DeviceRegisterMap : public QWidget void applyFilters(QString filter); bool hasTemplate(); bool getAutoread(); + void startTutorial(); + void startSimpleTutorial(); + +Q_SIGNALS: + void requestRead(uint32_t address); + void requestWrite(uint32_t address, uint32_t value); + void requestRegisterDump(QString path); + void tutorialFinished(); + void simpleTutorialFinished(); + void tutorialAborted(); private: ToolTemplate *tool; @@ -73,10 +84,12 @@ class SCOPY_REGMAP_EXPORT DeviceRegisterMap : public QWidget void initSettings(); int selectedRegister; -Q_SIGNALS: - void requestRead(uint32_t address); - void requestWrite(uint32_t address, uint32_t value); - void requestRegisterDump(QString path); + void initTutorial(); + void initSimpleTutorial(); + void abortTutorial(); + gui::TutorialBuilder *tutorial; + QMetaObject::Connection controllerTutorialFinish; + QMetaObject::Connection mapTutorialFinish; }; } // namespace scopy::regmap #endif // DEVICEREGISTERMAP_HPP diff --git a/plugins/regmap/src/register/registerdetailedwidget.hpp b/plugins/regmap/src/register/registerdetailedwidget.hpp index 264ef6caf5..a398a4def9 100644 --- a/plugins/regmap/src/register/registerdetailedwidget.hpp +++ b/plugins/regmap/src/register/registerdetailedwidget.hpp @@ -42,6 +42,7 @@ class RegisterDetailedWidget : public QWidget private: QVector *bitFieldList; int regWidth; + Q_SIGNALS: void bitFieldValueChanged(QString value); }; diff --git a/plugins/regmap/src/registercontroller.cpp b/plugins/regmap/src/registercontroller.cpp index c170a07131..2c19d2e472 100644 --- a/plugins/regmap/src/registercontroller.cpp +++ b/plugins/regmap/src/registercontroller.cpp @@ -119,6 +119,9 @@ RegisterController::RegisterController(QWidget *parent) writeWidgetLayout->addWidget(writeButton, 1, Qt::AlignRight); applyStyle(); + + readWidget->setProperty("tutorial_name", "READ_WIDGET"); + writeWidget->setProperty("tutorial_name", "WRITE_WIDGET"); } RegisterController::~RegisterController() @@ -164,6 +167,8 @@ void RegisterController::setHasMap(bool hasMap) writeWidgetLayout->addWidget(detailedRegisterToggle, 0.5, Qt::AlignRight); Style::setStyle(detailedRegisterToggle, style::properties::button::squareIconButton, true, true); detailedRegisterToggle->setFixedSize(32, 32); + + detailedRegisterToggle->setProperty("tutorial_name", "TOGGLE_DETAILED_BUTTON"); } } @@ -179,3 +184,31 @@ void RegisterController::applyStyle() // setStyleSheet(RegmapStyleHelper::regmapControllerStyle(nullptr)); } + +void RegisterController::startTutorial() +{ + QWidget *parent = Util::findContainingWindow(this); + registerMapTutorial = + new gui::TutorialBuilder(this, ":/registermap/tutorial_chapters.json", "register_controller", parent); + + connect(registerMapTutorial, &gui::TutorialBuilder::finished, this, [=]() { Q_EMIT tutorialFinished(); }); + connect(registerMapTutorial, &gui::TutorialBuilder::aborted, this, &RegisterController::tutorialAborted); + + registerMapTutorial->setTitle("Tutorial"); + registerMapTutorial->start(); +} + +void RegisterController::startSimpleTutorial() +{ + QWidget *parent = Util::findContainingWindow(this); + registerMapSimpleTutorial = new gui::TutorialBuilder(this, ":/registermap/tutorial_chapters.json", + "simple_register_controller", parent); + + connect(registerMapSimpleTutorial, &gui::TutorialBuilder::finished, this, + [=]() { Q_EMIT simpleTutorialFinished(); }); + + connect(registerMapSimpleTutorial, &gui::TutorialBuilder::aborted, this, &RegisterController::tutorialAborted); + + registerMapSimpleTutorial->setTitle("Tutorial"); + registerMapSimpleTutorial->start(); +} diff --git a/plugins/regmap/src/registercontroller.hpp b/plugins/regmap/src/registercontroller.hpp index 60eddcd149..8e65e710cc 100644 --- a/plugins/regmap/src/registercontroller.hpp +++ b/plugins/regmap/src/registercontroller.hpp @@ -27,6 +27,7 @@ #include "scopy-regmap_export.h" #include +#include class QHBoxLayout; class QSpinBox; @@ -54,6 +55,18 @@ class SCOPY_REGMAP_EXPORT RegisterController : public QWidget void registerValueChanged(QString value); QString getAddress(); void setHasMap(bool hasMap); + void startTutorial(); + void startSimpleTutorial(); + +Q_SIGNALS: + void requestRead(uint32_t address); + void requestWrite(uint32_t address, uint32_t value); + void registerAddressChanged(uint32_t address); + void valueChanged(QString value); + void toggleDetailedMenu(bool toggled); + void tutorialFinished(); + void simpleTutorialFinished(); + void tutorialAborted(); private: QHBoxLayout *mainLayout; @@ -72,13 +85,8 @@ class SCOPY_REGMAP_EXPORT RegisterController : public QWidget bool addressChanged = false; bool hasMap = false; void applyStyle(); - -Q_SIGNALS: - void requestRead(uint32_t address); - void requestWrite(uint32_t address, uint32_t value); - void registerAddressChanged(uint32_t address); - void valueChanged(QString value); - void toggleDetailedMenu(bool toggled); + gui::TutorialBuilder *registerMapTutorial; + gui::TutorialBuilder *registerMapSimpleTutorial; }; } // namespace scopy::regmap #endif // REGISTERCONTROLLER_HPP diff --git a/plugins/regmap/src/registermapsettingsmenu.cpp b/plugins/regmap/src/registermapsettingsmenu.cpp index 4f3d9c8041..b42835185a 100644 --- a/plugins/regmap/src/registermapsettingsmenu.cpp +++ b/plugins/regmap/src/registermapsettingsmenu.cpp @@ -37,6 +37,7 @@ #include #include +#include using namespace scopy; using namespace regmap; @@ -167,6 +168,29 @@ RegisterMapSettingsMenu::RegisterMapSettingsMenu(QWidget *parent) this->layout()->addItem(spacer); applyStyle(); + + // init tutorial properties + autoread->setProperty("tutorial_name", "AUTOREAD"); + setIntervalWidget->setProperty("tutorial_name", "READ_INTERVAL"); + findPathWidget->setProperty("tutorial_name", "FIND_PATH"); + writeListOfValuesButton->setProperty("tutorial_name", "WRITE_VALUES"); + registerDump->setProperty("tutorial_name", "REGISTER_DUMP"); } void RegisterMapSettingsMenu::applyStyle() { RegmapStyleHelper::regmapSettingsMenu(this); } + +void RegisterMapSettingsMenu::startTutorial() +{ + QWidget *parent = Util::findContainingWindow(this); + gui::TutorialBuilder *settingsTutorial = + new gui::TutorialBuilder(this, ":/registermap/tutorial_chapters.json", "settings", parent); + settingsTutorial->setTitle("Tutorial"); + settingsTutorial->start(); + + auto settingsTutorialFinish = connect(settingsTutorial, &gui::TutorialBuilder::finished, this, + &RegisterMapSettingsMenu::tutorialDone, Qt::UniqueConnection); + connect(settingsTutorial, &gui::TutorialBuilder::aborted, this, [=, this]() { + disconnect(settingsTutorialFinish); + Q_EMIT tutorialAborted(); + }); +} diff --git a/plugins/regmap/src/registermapsettingsmenu.hpp b/plugins/regmap/src/registermapsettingsmenu.hpp index 08dafaa9cd..fa88186448 100644 --- a/plugins/regmap/src/registermapsettingsmenu.hpp +++ b/plugins/regmap/src/registermapsettingsmenu.hpp @@ -42,11 +42,15 @@ class RegisterMapSettingsMenu : public QWidget public: explicit RegisterMapSettingsMenu(QWidget *parent = nullptr); + void startTutorial(); + Q_SIGNALS: void autoreadToggled(bool toggled); void requestRead(int address); void requestWrite(uint32_t address, uint32_t value); void requestRegisterDump(QString path); + void tutorialDone(); + void tutorialAborted(); private: MenuHeaderWidget *header; diff --git a/plugins/regmap/src/registermaptool.cpp b/plugins/regmap/src/registermaptool.cpp index 6b70af5ca2..f6b3be8a85 100644 --- a/plugins/regmap/src/registermaptool.cpp +++ b/plugins/regmap/src/registermaptool.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,8 @@ #include #include +#include + using namespace scopy; using namespace regmap; @@ -105,6 +108,8 @@ RegisterMapTool::RegisterMapTool(QWidget *parent) QObject::connect(searchBarWidget, &SearchBarWidget::requestSearch, this, [=](QString searchParam) { deviceList->value(registerDeviceList->currentText())->applyFilters(searchParam); }); + + initTutorialProperties(); } RegisterMapTool::~RegisterMapTool() { delete deviceList; } @@ -153,6 +158,72 @@ void RegisterMapTool::toggleSettingsMenu(QString registerName, bool toggle) } } +void RegisterMapTool::initTutorialProperties() +{ + registerDeviceList->setProperty("tutorial_name", "DEVICE_LIST"); + settingsMenu->setProperty("tutorial_name", "SETTINGS_BUTTON"); + searchBarWidget->setProperty("tutorial_name", "SEARCH_BAR"); +} + +void RegisterMapTool::startTutorial() +{ + settingsMenu->setChecked(true); + + QWidget *parent = Util::findContainingWindow(this); + gui::TutorialBuilder *registerMapTutorial = + new gui::TutorialBuilder(this, ":/registermap/tutorial_chapters.json", "registermap", parent); + + settingsTutorialFinish = connect(registerMapTutorial, &gui::TutorialBuilder::finished, settings, + &RegisterMapSettingsMenu::startTutorial, Qt::UniqueConnection); + + controllerTutorial = connect( + settings, &RegisterMapSettingsMenu::tutorialDone, this, + [=, this]() { deviceList->value(activeRegisterMap)->startTutorial(); }, Qt::UniqueConnection); + + connect(deviceList->value(activeRegisterMap), &DeviceRegisterMap::tutorialFinished, this, + &RegisterMapTool::tutorialAborted); + connect(deviceList->value(activeRegisterMap), &DeviceRegisterMap::tutorialAborted, this, + &RegisterMapTool::tutorialAborted); + + connect(registerMapTutorial, &gui::TutorialBuilder::aborted, this, &RegisterMapTool::tutorialAborted); + connect(settings, &RegisterMapSettingsMenu::tutorialAborted, this, &RegisterMapTool::tutorialAborted); + + registerMapTutorial->setTitle("Tutorial"); + registerMapTutorial->start(); +} + +void RegisterMapTool::startSimpleTutorial() +{ + settingsMenu->setChecked(true); + + QWidget *parent = Util::findContainingWindow(this); + gui::TutorialBuilder *registerMapTutorial = + new gui::TutorialBuilder(this, ":/registermap/tutorial_chapters.json", "simple_registermap", parent); + + settingsTutorialFinish = connect(registerMapTutorial, &gui::TutorialBuilder::finished, settings, + &RegisterMapSettingsMenu::startTutorial, Qt::UniqueConnection); + + controllerTutorial = connect( + settings, &RegisterMapSettingsMenu::tutorialDone, this, + [=, this]() { deviceList->value(activeRegisterMap)->startSimpleTutorial(); }, Qt::UniqueConnection); + + connect(deviceList->value(activeRegisterMap), &DeviceRegisterMap::simpleTutorialFinished, this, + &RegisterMapTool::tutorialAborted); + connect(deviceList->value(activeRegisterMap), &DeviceRegisterMap::tutorialAborted, this, + &RegisterMapTool::tutorialAborted); + connect(registerMapTutorial, &gui::TutorialBuilder::aborted, this, &RegisterMapTool::tutorialAborted); + connect(settings, &RegisterMapSettingsMenu::tutorialAborted, this, &RegisterMapTool::tutorialAborted); + + registerMapTutorial->setTitle("Tutorial"); + registerMapTutorial->start(); +} + +void RegisterMapTool::tutorialAborted() +{ + disconnect(settingsTutorialFinish); + disconnect(controllerTutorial); +} + void RegisterMapTool::updateActiveRegisterMap(QString registerName) { if(activeRegisterMap != "" && registerName != activeRegisterMap) { @@ -179,3 +250,19 @@ void RegisterMapTool::toggleSearchBarEnabled(bool enabled) searchBarWidget->hide(); } } + +void RegisterMapTool::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); + + // Handle tutorial + if(Preferences::get("regmapplugin_start_tutorial").toBool()) { + if(searchBarWidget->isVisible()) { + + startTutorial(); + } else { + startSimpleTutorial(); + } + Preferences::set("regmapplugin_start_tutorial", false); + } +} diff --git a/plugins/regmap/src/registermaptool.hpp b/plugins/regmap/src/registermaptool.hpp index d198149a88..0dd42f9cf4 100644 --- a/plugins/regmap/src/registermaptool.hpp +++ b/plugins/regmap/src/registermaptool.hpp @@ -32,6 +32,10 @@ class QComboBox; namespace scopy { + +namespace gui { +class TutorialBuilder; +} namespace regmap { class RegisterMapValues; @@ -66,9 +70,17 @@ class SCOPY_REGMAP_EXPORT RegisterMapTool : public QWidget bool first = true; void toggleSettingsMenu(QString registerName, bool toggle); + void initTutorialProperties(); + void startTutorial(); + void startSimpleTutorial(); + void tutorialAborted(); + QMetaObject::Connection settingsTutorialFinish; + QMetaObject::Connection controllerTutorial; + private Q_SLOTS: void updateActiveRegisterMap(QString registerName); void toggleSearchBarEnabled(bool enabled); + void showEvent(QShowEvent *event) override; }; } // namespace regmap } // namespace scopy diff --git a/plugins/regmap/src/regmapplugin.cpp b/plugins/regmap/src/regmapplugin.cpp index c63f4ffcda..66e1eb0e1d 100644 --- a/plugins/regmap/src/regmapplugin.cpp +++ b/plugins/regmap/src/regmapplugin.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -134,6 +135,7 @@ void RegmapPlugin::initPreferences() { Preferences *p = Preferences::GetInstance(); p->init("regmap_color_by_value", "Default"); + p->init("regmapplugin_start_tutorial", true); #if defined __APPLE__ p->init("additional_regmap_xml_path", QCoreApplication::applicationDirPath() + "/plugins/xmls"); #else @@ -164,6 +166,22 @@ bool RegmapPlugin::loadPreferencesPage() "Register background and Bitfield background", "Register text and Bitfield text", "Register background and Bitfield text", "Register text and Bitfield background"}, generalSection)); + + QWidget *resetTutorialWidget = new QWidget(); + QHBoxLayout *resetTutorialWidgetLayout = new QHBoxLayout(); + + resetTutorialWidget->setLayout(resetTutorialWidgetLayout); + resetTutorialWidgetLayout->setMargin(0); + + QPushButton *resetTutorial = new QPushButton("Reset", generalSection); + Style::setStyle(resetTutorial, style::properties::button::basicButton); + connect(resetTutorial, &QPushButton::clicked, this, + [=, this]() { p->set("regmapplugin_start_tutorial", true); }); + + resetTutorialWidgetLayout->addWidget(new QLabel("Register map tutorial "), 6); + resetTutorialWidgetLayout->addWidget(resetTutorial, 1); + generalSection->contentLayout()->addWidget(resetTutorialWidget); + return true; }