mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-05-08 22:00:03 +02:00

- qt4->qt5 - in built qt5 6.1.5 because rhel7 is not upto date with qt5, removed findqwt.cmake - made a fix in qwt lib (qwt_plot_layout.h) to work with 5.15 and lower versions for qrect constr. - qt5 forms fixed, qt4 many hard coding forms switched to forms including qtabwidget, scrolls etc, fonts moved to forms - docking option enabled by default, removed option to disable docking feature from "Mode" - added qVersionResolve utility functions to handle compatibility before and after qt5.12 - qtplots (ian's code) takes in gain mode enable to set some settings within the class, with proper gain plot ticks - ensure gain plots have no zooming of z axis in 2d and y axis in 1d - removed placeholder text in qpalette in main window form as its not supportd until 5.12 (so using qt5.9 designer insted of qt5.15 to cope) - tab order Servers: - fixed some error messages that were empty for fail in funcs (mostly minor as if this error, major issues)
562 lines
19 KiB
C++
562 lines
19 KiB
C++
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||
#include "qDetectorMain.h"
|
||
#include "qDefs.h"
|
||
#include "qDrawPlot.h"
|
||
#include "qTabAdvanced.h"
|
||
#include "qTabDataOutput.h"
|
||
#include "qTabDebugging.h"
|
||
#include "qTabDeveloper.h"
|
||
#include "qTabMeasurement.h"
|
||
#include "qTabMessages.h"
|
||
#include "qTabPlot.h"
|
||
#include "qTabSettings.h"
|
||
|
||
#include "sls/ToString.h"
|
||
#include "sls/versionAPI.h"
|
||
|
||
#include <QFileDialog>
|
||
#include <QResizeEvent>
|
||
#include <QSizePolicy>
|
||
|
||
#include "sls/Version.h"
|
||
#include <getopt.h>
|
||
#include <string>
|
||
#include <sys/stat.h>
|
||
|
||
std::string getClientVersion() {
|
||
try {
|
||
sls::Version v(APILIB);
|
||
return v.concise();
|
||
} catch (...) {
|
||
return std::string("unknown");
|
||
}
|
||
}
|
||
|
||
int main(int argc, char **argv) {
|
||
|
||
// options
|
||
std::string fname;
|
||
bool isDeveloper = false;
|
||
int multiId = 0;
|
||
|
||
// parse command line for config
|
||
static struct option long_options[] = {
|
||
// These options set a flag.
|
||
//{"verbose", no_argument, &verbose_flag, 1},
|
||
// These options don’t set a flag. We distinguish them by their indices.
|
||
{"developer", no_argument, nullptr, 'd'},
|
||
{"config", required_argument, nullptr, 'f'},
|
||
{"id", required_argument, nullptr, 'i'},
|
||
{"version", no_argument, nullptr, 'v'},
|
||
{"help", no_argument, nullptr, 'h'},
|
||
{nullptr, 0, nullptr, 0}};
|
||
|
||
// getopt_long stores the option index here
|
||
optind = 1;
|
||
int option_index = 0;
|
||
int c = 0;
|
||
|
||
while (c != -1) {
|
||
c = getopt_long(argc, argv, "hvdf:i:", long_options, &option_index);
|
||
// Detect the end of the options
|
||
if (c == -1)
|
||
break;
|
||
switch (c) {
|
||
|
||
case 'f':
|
||
fname = optarg;
|
||
LOG(sls::logDEBUG)
|
||
<< long_options[option_index].name << " " << optarg;
|
||
break;
|
||
|
||
case 'd':
|
||
isDeveloper = true;
|
||
break;
|
||
|
||
case 'i':
|
||
multiId = atoi(optarg);
|
||
break;
|
||
|
||
case 'v':
|
||
LOG(sls::logINFO) << "SLS Detector GUI " << getClientVersion();
|
||
return 0;
|
||
|
||
case 'h':
|
||
default:
|
||
std::string help_message =
|
||
"\n" + std::string(argv[0]) + "\n" +
|
||
"Usage: " + std::string(argv[0]) + " [arguments]\n" +
|
||
"Possible arguments are:\n" +
|
||
"\t-d, --developer : Enables the developer tab\n" +
|
||
"\t-f, --config <fname> : Loads config from file\n" +
|
||
"\t-i, --id <i> : Sets the multi detector id to "
|
||
"i. Default: 0. Required \n" +
|
||
"\t only when more than one multi "
|
||
"detector object is needed.\n\n";
|
||
LOG(sls::logERROR) << help_message;
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
QApplication app(argc, argv);
|
||
try {
|
||
sls::qDetectorMain det(multiId, fname, isDeveloper);
|
||
det.show();
|
||
app.exec();
|
||
} catch (const std::exception &e) {
|
||
sls::qDefs::Message(sls::qDefs::CRITICAL,
|
||
std::string(e.what()) + "\nExiting Gui :'( ",
|
||
"main");
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
namespace sls {
|
||
|
||
qDetectorMain::qDetectorMain(int multiId, const std::string &fname,
|
||
bool isDevel)
|
||
: QMainWindow(nullptr), detType(slsDetectorDefs::GENERIC),
|
||
isDeveloper(isDevel) {
|
||
|
||
setupUi(this);
|
||
SetUpDetector(fname, multiId);
|
||
SetUpWidgetWindow();
|
||
}
|
||
|
||
qDetectorMain::~qDetectorMain() {
|
||
disconnect(tabs, SIGNAL(currentChanged(int)), this, SLOT(Refresh(int)));
|
||
}
|
||
|
||
void qDetectorMain::SetUpWidgetWindow() {
|
||
// plot setup
|
||
plot = new qDrawPlot(dockWidgetPlot, det.get());
|
||
LOG(logDEBUG) << "DockPlot ready";
|
||
dockWidgetPlot->setWidget(plot);
|
||
dockWidgetPlot->setFloating(false);
|
||
zoomToolTip = dockWidgetPlot->toolTip();
|
||
|
||
// creating all the other tab widgets
|
||
tabMeasurement = new qTabMeasurement(tMeasurement, det.get(), plot);
|
||
tabDataOutput = new qTabDataOutput(tDataOutput, det.get());
|
||
tabPlot = new qTabPlot(tPlot, det.get(), plot);
|
||
tabSettings = new qTabSettings(tSettings, det.get());
|
||
tabAdvanced = new qTabAdvanced(tAdvanced, det.get(), plot);
|
||
tabDebugging = new qTabDebugging(tDebugging, det.get());
|
||
tabDeveloper = new qTabDeveloper(tDeveloper, det.get());
|
||
|
||
scrollMeasurement->setWidget(tabMeasurement);
|
||
scrollDataOutput->setWidget(tabDataOutput);
|
||
scrollPlot->setWidget(tabPlot);
|
||
scrollSettings->setWidget(tabSettings);
|
||
scrollAdvanced->setWidget(tabAdvanced);
|
||
scrollDebugging->setWidget(tabDebugging);
|
||
scrollDeveloper->setWidget(tabDeveloper);
|
||
scrollTerminal->setWidget(tabMessages);
|
||
|
||
tabs->setCurrentIndex(MEASUREMENT);
|
||
defaultTabColor = tabs->tabBar()->tabTextColor(DATAOUTPUT);
|
||
// set current tab to blue
|
||
tabs->tabBar()->setTabTextColor(0, QColor(0, 0, 200, 255));
|
||
tabs->setTabEnabled(DEBUGGING, false);
|
||
tabs->setTabEnabled(ADVANCED, false);
|
||
tabs->setTabEnabled(DEVELOPER, isDeveloper);
|
||
actionLoadTrimbits->setVisible(false);
|
||
actionSaveTrimbits->setVisible(false);
|
||
LOG(logINFO) << "Debug Mode: 0, Expert Mode: 0, Developer Mode: "
|
||
<< isDeveloper;
|
||
|
||
Initialization();
|
||
}
|
||
|
||
void qDetectorMain::SetUpDetector(const std::string &config_file, int multiID) {
|
||
|
||
// instantiate detector and set window title
|
||
det = make_unique<Detector>(multiID);
|
||
|
||
// create messages tab to capture config file loading logs
|
||
tabMessages = new qTabMessages(tTerminal);
|
||
|
||
// loads the config file at startup
|
||
if (!config_file.empty())
|
||
LoadConfigFile(config_file);
|
||
|
||
// validate detector type (for GUI) and update menu
|
||
detType = det->getDetectorType().tsquash(
|
||
"Different detector type for all modules.");
|
||
actionLoadTrimbits->setEnabled(false);
|
||
actionSaveTrimbits->setEnabled(false);
|
||
switch (detType) {
|
||
case slsDetectorDefs::EIGER:
|
||
case slsDetectorDefs::MYTHEN3:
|
||
actionLoadTrimbits->setEnabled(true);
|
||
actionSaveTrimbits->setEnabled(true);
|
||
break;
|
||
case slsDetectorDefs::GOTTHARD:
|
||
case slsDetectorDefs::JUNGFRAU:
|
||
case slsDetectorDefs::MOENCH:
|
||
case slsDetectorDefs::GOTTHARD2:
|
||
break;
|
||
default:
|
||
std::ostringstream os;
|
||
os << det->getHostname() << " has "
|
||
<< ToString(det->getDetectorType().squash()) << " detector type ("
|
||
<< std::to_string(detType) << "). Exiting GUI.";
|
||
std::string errorMess = os.str();
|
||
throw RuntimeError(errorMess.c_str());
|
||
}
|
||
std::ostringstream os;
|
||
os << "SLS Detector GUI : " << ToString(det->getDetectorType().squash())
|
||
<< " - " << det->getHostname();
|
||
std::string title = os.str();
|
||
LOG(logINFO) << title;
|
||
setWindowTitle(QString(title.c_str()));
|
||
}
|
||
|
||
void qDetectorMain::Initialization() {
|
||
// Dockable Plot
|
||
connect(dockWidgetPlot, SIGNAL(topLevelChanged(bool)), this,
|
||
SLOT(ResizeMainWindow(bool)));
|
||
// tabs
|
||
connect(tabs, SIGNAL(currentChanged(int)), this,
|
||
SLOT(Refresh(int))); //( QWidget*)));
|
||
// Measurement tab
|
||
connect(tabMeasurement, SIGNAL(EnableTabsSignal(bool)), this,
|
||
SLOT(EnableTabs(bool)));
|
||
connect(tabMeasurement, SIGNAL(FileNameChangedSignal(QString)), plot,
|
||
SLOT(SetSaveFileName(QString)));
|
||
// Plot tab
|
||
connect(tabPlot, SIGNAL(DisableZoomSignal(bool)), this,
|
||
SLOT(SetZoomToolTip(bool)));
|
||
|
||
// Plotting
|
||
connect(plot, SIGNAL(AcquireFinishedSignal()), tabMeasurement,
|
||
SLOT(AcquireFinished()));
|
||
connect(plot, SIGNAL(AbortSignal(QString)), tabMeasurement,
|
||
SLOT(AbortAcquire(QString)));
|
||
|
||
// menubar
|
||
// Modes Menu
|
||
connect(menuModes, SIGNAL(triggered(QAction *)), this,
|
||
SLOT(EnableModes(QAction *)));
|
||
// Utilities Menu
|
||
connect(menuUtilities, SIGNAL(triggered(QAction *)), this,
|
||
SLOT(ExecuteUtilities(QAction *)));
|
||
// Help Menu
|
||
connect(menuHelp, SIGNAL(triggered(QAction *)), this,
|
||
SLOT(ExecuteHelp(QAction *)));
|
||
}
|
||
|
||
void qDetectorMain::LoadConfigFile(const std::string &config_file) {
|
||
|
||
LOG(logINFO) << "Loading config file at start up:" << config_file;
|
||
|
||
struct stat st_buf;
|
||
QString file = QString(config_file.c_str());
|
||
|
||
// path doesnt exist
|
||
if (stat(config_file.c_str(), &st_buf)) {
|
||
qDefs::Message(
|
||
qDefs::WARNING,
|
||
std::string("<nobr>Start up configuration failed to load. The "
|
||
"following file does not exist:</nobr><br><nobr>") +
|
||
config_file,
|
||
"qDetectorMain::LoadConfigFile");
|
||
LOG(logWARNING) << "Config file does not exist";
|
||
}
|
||
// not a file
|
||
else if (!S_ISREG(st_buf.st_mode)) {
|
||
qDefs::Message(
|
||
qDefs::WARNING,
|
||
std::string(
|
||
"<nobr>Start up configuration failed to load. The following "
|
||
"file is not a recognized file format:</nobr><br><nobr>") +
|
||
config_file,
|
||
"qDetectorMain::LoadConfigFile");
|
||
LOG(logWARNING) << "File not recognized";
|
||
} else {
|
||
try {
|
||
det->loadConfig(config_file);
|
||
}
|
||
CATCH_DISPLAY("Could not load config file.",
|
||
"qDetectorMain::LoadConfigFile")
|
||
}
|
||
}
|
||
|
||
void qDetectorMain::EnableModes(QAction *action) {
|
||
bool enable;
|
||
|
||
// Set DebugMode
|
||
if (action == actionDebug) {
|
||
enable = actionDebug->isChecked();
|
||
tabs->setTabEnabled(DEBUGGING, enable);
|
||
LOG(logINFO) << "Debug Mode: " << qDefs::stringEnable(enable);
|
||
|
||
}
|
||
|
||
// Set ExpertMode(comes here only if its a digital detector)
|
||
else if (action == actionExpert) {
|
||
enable = actionExpert->isChecked();
|
||
|
||
tabs->setTabEnabled(ADVANCED, enable);
|
||
bool visible = enable && (detType == slsDetectorDefs::EIGER ||
|
||
detType == slsDetectorDefs::MYTHEN3);
|
||
actionLoadTrimbits->setVisible(visible);
|
||
actionSaveTrimbits->setVisible(visible);
|
||
tabSettings->SetExportMode(enable);
|
||
LOG(logINFO) << "Expert Mode: " << qDefs::stringEnable(enable);
|
||
} else {
|
||
LOG(logERROR) << "Unknown action";
|
||
}
|
||
}
|
||
|
||
void qDetectorMain::ExecuteUtilities(QAction *action) {
|
||
bool refreshTabs = false;
|
||
try {
|
||
|
||
if (action == actionLoadConfiguration) {
|
||
LOG(logDEBUG) << "Loading Configuration";
|
||
QString fName = QString(det->getFilePath().squash("/tmp/").c_str());
|
||
fName = QFileDialog::getOpenFileName(
|
||
this, tr("Load Detector Configuration"), fName,
|
||
tr("Configuration files (*.config);;All Files(*)"));
|
||
// Gets called when cancelled as well
|
||
if (!fName.isEmpty()) {
|
||
refreshTabs = true;
|
||
det->loadConfig(std::string(fName.toLatin1().constData()));
|
||
qDefs::Message(qDefs::INFORMATION,
|
||
"The Configuration Parameters have been "
|
||
"configured successfully.",
|
||
"qDetectorMain::ExecuteUtilities");
|
||
LOG(logINFO) << "Configuration Parameters loaded successfully";
|
||
}
|
||
}
|
||
|
||
else if (action == actionLoadParameters) {
|
||
LOG(logDEBUG) << "Loading Parameters";
|
||
QString fName = QString(det->getFilePath().squash("/tmp/").c_str());
|
||
fName = QFileDialog::getOpenFileName(
|
||
this, tr("Load Measurement Setup"), fName,
|
||
tr("Parameter files (*.det);;All Files(*)"));
|
||
// Gets called when cancelled as well
|
||
if (!fName.isEmpty()) {
|
||
refreshTabs = true;
|
||
det->loadParameters(std::string(fName.toLatin1().constData()));
|
||
qDefs::Message(qDefs::INFORMATION,
|
||
"The Detector Parameters have been "
|
||
"configured successfully.",
|
||
"qDetectorMain::ExecuteUtilities");
|
||
LOG(logINFO) << "Parameters loaded successfully";
|
||
}
|
||
}
|
||
|
||
else if (action == actionLoadTrimbits) {
|
||
QString fName =
|
||
QString((det->getSettingsPath().squash("/tmp/")).c_str());
|
||
LOG(logDEBUG) << "Loading Trimbits";
|
||
// so that even nonexisting files can be selected
|
||
QFileDialog *fileDialog = new QFileDialog(
|
||
this, tr("Load Detector Trimbits"), fName,
|
||
tr("Trimbit files (*.trim noise.sn*);;All Files(*)"));
|
||
fileDialog->setFileMode(QFileDialog::AnyFile);
|
||
if (fileDialog->exec() == QDialog::Accepted) {
|
||
fName = fileDialog->selectedFiles()[0];
|
||
det->loadTrimbits(std::string(fName.toLatin1().constData()));
|
||
qDefs::Message(qDefs::INFORMATION,
|
||
"The Trimbits have been loaded successfully.",
|
||
"qDetectorMain::ExecuteUtilities");
|
||
LOG(logINFO) << "Trimbits loaded successfully";
|
||
}
|
||
}
|
||
|
||
else if (action == actionSaveTrimbits) {
|
||
QString fPath =
|
||
QString((det->getSettingsPath().squash("/tmp/")).c_str());
|
||
LOG(logDEBUG) << "Saving Trimbits";
|
||
QString fName = QFileDialog::getSaveFileName(
|
||
this, tr("Save Detector Trimbits"), fPath,
|
||
tr("Trimbit files (*.trim noise.sn*);;All Files(*)"));
|
||
if (!fName.isEmpty()) {
|
||
det->saveTrimbits(std::string(fName.toLatin1().constData()));
|
||
qDefs::Message(qDefs::INFORMATION,
|
||
"The Trimbits have been saved successfully.",
|
||
"qDetectorMain::ExecuteUtilities");
|
||
LOG(logINFO) << "Trimbits saved successfully";
|
||
}
|
||
}
|
||
}
|
||
CATCH_DISPLAY("Could not execute utilities.",
|
||
"qDetectorMain::ExecuteUtilities")
|
||
|
||
Refresh(tabs->currentIndex());
|
||
if (refreshTabs) {
|
||
tabMeasurement->Refresh();
|
||
tabSettings->Refresh();
|
||
tabDataOutput->Refresh();
|
||
if (tabAdvanced->isEnabled())
|
||
tabAdvanced->Refresh();
|
||
if (tabDebugging->isEnabled())
|
||
tabDebugging->Refresh();
|
||
if (tabDeveloper->isEnabled())
|
||
tabDeveloper->Refresh();
|
||
tabPlot->Refresh();
|
||
}
|
||
}
|
||
|
||
void qDetectorMain::ExecuteHelp(QAction *action) {
|
||
if (action == actionAbout) {
|
||
LOG(logINFO) << "About Common GUI for Jungfrau, Eiger, Mythen3, "
|
||
"Gotthard, Gotthard2 and Moench detectors";
|
||
|
||
std::string clientVersion = "unknown";
|
||
try {
|
||
clientVersion = det->getClientVersion();
|
||
}
|
||
CATCH_DISPLAY("Could not get client version.",
|
||
"qDetectorMain::ExecuteHelp")
|
||
|
||
qDefs::Message(
|
||
qDefs::INFORMATION,
|
||
"<p style=\"font-family:verdana;\">"
|
||
|
||
"<b>SLS Detector Client version: " +
|
||
clientVersion +
|
||
"</b><br><br>"
|
||
|
||
"Common GUI to control the SLS Detectors: "
|
||
"Jungfrau, Eiger, Mythen3, Gotthard, Gotthard2 and "
|
||
"Moench.<br><br>"
|
||
|
||
"It can be operated in parallel with the command "
|
||
"line interface: sls_detector_put, sls_detector_get, "
|
||
"sls_detector_acquire and sls_detector_help.<br><br>"
|
||
|
||
"Support:<br>"
|
||
"Dhanya.Thattil@psi.ch <br>"
|
||
"Erik.Froejdh@psi.ch.<br><br><br>"
|
||
|
||
"<br>slsDetectorGui Copyright (C) 2021 Contributors to SLS "
|
||
"Detector Package<br><br>"
|
||
|
||
"See COPYING in root folder for Licensing details:<br>"
|
||
"LGPL-3.0-or-other"
|
||
|
||
"<\\p>",
|
||
"qDetectorMain::ExecuteHelp");
|
||
}
|
||
}
|
||
|
||
void qDetectorMain::Refresh(int index) {
|
||
LOG(logDEBUG) << "Refresh Main Tab";
|
||
|
||
if (!tabs->isTabEnabled(index))
|
||
tabs->setCurrentIndex((index++) < (tabs->count() - 1) ? index
|
||
: MEASUREMENT);
|
||
else {
|
||
switch (tabs->currentIndex()) {
|
||
case MEASUREMENT:
|
||
tabMeasurement->Refresh();
|
||
break;
|
||
case SETTINGS:
|
||
tabSettings->Refresh();
|
||
break;
|
||
case DATAOUTPUT:
|
||
tabDataOutput->Refresh();
|
||
break;
|
||
case PLOT:
|
||
tabPlot->Refresh();
|
||
break;
|
||
case ADVANCED:
|
||
tabAdvanced->Refresh();
|
||
break;
|
||
case DEBUGGING:
|
||
tabDebugging->Refresh();
|
||
break;
|
||
case DEVELOPER:
|
||
tabDeveloper->Refresh();
|
||
break;
|
||
case MESSAGES:
|
||
tabMessages->Refresh();
|
||
break;
|
||
}
|
||
}
|
||
for (int i = 0; i < NumberOfTabs; ++i)
|
||
tabs->tabBar()->setTabTextColor(i, defaultTabColor);
|
||
tabs->tabBar()->setTabTextColor(index, QColor(0, 0, 200, 255));
|
||
}
|
||
|
||
void qDetectorMain::ResizeMainWindow(bool b) {
|
||
LOG(logDEBUG1) << "Resizing Main Window: height:" << height();
|
||
if (b) {
|
||
setMaximumHeight(centralwidget->height() + menu->height());
|
||
LOG(logINFO) << "Plot undocked from main window";
|
||
} else {
|
||
setMaximumHeight(QWIDGETSIZE_MAX);
|
||
LOG(logINFO) << "Plot docked back to main window";
|
||
}
|
||
}
|
||
|
||
void qDetectorMain::resizeEvent(QResizeEvent *event) {
|
||
tabs->tabBar()->setFixedWidth(width());
|
||
event->accept();
|
||
}
|
||
|
||
void qDetectorMain::EnableTabs(bool enable) {
|
||
LOG(logDEBUG) << "qDetectorMain::EnableTabs";
|
||
|
||
// normal tabs
|
||
tabs->setTabEnabled(DATAOUTPUT, enable);
|
||
tabs->setTabEnabled(SETTINGS, enable);
|
||
tabs->setTabEnabled(MESSAGES, enable);
|
||
|
||
// actions check
|
||
actionLoadConfiguration->setEnabled(enable);
|
||
actionLoadParameters->setEnabled(enable);
|
||
actionDebug->setEnabled(enable);
|
||
actionExpert->setEnabled(enable);
|
||
|
||
// special tabs
|
||
tabs->setTabEnabled(DEBUGGING, enable && (actionDebug->isChecked()));
|
||
tabs->setTabEnabled(DEVELOPER, enable && isDeveloper);
|
||
// expert
|
||
bool expertTab = enable && (actionExpert->isChecked());
|
||
tabs->setTabEnabled(ADVANCED, expertTab);
|
||
actionLoadTrimbits->setVisible(expertTab &&
|
||
detType == slsDetectorDefs::EIGER);
|
||
actionSaveTrimbits->setVisible(expertTab &&
|
||
detType == slsDetectorDefs::EIGER);
|
||
|
||
// moved to here, so that its all in order, instead of signals and different
|
||
// threads
|
||
if (!enable) {
|
||
// tabMeasurement->Refresh(); too slow to refresh
|
||
tabSettings->Refresh();
|
||
tabDataOutput->Refresh();
|
||
if (tabAdvanced->isEnabled())
|
||
tabAdvanced->Refresh();
|
||
if (tabDebugging->isEnabled())
|
||
tabDebugging->Refresh();
|
||
if (tabDeveloper->isEnabled())
|
||
tabDeveloper->Refresh();
|
||
|
||
tabPlot->Refresh();
|
||
plot->StartAcquisition();
|
||
} else { // to enable scan box
|
||
tabPlot->Refresh();
|
||
// to start adc timer
|
||
if (tabDeveloper->isEnabled())
|
||
tabDeveloper->Refresh();
|
||
}
|
||
}
|
||
|
||
void qDetectorMain::SetZoomToolTip(bool disable) {
|
||
if (disable)
|
||
dockWidgetPlot->setToolTip(
|
||
"<span style=\" color:#00007f;\">To Enable mouse-controlled "
|
||
"zooming capabilities,\ndisable min and max for all axes.<span> ");
|
||
else
|
||
dockWidgetPlot->setToolTip(zoomToolTip);
|
||
}
|
||
|
||
} // namespace sls
|