/* Copyright (c) 2008-2019 Jan W. Krieger (, ) This software is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "jkqtplotter/jkqtpbaseplotter.h" #include "jkqtplotter/jkqtplotterstyle.h" #include "jkqtplotter/jkqtpbaseplotterstyle.h" #include "jkqtplottertools/jkqtptools.h" #include "jkqtplottertools/jkqtp_imexport.h" #include "jkqtplottergui/jkvanishqtoolbar.h" #include #ifndef JKQTPLOTTER_H #define JKQTPLOTTER_H /** \brief initialized Qt-ressources necessary for JKQTPlotter * \ingroup jkqtpplotterclasses_tools */ JKQTP_LIB_EXPORT void initJKQTPlotterResources(); /** \brief plotter widget for scientific plots (uses JKQTBasePlotter to do the actual drawing) * \ingroup jkqtpplotterclasses * * This class is a QWidget-wrapper around JKQTBasePlotter. It uses the tools from JKQTBasePlotter * to display scientific plots. This class mostly adds the Widget for the output and adds different * types of user interactions. * * Please have a look at the documentation of JKQTBasePlotter for details on the management of graphs * and the formating/styling of the plot and graphs! * * The rest of this documentation ins split into sections that each treat a special topic, as outlines below: * * \tableofcontents * * * \section JKQTPLOTTER_BASICUSAGE Basic Usage of JKQTPlotter * * JKQTPlotter is a plotter widget which wraps around a JKQTBasePlotter instanced that does the actual drawing. * A basic usage of JKQTPlotter looks like this: * * \code{.cpp} * // create a new JKQTPlotter instance * JKQTPlotter* plot = new JKQTPlotter(parentWidget); * * // fill two vectors with dtaa for a graph: * QVector X, Y; * fillDataVectors(X, Y); * * // make data available to the internal datastore of the plotter: * size_t columnX=plot->getDatastore()->addCopiedColumn(X, "x"); * size_t columnY=plot->getDatastore()->addCopiedColumn(Y, "y"); * * // create a graph/curve, which displays the data * JKQTPXYLineGraph* graph1=new JKQTPXYLineGraph(plot); * graph1->setXColumn(columnX); * graph1->setYColumn(columnY); * graph1->setTitle(QObject::tr("graph title")); * plot->addGraph(graph1); * * // autoscale the plot * plot->zoomToFit(); * // alternatively set the axis dimension by hand: * plot->setXY(-10,10,-10,10); * \endcode * * The result should look something like this: * * \image html jkqtplotter_simpletest1.png * * Starting from this basic example, you can observe several important principles: * # Data is stored in an (internal) instance of JKQTPDatastore, which is accessible through * JKQTPlotter::getDatastore(). * This datastore can either own its data (which is done here, as we copy the data into the store * by calling JKQTPDatastore::addCopiedColumn(), or it can merely reference to the data (then * data needs to be available as array of \c double values). * # Naming conventions: * - \b plot is the complete drawn image, including the axes, the graphs, the key and all other visual elements * - plot element any sub element of the plot, e.g. a single coordinate axis, the key, but also any graph/curve * - \b graph is a single curve/image/geometric element in the plot * - geometric element is a special graph that does not represent a curve based on data from the JKQTPDatastore, * but a single graphic element, like a rectangle/circle/line/..., some text, a single symbol * - \b key is the legend of the plot * - coordinate axis is each of the x- or y-axis (there might be addition axes, e.g. when showing a color-scale) * . * # Each graph is represented by a class derived from JKQTPPlotElement (in the example we instanciated a JKQTPXYLineGraph, * which shows data as a scatter of symbols that may (or may not) be connected by a line). * Creating the graph class does not yet add it to the plotter. To add it, call JKQTPlotter::addGraph(). Only * after this sep, the graph is displayed. You can modify the apperance of the graph (e.g. colors, * name in the key ...) by setting properties in the graph class instance. * # You can auto-zoom the axis ranges of the plot by calling JKQTPlotter::zoomToFit(), or set them * exlicitly by calling JKQTPlotter::setXY(). The user can later zoom in/out by the mouse (and other means). * You can limit this zoom range by setting an absolute axis range, calling e.g. JKQTPlotter::setAbsoluteXY(). * The the user cannot zoom farther out than the given range(s). * # If you want to style the plot itself, you need to set properties of the underlying JKQTBasePloter instance, which * is accessible through JKQTPlotter::getPlotter(). If you want to style the coordinate axes, you can acces their * representing objects by caling JKQTPlotter::getXAxis() or JKQTPlotter::getYAxis(). * . * * \see \ref JKQTPlotterSimpleTest and \see JKQTPlotterQtCreator * * \section JKQTPLOTTER_SYNCMULTIPLOT Synchronizing Several Plots * * Often a single plot is not sufficient, but several plots need to be aligned with respect to each other: * * \image html test_multiplot.png * * In the Qt Window this is achieved by placing several JKQTPlotter objects into a QGridLayout. * In order to support this alignment, also when exporting/printing a plot, and when the user interactions with the plot (e.g. zooming), * JKQTPlotter offers an API which allows to : *
    *
  • declare (grid-like) relations between plots for export/printing * \see setGridPrinting(), addGridPrintingPlotter(), clearGridPrintingPlotters(), setGridPrintingCurrentPos() and \ref JKQTBASEPLOTTER_SYNCMULTIPLOT_SYNC
  • *
  • synchronize axes/plots * \see synchronizeXToMaster(), synchronizeYToMaster(), resetMasterSynchronization() and \ref JKQTBASEPLOTTER_SYNCMULTIPLOT_GRIDPRINT
  • *
* * * \note This API adopts and extends the possibilities of JKQTBasePlotter. Please see the documentation there for details: *
    *
  • \ref JKQTBASEPLOTTER_SYNCMULTIPLOT *
      *
    • \ref JKQTBASEPLOTTER_SYNCMULTIPLOT_SYNC
    • *
    • \ref JKQTBASEPLOTTER_SYNCMULTIPLOT_GRIDPRINT
    • *
    *
* * * * \section JKQTPLOTTER_USERINTERACTION User-Interactions/GUI Features * * JKQTPlotter offers a lot of user-interaction features out of the box. These are detailed below. * * \subsection JKQTPLOTTER_CONTEXTMENU Context Menu of JKQTPlotter * * The class JKQTPlotter has a context menu that already offers a lot of functionality. * * \image html jkqtplotter_defaultcontextmenu.png * * \image html contextmenu_graphvisibility.gif * * It allows to: *
    *
  • copy or save the data from the internal JKQTPDatastore
  • *
  • copy or save the plot to an image file (PNG, PDF, ...), includes a softisticated export-preview dialog: * * \image html jkqtplotter_exportpreviewdialog.png *
  • *
  • print the plot (includes a softisticated print-preview dialog): * * \image html jkqtplotter_printpreview.png "Print Preview Dialog" * * \image html jkqtplotter_printpreview_relsize_mullinewidth_mulfonts.png "Print Preview Dialog with modified (relative) size, line-width and font-size" *
  • *
  • open a dialog with a table of the plot data: * * \image html jkqtplotter_datatabledialog.png "Data Table Dialog (with buttons to save or copy the data)" *
  • *
  • zoom into/out of the plot and determine an auto-zoom, which shows all of the plot data
  • *
  • switch the visibility of the different graphs in the plot
  • *
* * You can activate this menu, by setting \c setContextMenuMode(jkqtpcmmStandardContextMenu); and binding a mouse-action (typically the right-click) * to the context menu by calling \c deregisterMouseDragAction(Qt::RightButton,Qt::NoModifier) which deregisters any user actions from the rhs single * mouse click. In that case, the context menu is opened by default (see setContextMenuMode() to choose the mode of the context menu). * * * In addition JKQTPlotter provides several ways to customize this menu: * - You can add additional actions to the JKQTPlotter, by calling `JKQTPlotter::addAction()` (i.e. using the default Qt mechanism) * and/or by adding actions to the internal JKQTBasePlotter, using `JKQTBasePlotter::registerAdditionalAction()` * - You can modify the menu, when it is displayed, by connecting a slot to the signal `JKQTPlotter::contextMenuOPened(x,y,menu)`: * \code * connect(plot, SIGNAL(contextMenuOpened(double, double, QMenu*)), this, SLOT(contextMenuOpened(double, double, QMenu*))); * * // ... * * void TestUserInteraction::contextMenuOpened(double x, double y, QMenu *contextMenu) * { * contextMenu->addSeparator(); * QAction* act=contextMenu->addMenu(QString("contextMenuOpened(x=%1, y=%2)").arg(x).arg(y))->addAction("user-added action"); * connect(act, &QAction::triggered, [x,y]() { QMessageBox::warning(nullptr, tr("Plot Context Menu"), * tr("Context Menu was opened at x/y=%1/%2!").arg(x).arg(y), * QMessageBox::Ok, * QMessageBox::Ok); }); * labMouseAction->setText(QString("contextMenuOpened(x=%1, y=%2)").arg(x).arg(y)); * } * \endcode * . * * \subsection JKQTPLOTTER_SPECIALCONTEXTMENU Special (User-Defined) Context Menu of JKQTPlotter * * In addition to the standard context menu, JKQTPlotter can also be configures to display a special, user-defined context menu. * To do so, call `\c setContextMenuMode(jkqtpcmmSpecialContextMenu) and set your menu, by calling \c setSpecialContextMenu() * You can also combine the special menu and the standard menu, by calling \c setContextMenuMode(jkqtpcmmStandardAndSpecialContextMenu) . * * You can also use the signal contextMenuOpened() to modify the special context menu, but note that alterations to this menu are permanently * stored in the special menu object. See contextMenuOpened() for a detailed discussion and ways to circumvent this! * * * \subsection JKQTPLOTTER_TOOLBAR Toolbar of JKQTPlotter * * In addition to the context-menu, a JKQtPlotter also also provides a toolbar at its top that offers * most of the functionality of the context menu. Usually this toolbar is enabled (see toolbarEnabled) * and is in a mode where it is hidden, until the mouse moves over an area at the top of the plot (see toolbarAlwaysOn): * * \image html jkqtplotter_toolbar_hidden.png "Hidden Toolbar" * \image html jkqtplotter_toolbar_shown.png "Shown Toolbar" * * \image html jkqtvanishtoolbar.gif * * If toolbarAlwaysOn is set to \c true (setToolbarAlwaysOn() ), the toolbar is always displayed: * * \image html jkqtplotter_toolbar_alwayson.png * * \see toolbarEnabled, toolbarAlwaysOn, \ref JKQTPlotterUserInteraction * * * * \subsection JKQTPLOTTER_ACTIONS QActions from a JKQTPlotter * Often you want to allow the suer to operate a plot from a user-defined QToolBar or a QMenu/QMenuBar in your * application (e.g. provide zooming commands ...). there are generally two ways to achieve this: *
    *
  1. Simply connect home-brewn QAction instances to the slots provided by JKQTPlotter and JKQTBasePlotter. * This also allows you to connect different plot properties to edit widgets in your forms. * \code * // add a checkbox to show and hide the position display label in the plot * chkPositionDisplay=new QCheckBox(tr("show mouse cursor position"), this); * chkPositionDisplay->setChecked(plot->isMousePositionShown()); * connect(chkPositionDisplay, SIGNAL(toggled(bool)), plot, SLOT(setMousePositionShown(bool))); * \endcode *
  2. *
  3. For several functions (especially those also present in JKQTPlotter's context-emun, you can also find * readily available QAction instances. these are available from JKQTBasePlotter (e.g. by JKQTBasePlotter::getActionPrint() ...). * From JKQTPlotter you therefor have to use: getPlotter()->getActionPrint() * \code * // add some of the default QActions from the JKQTPlotter to the window menu * // Some of the are also available in the context menu and toolbar of the JKQTPlotter * // others are not * QMenu* menuPlot=menuBar()->addMenu("Plot-Menu"); * menuPlot->addAction(plot->getPlotter()->getActionPrint()); * QMenu* menuPlotS=menuPlot->addMenu("Save ..."); * menuPlotS->addAction(plot->getPlotter()->getActionSaveData()); * menuPlotS->addAction(plot->getPlotter()->getActionSavePDF()); // not available from JKQTPlotter by default * menuPlotS->addAction(plot->getPlotter()->getActionSavePlot()); * \endcode *
  4. *
* \see \ref JKQTPlotterUserInteraction * * * * \subsection JKQTPLOTTER_USERMOUSEINTERACTION Mouse-Interaction in JKQTPlotter * * This section summarizes all user-interaction functions in JKQTPlotter that somehow relate to the mouse. * These are: * - \ref JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEDRAG * - \ref JKQTPLOTTER_USERMOUSEINTERACTION_MOUSECLICK * - \ref JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEWHEEL * - \ref JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEMOVE * . * * \note Zooming and Paning interactions apply to both axes when they are performed with the mouse * inside the plot. They are limited to one of the two axes, when the mouse hovers over that axis * (e.g. when you zoom by mouse-wheel while the mouse pointer is below the plot, over the x-axis, * only the x-axis is affected by the operation). * * \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEDRAG Actions When Dragging the Mouse * JKQTPlotter offers several methods that allow to customize, how it reacts to mouse actions: * - registerMouseDragAction() tells JKQTPlotter to perform a certain action (selected from JKQTPlotter::MouseActionMode) * when a specified mouse button is pushed while a specified (or no) keyborad modifiers (e.g. CTRL,ALT,SHIFT...) is pressed. * By default JKQTPlotter calls these two registers in its constructors: * \code * registerMouseDragAction(Qt::LeftButton, Qt::NoModifier, JKQTPlotter::MouseActionMode::jkqtpmdaZoomByRectangle); * registerMouseDragAction(Qt::LeftButton, Qt::ControlModifier, JKQTPlotter::MouseActionMode::jkqtpmdaPanPlotOnMove); * \endcode * Therefore by default you can draw a zoom rectangle with the left mouse button without modifiers * and you can pan/drag the plot with the left mouse-button while keeping CTRL pressed. * - deregisterMouseDragAction() deletes a previously defined user-interaction * - clearAllRegisteredMouseDragActions() deletes all previously specified user-actions * . * * Pressing the \c ESC key will stop the current JKQTPlotter::MouseActionMode. * * If e.g. the mode JKQTPlotter::MouseActionMode::jkqtpmdaZoomByRectangle is selected, while you drag the mouse, the * zoom rectangle is drawn over the plot. You can modify the style of drawing using these functions: * - setUserActionColor() sets the color of the drawn shape * - setUserActionCompositionMode() specifies how to combine the shape with the existing plot * . * * \image html zoomin_mouse_contextmenu.gif "Zooming with the mouse" * * \image html draw_rectangle.gif "Draw Rectangle User-Action" * * \image html drag_viewport.gif "Drag the Plot Viewport" * * * \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_MOUSECLICK Actions After (Double-)Clicks on the Mouse Buttons * The right mouse button has a special role: If it is single-clicked and no JKQTPlotter::MouseActionMode is specified * for the vent, it opens the context menu, unless you call \c setContextMenuMode(jkqtpcmmNoContextMenu) . * You can also use setContextMenuMode() to specify which type of context menu is shown. See JKQTPContextMenuModes * for details on the available modes. * * For any mouse-click, one of the following signals is emitted: * - plotMouseClicked() for any single-click (during the pressDown-Event!) * - plotMouseDoubleClicked() for any double-click * . * * The reaction to double-clicks of the mouse buttons can be specified separately. The possible * actions are listed in JKQTPMouseDoubleClickActions. You can bind one of these actions * to a specific click with these functions: * - registerMouseDoubleClickAction() tells JKQTPlotter to perform a certain action (selected from JKQTPMouseDoubleClickActions) * when a specified mouse button is pushed while a specified (or no) keyborad modifiers (e.g. CTRL,ALT,SHIFT...) is pressed. * By default JKQTPlotter calls this in its constructors: * \code * registerMouseDoubleClickAction(Qt::LeftButton, Qt::NoModifier, JKQTPMouseDoubleClickActions::jkqtpdcaClickMovesViewport); * \endcode * Therefore by default you can pan the plot/move the viewport by double clicking a location * - deregisterMouseDoubleClickAction() deletes a previously defined user-interaction * - clearAllRegisteredMouseDoubleClickAction() deletes all previously specified user-actions * . * The button to react to is specified as a parameter. * * \image html contextmenu_graphvisibility.gif * * \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEWHEEL Actions When a Mouse Wheel Event Occurs * The actions to be performed when the mouse hweel is operated are specified in JKQTPMouseWheelActions. * You can bind one of these actions to the mouse-wheel (under the condition that a specified Qt::KeyboardModifiers * is pressed) by using these functions: * - registerMouseWheelAction() tells JKQTPlotter to perform a certain action (selected from JKQTPMouseWheelActions) * when a specified mouse button is pushed while a specified (or no) keyborad modifiers (e.g. CTRL,ALT,SHIFT...) is pressed. * By default JKQTPlotter calls this in its constructors: * \code * registerMouseWheelAction(Qt::NoModifier, JKQTPMouseWheelActions::jkqtpmwaZoomByWheel); * \endcode * Therefore by default you can zoom into and out of the plot, using the mouse wheel. * - deregisterMouseWheelAction() deletes a previously defined user-interaction * - clearAllMouseWheelActions() deletes all previously specified user-actions * . * In addition the signal void plotMouseWheelOperated() is emitted whenever a mouse-wheel event occurs. * * * \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEMOVE Signaling When Mouse Moves * In addition the signal plotMouseMove() is called whenever the mouse moves over the plot. * Additional signals may be emitted, depending on the currently active JKQTPlotter::MouseActionMode. * * Also the current mouse position is shown above the graph by default (can be switched on or off * using setMousePositionShown() ). * * \image html mousepositiondisplay.gif * * * \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_FASTRESIZING Fast Resizing of a Plot Widget * When the user resized the widget, the graph would in principle have to be readrawn for every intermediate step. * As this is very timeconsuming, JKQTPlotter uses a different approach: Actual Redrawing is delayed a few 100ms * and this delay is reset whenever the widget size changes. Only after the last delay expires, the plot is redrawn. * In between an image of the last state of the plot is simple stretched/compressed to fill the new/current * widget size. In sum this looks like this: * * \image html jkqtplotter_fastresizing.gif * * * * * \section JKQTPLOTTER_USEQTCREATOR How to use JKQTPlotter in the Qt Form Designer * * As JKQTPlotter is a standard Qt widget, you can also use it in Qt UI-files designed with the Qt From Designer (e.g. from within QTCreator). * For this to work you have to use the Promote QWidget"-feature of the form designer. The steps you need to take are detailed below: *
    *
  1. add a new UI-file to your project and open it in the Form Editor. Then right-click the form and select `Promote Widgets ...`: * * \image html uidesigner_step1.png *
  2. *
  3. In the dialog that opens, you have to define `JKQTPlotter` as a promotion to `QWidget` as shown below. Finally store the settings by clicking `Add` and closing the dialog with `Close`. * * \image html uidesigner_step2.png *
  4. *
  5. Now you can add a `QWidget`from the side-bar to the form and then promote it to `JKQTPlotter`, by selecting and right-clicking the `QWidget` and then selecting `Promote To | JKQTPlotter`: * * \image html uidesigner_step3.png *
  6. *
* * \see \ref JKQTPlotterQtCreator
Also see \ref JKQTPlotterStyling for another example of using the Qt UI Designer with JKQTPlotter * */ class JKQTP_LIB_EXPORT JKQTPlotter: public QWidget { Q_OBJECT public: /** \brief class constructor * * If \a datastore_internal \c ==false, you can supply an external JKQTPDatastore with the parameter \a datast */ explicit JKQTPlotter(bool datastore_internal, QWidget* parent=nullptr, JKQTPDatastore* datast=nullptr); /** \brief class constructor for a JKQTPlotter using an external JKQTPDatastore \a dataset */ explicit JKQTPlotter(JKQTPDatastore* datast, QWidget* parent=nullptr); /** \brief class constructor * * generated a new internal JKQTPDatastore */ explicit JKQTPlotter(QWidget* parent=nullptr); /** \brief class destructor */ virtual ~JKQTPlotter(); /** reinitializes the toolbar, i.e. fills in QActions added to the QWidget since its creation/the last call to this function */ void updateToolbarActions(); /** \brief set the width/height of the icons in the toolbar in pt */ void setToolbarIconSize(int value); /** \brief get the width/height of the icons in the toolbar in pt */ int getToolbarIconSize(); /** \brief returns the class internally used for plotting */ JKQTBasePlotter* getPlotter() const { return plotter; } /** \brief returns the class internally used for plotting */ const JKQTBasePlotter* getConstplotter() const { return const_cast(plotter); } /** \brief returns whether the toolbar is enabled * * \copydetails JKQTPlotterStyle::toolbarEnabled * * \see setToolbarEnabled(), JKQTPlotterStyle::toolbarEnabled */ bool isToolbarEnabled() const; /** \brief returns whether the toolbar is always visible or only when the mouse moves to the upper left area * * \copydetails JKQTPlotterStyle::toolbarAlwaysOn * * \see setToolbarAlwaysOn(), JKQTPlotterStyle::toolbarAlwaysOn */ bool isToolbarAlwaysOn() const; /** \brief specifies whether to display the current position of the mouse in the top border of the plot (this may automatically extent the * top border, so the position fits in. The default widget font is used for the output. * * \copydetails JKQTPlotterStyle::displayMousePosition * * \see setMousePositionShown(), JKQTPlotterStyle::displayMousePosition, \ref JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEMOVE */ bool isMousePositionShown() const; /** \brief returns the fill color of the zoom rectangle \see \ref JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEDRAG */ QColor getUserActionColor() const; /** \brief returns the QPainter::CompositionMode used to draw the zoom rectangle etc. \see \ref JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEDRAG */ QPainter::CompositionMode getUserActionCompositionMode() const; /** \brief loads the plot properties from a QSettings object */ void loadSettings(const QSettings &settings, const QString& group=QString("plots/")); /** \brief saves the plot properties into a QSettings object. * * This method only saves those properties that differ from their default value. */ void saveSettings(QSettings& settings, const QString& group=QString("plots/")) const; /** \brief returns the minimum size of the widget */ QSize minimumSizeHint() const; /** \brief returns the size of the widget */ QSize sizeHint() const; /*! \brief synchronize the plot borders (and zooming) with a given plotter (master --> slave/this) This function allows two plotters to draw a graph with exactly the same height or width as in another graph. For example if you want to have two plotters which are positioned one above the other (and have the same widget widths, which could be guaranteed by a QLayout) you may want to make sure that their plotWidth s are always the same. In this case call \code plotter2->synchronizeToMaster(plotter1, sdXAxis, true) \endcode of the lower plotter \c plotter2 . Now whenever the size of plotter1 changes, also plotter2 is redrawn with the changed borders. \image html jkqtbaseplotter_synchronization.png "Different Synchronization Settings for synchronizeDirection=sdXAxis" \param master the plotter widget to synchronize to \param synchronizeDirection direction in which to synchronize \param synchronizeAxisLength do you want the axis length to be synchronized? \param synchronizeZoomingMasterToSlave if set, also zooming in the master leads to a modification of the linked axes in the slave \param synchronizeZoomingSlaveToMaster if set, also zooming in the slave leads to a modification of the linked axes in the master \see synchronizeXToMaster(), synchronizeYToMaster(), resetMasterSynchronization(), \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void synchronizeToMaster(JKQTPlotter* master, JKQTBasePlotter::SynchronizationDirection synchronizeDirection, bool synchronizeAxisLength=true, bool synchronizeZoomingMasterToSlave=true, bool synchronizeZoomingSlaveToMaster=true); /*! \brief synchronize the plot x-axis width (and x-zooming) with a given master plotter (master --> slave/this) \param master the plotter widget to synchronize to \param synchronizeAxisLength do you want the axis length to be synchronized? \param synchronizeZoomingMasterToSlave if set, also zooming in the master leads to a modification of the linked axes in the slave \param synchronizeZoomingSlaveToMaster if set, also zooming in the slave leads to a modification of the linked axes in the master \image html jkqtbaseplotter_synchronization.png "Different Synchronization Settings for synchronizeDirection=sdXAxis" \note This is a short-cut to synchronizeToMaster() with \c synchronizeDirection=csXAxis \see synchronizeToMaster(), synchronizeYToMaster(), resetMasterSynchronization(), \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void synchronizeXToMaster(JKQTPlotter* master, bool synchronizeAxisLength=true, bool synchronizeZoomingMasterToSlave=true, bool synchronizeZoomingSlaveToMaster=true); /*! \brief synchronize the plot y-axis height (and y-zooming) with a given master plotter (master --> slave/this) \param master the plotter widget to synchronize to \param synchronizeAxisLength do you want the axis length to be synchronized? \param synchronizeZoomingMasterToSlave if set, also zooming in the master leads to a modification of the linked axes in the slave \param synchronizeZoomingSlaveToMaster if set, also zooming in the slave leads to a modification of the linked axes in the master \note This function internally calls JKQTBasePlotter::synchronizeToMaster() \note This is a short-cut to synchronizeToMaster() with \c synchronizeDirection=csXAxis \see synchronizeToMaster(), synchronizeXToMaster(), resetMasterSynchronization(), \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void synchronizeYToMaster(JKQTPlotter* master, bool synchronizeAxisLength=true, bool synchronizeZoomingMasterToSlave=true, bool synchronizeZoomingSlaveToMaster=true); /** \brief switches any synchronization off, that has been created by synchronizeToMaster() * * \note This function internally calls JKQTBasePlotter::synchronizeToMaster() \see synchronizeToMaster(), synchronizeXToMaster(), resetMasterSynchronization(), \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void resetMasterSynchronization(JKQTBasePlotter::SynchronizationDirection synchronizeDirection=JKQTBasePlotter::sdXYAxes); /*! \brief enables grid-printing for this plot * * \note This function call forwards to JKQTBasePlotter::setGridPrinting() * \see setGridPrinting(), addGridPrintingPlotter(), clearGridPrintingPlotters(), setGridPrintingCurrentPos(), \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void setGridPrinting(bool enabled); /** \brief add a new plotter \a plotterOther for grid printing mode, at location \a x / \a y * * \note This function call forwards to JKQTBasePlotter::addGridPrintingPlotter() * \see setGridPrinting(), addGridPrintingPlotter(), clearGridPrintingPlotters(), setGridPrintingCurrentPos(), \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void addGridPrintingPlotter(size_t x, size_t y, JKQTPlotter* plotterOther) ; /** \brief clear all additional plotters for grid printing mode * * \note This function call forwards to JKQTBasePlotter::clearGridPrintingPlotters() * \see setGridPrinting(), addGridPrintingPlotter(), clearGridPrintingPlotters(), setGridPrintingCurrentPos(), \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void clearGridPrintingPlotters() ; /** \brief set the x-position of this JKQTPlotter in the grid-printing grid * * \note This function call forwards to JKQTBasePlotter::setGridPrintingCurrentX() * \see setGridPrinting(), addGridPrintingPlotter(), clearGridPrintingPlotters(), setGridPrintingCurrentPos(), setGridPrintingCurrentY(), \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void setGridPrintingCurrentX(size_t x); /** \brief set the y-position of this JKQTPlotter in the grid-printing grid * * \note This function call forwards to JKQTBasePlotter::setGridPrintingCurrentY() * \see setGridPrinting(), addGridPrintingPlotter(), clearGridPrintingPlotters(), setGridPrintingCurrentPos(), setGridPrintingCurrentX(), \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void setGridPrintingCurrentY(size_t y); /** \brief set the x- and y-positions of this JKQTPlotter in the grid-printing grid * * \note This function call forwards to JKQTBasePlotter::setGridPrintingCurrentPos() * \see setGridPrinting(), addGridPrintingPlotter(), clearGridPrintingPlotters(), setGridPrintingCurrentX(), setGridPrintingCurrentY() \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void setGridPrintingCurrentPos(size_t x, size_t y); /** \brief returns a pointer to the datastore used by this object */ inline JKQTPDatastore* getDatastore() { return plotter->getDatastore(); } /** \brief tells the plotter object to use the given external datastore. * * If the current datastore is internally managed, this method will free that object and use the supplied datastore * with external management. If the current datastore is already external, this method will simply replace it by the * new one. */ inline void useExternalDatastore(JKQTPDatastore* newStore) { plotter->useExternalDatastore(newStore); } /** \copydoc JKQTBasePlotter::useAsInternalDatastore() */ inline void useAsInternalDatastore(JKQTPDatastore* newStore) { plotter->useAsInternalDatastore(newStore); } /** \copydoc JKQTBasePlotter::useInternalDatastore() */ inline void useInternalDatastore() { plotter->useInternalDatastore(); } /** \copydoc JKQTBasePlotter::forceInternalDatastore() */ inline void forceInternalDatastore() { plotter->forceInternalDatastore(); } /** \copydoc JKQTBasePlotter::setEmittingSignalsEnabled() */ inline void setEmittingSignalsEnabled(bool sig) { plotter->setEmittingSignalsEnabled(sig); } /** \copydoc JKQTBasePlotter::isEmittingSignalsEnabled() */ inline bool isEmittingSignalsEnabled() { return plotter->isEmittingSignalsEnabled(); } /** \brief returns, whether automatic redrawing the plot is currently activated (e.g. you can deactivate this with setPlotUpdateEnabled() while performing major updates on the plot) * * \see setPlotUpdateEnabled() */ bool isPlotUpdateEnabled() const; /** \brief sets whether automatic redrawing the plot is currently activated (e.g. you can sett his to \c false while performing major updates on the plot) * * \see isPlotUpdateEnabled() */ void setPlotUpdateEnabled(bool enable); /** \brief registeres a certain mouse drag action \a action to be executed when a mouse drag operation is * initialized with the given \a button and \a modifier */ void registerMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifiers modifier, JKQTPMouseDragActions action); /** \brief deregisteres the mouse drag action to be executed when a mouse drag operation is * initialized with the given \a button and \a modifier */ void deregisterMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifiers modifier); /** \brief clear all registeres mouse drag actions */ void clearAllRegisteredMouseDragActions(); /** \brief registeres a certain mouse action \a action to be executed when a mouse double-click occurs * with the given \a button and \a modifier */ void registerMouseDoubleClickAction(Qt::MouseButton button, Qt::KeyboardModifiers modifier, JKQTPMouseDoubleClickActions action); /** \brief deregisteres the mouse action \a action to be executed when a mouse double-click occurs * with the given \a button and \a modifier */ void deregisterMouseDoubleClickAction(Qt::MouseButton button, Qt::KeyboardModifiers modifier); /** \brief clear all registered mouse double-click actions */ void clearAllRegisteredMouseDoubleClickActions(); /** \brief specifies the action to perform on a mouse wheel event when a given modifier is pressed \see deregisterMouseWheelAction(), clearAllMouseWheelActions(), \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void registerMouseWheelAction(Qt::KeyboardModifiers modifier, JKQTPMouseWheelActions action); /** \brief deletes all mouse-wheel actions registered for a given \a modifier \see registerMouseWheelAction(), clearAllMouseWheelActions(), \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void deregisterMouseWheelAction(Qt::KeyboardModifiers modifier); /** \brief deletes all mouse-wheel actions \see registerMouseWheelAction(), deregisterMouseWheelAction(), \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void clearAllMouseWheelActions(); /*! \brief returns the currently set special context menu object * * \see \ref JKQTPLOTTER_SPECIALCONTEXTMENU, setSpecialContextMenu(), menuSpecialContextMenu, contextMenuOpened(), \ref JKQTPlotterUserInteraction */ QMenu *getSpecialContextMenu() const; /*! \brief sets a QMenu object to be used as special context menu * * \see \ref JKQTPLOTTER_SPECIALCONTEXTMENU, getSpecialContextMenu(), menuSpecialContextMenu, contextMenuOpened() */ void setSpecialContextMenu(QMenu* menu); /** \brief x-position of the mouse (in plot coordinates) when a user mouse-action was started (e.g. drawing a rectangle) * * \see \ref JKQTPLOTTER_CONTEXTMENU , getMouseContextY(), getMouseLastClickX(), getMouseLastClickY() */ double getMouseContextX() const; /** \brief y-position of the mouse (in plot coordinates) when a user mouse-action was started (e.g. drawing a rectangle) * * \see \ref JKQTPLOTTER_CONTEXTMENU , getMouseContextX(), getMouseLastClickX(), getMouseLastClickY() */ double getMouseContextY() const; /** \brief x-position of the last mouse-click (in screen pixels) * * \see getMouseLastClickY(), getMouseContextX(), getMouseContextY() */ int getMouseLastClickX() const; /** \brief y-position of the last mouse-click (in screen pixels) * * \see getMouseLastClickX(), getMouseContextX(), getMouseContextY() */ int getMouseLastClickY() const; /** \brief returns the coordinate axis object for the x-axis \see JKQTBasePlotter::getXAxis() */ inline JKQTPHorizontalAxis* getXAxis() { return plotter->getXAxis(); } /** \brief returns the coordinate axis object for the y-axis \see JKQTBasePlotter::getYAxis() */ inline JKQTPVerticalAxis* getYAxis() { return plotter->getYAxis(); } /** \brief returns the coordinate axis object for the x-axis as a const pointer \see JKQTBasePlotter::getXAxis() */ inline const JKQTPHorizontalAxis* getXAxis() const { return plotter->getXAxis(); } /** \brief returns the coordinate axis object for the y-axis as a const pointer \see JKQTBasePlotter::getYAxis() */ inline const JKQTPVerticalAxis* getYAxis() const { return plotter->getYAxis(); } /** \brief returns the \a i -th graph (of type JKQTPPlotElement) in this plotter instance \see JKQTBasePlotter::getGraph() */ inline JKQTPPlotElement* getGraph(size_t i) { return plotter->getGraph(i); } /** \brief returns the number of graphs \see JKQTBasePlotter::getGraphCount() */ inline size_t getGraphCount() { return plotter->getGraphCount(); } /** \brief remove the i-th graph \see JKQTBasePlotter::deleteGraph() */ inline void deleteGraph(size_t i, bool deletegraph=true) { plotter->deleteGraph(i, deletegraph); } /** \brief returns \c true, if the given graph is present \see JKQTBasePlotter::containsGraph() */ inline bool containsGraph(JKQTPPlotElement* gr) { return plotter->containsGraph(gr); } /** \brief remove the given graph, if it is contained \see JKQTBasePlotter::deleteGraph() */ inline void deleteGraph(JKQTPPlotElement* gr, bool deletegraph=true) { plotter->deleteGraph(gr, deletegraph); } /** \brief remove all plots * * \param deleteGraphs if set \c true (default) the graph objects will also be deleted * * \see JKQTBasePlotter::clearGraphs() */ inline void clearGraphs(bool deleteGraphs=true) { plotter->clearGraphs(deleteGraphs); } /** \brief add a new graph, returns it's position in the graphs list * * \param gr graph object (of type JKQTPPlotElement) to be added. \b Note: The JKQTPlotter takes ownership of graph \a gr . * \return ID of the added graph object \a gr in the internal list of graphs * * \see JKQTBasePlotter::addGraph() */ inline size_t addGraph(JKQTPPlotElement* gr) { return plotter->addGraph(gr); } /** \brief move the given graph to the top, or add it, if it is not yet contained * * \param gr graph object (of type JKQTPPlotElement) to be moved (needs to be containing to the JKQTPlotter already!) * \return ID of the added graph object \a gr in the internal list of graphs * * \see JKQTBasePlotter::moveGraphTop() */ inline size_t moveGraphTop(JKQTPPlotElement* gr) { return plotter->moveGraphTop(gr); } /** \brief move the given graph to the top, or add it, if it is not yet contained * * \param gr graph object (of type JKQTPPlotElement) to be moved (needs to be containing to the JKQTPlotter already!) * \return ID of the added graph object \a gr in the internal list of graphs * * \see JKQTBasePlotter::moveGraphBottom() */ inline size_t moveGraphBottom(JKQTPPlotElement* gr) { return plotter->moveGraphBottom(gr); } /** \brief add a new graphs from a QVector, QList, std::vector ... or any standard-iterateable container with JKQTPPlotElement*-items * * \tparam TJKQTPGraphContainer a container type with default C++-sytle iterator interface * (i.e. methods \c begin() and \c end() and an iterator, which may be * moved to the next element with the operator \c ++ . * \param gr Container of type TJKQTPGraphContainer, which contains the graphs \b Note: The JKQTPlotter takes ownership of graphs in \a gr . * \param[out] graphIDsOut optional output parameter, the vector will contain the IDs of each graph added to theis plot * * \see JKQTBasePlotter::addGraphs() */ template inline void addGraphs(const TJKQTPGraphContainer& gr, QVector* graphIDsOut=nullptr) { plotter->addGraphs(gr, graphIDsOut); } /** \brief returns the current x-axis min \see JKQTBasePlotter::getYAxis() */ inline double getXMin() const {return plotter->getXMin(); } /** \brief returns the current x-axis max \see JKQTBasePlotter::getYAxis() */ inline double getXMax() const {return plotter->getXMax(); } /** \brief returns the current y-axis min \see JKQTBasePlotter::getYAxis() */ inline double getYMin() const {return plotter->getYMin(); } /** \brief returns the current y-axis max \see JKQTBasePlotter::getYAxis() */ inline double getYMax() const {return plotter->getYMax(); } /** \brief returns the absolute x-axis min */ inline double getAbsoluteXMin() const {return plotter->getAbsoluteXMin(); } /** \brief returns the absolute x-axis max */ inline double getAbsoluteXMax() const {return plotter->getAbsoluteXMax(); } /** \brief returns the absolute y-axis min */ inline double getAbsoluteYMin() const {return plotter->getAbsoluteYMin(); } /** \brief returns the absolute y-axis max */ inline double getAbsoluteYMax() const {return plotter->getAbsoluteYMax(); } /** \brief returns the current magnification factor */ inline double getMagnification() const { return magnification; } /** \brief gets the next unused style id, i.e. the smalles number >=0 which is not contained in usedStyles */ inline int getNextStyle() { return getPlotter()->getNextStyle(); } /** \brief returns a QPen object for the i-th plot style */ inline JKQTBasePlotter::JKQTPPen getPlotStyle(int i) const { return getConstplotter()->getPlotStyle(i); } /** \brief font size for key labels [in points] */ inline double getKeyFontSize() const { return getConstplotter()->getKeyFontSize(); } /** \brief returns the currently set mode for the context menu \see JKQTPContextMenuModes, \ref JKQTPLOTTER_CONTEXTMENU , \ref JKQTPLOTTER_SPECIALCONTEXTMENU , \ref JKQTPLOTTER_USERMOUSEINTERACTION */ JKQTPContextMenuModes getContextMenuMode() const; /** \brief current style properties for this JKQTPlotter * * \see JKQTPSetSystemDefaultStyle(), JKQTPSetSystemDefaultStyle(), \ref jkqtpplotter_styling */ const JKQTPlotterStyle& getCurrentPlotterStyle() const; /** \brief replace the current style properties for this JKQTBasePlotter * * \see JKQTPSetSystemDefaultStyle(), JKQTPSetSystemDefaultStyle(), getCurrentPlotterStyle(), \ref jkqtpplotter_styling */ void setCurrentPlotterStyle(const JKQTPlotterStyle& style); /** \brief replace the current style properties for this JKQTBasePlotter * * \see JKQTPSetSystemDefaultStyle(), JKQTPSetSystemDefaultStyle(), getCurrentPlotterStyle(), \ref jkqtpplotter_styling */ void setCurrentPlotterStyle(const JKQTPlotterStyle& style, const JKQTBasePlotterStyle &baseStyle); /** \brief replace the current style properties for this JKQTBasePlotter with properties loaded from \a settings * * \param settings the QSettings object to read from * \param group group in \a settings to read from * \param alsoLoadBaseStyle if \c true, then also JKQTBasePlotter::loadCurrentPlotterStyle() of the internal JKQTBasePlotter is called * * \see JKQTPSetSystemDefaultStyle(), JKQTPSetSystemDefaultStyle(), getCurrentPlotterStyle(), \ref jkqtpplotter_styling */ void loadCurrentPlotterStyle(const QSettings& settings, const QString& group="plot/", bool alsoLoadBaseStyle=true); /** \brief store the current style properties for this JKQTBasePlotter with properties loaded from \a settings * * \param settings the QSettings object to write to * \param group group in \a settings to write to * \param alsoSaveBaseStyle if \c true, then also JKQTBasePlotter::saveCurrentPlotterStyle() of the internal JKQTBasePlotter is called * * \see JKQTPSetSystemDefaultStyle(), JKQTPSetSystemDefaultStyle(), getCurrentPlotterStyle(), \ref jkqtpplotter_styling */ void saveCurrentPlotterStyle(QSettings& settings, const QString& group="plot/", bool alsoSaveBaseStyle=true) const; public slots: /** \brief set the current plot magnification */ void setMagnification(double m); /** \brief sets x/ymin and x/ymax to the supplied values and replots the graph (zoom operation!) */ inline void zoom(double nxmin, double nxmax, double nymin, double nymax) { plotter->zoom(nxmin, nxmax, nymin, nymax); } /** \brief sets whether to plot grid lines or not * * \image html jkqtplotter_gridvisible.png "Grid visible" * \image html jkqtplotter_gridinvisible.png "Grid invisible" * */ inline void setGrid(bool val) { plotter->setGrid(val); } /** \brief save the current plot as an image file, with the current widget aspect ratio, if filename is empty a file selection dialog is displayed. * The image format is extracted from the file extension (jpeg, tiff, png, pdf, ...) */ inline void saveImage(const QString& filename=QString(""), bool displayPreview=true) { plotter->saveImage(filename, displayPreview); } /** \brief save the data used for the current plot. The file format is extracted from the file extension (csv, ...) * * The parameter \a format specifies the export format. if it is empty the format will be choosen according to the file extension, or * if \a filename is also empty the format will be choosen according to what is selected in the file selection dialog. * * If \a format is \c "slk" the output will be in SYLK format, if \a format is \c "csv" or \a "dat" the output will be comma separated values * and if \a format is \c "txt" the output will be tab separated values. */ inline void saveData(const QString& filename=QString(""), const QString& format=QString("")) { plotter->saveData(filename, format); } /** \brief print the current plot, if printer is \c nullptr a printer selection dialog is displayed */ inline void print(QPrinter* printer=nullptr) { plotter->print(printer); } /** \brief copy displayed data to cpliboard */ inline void copyData() { plotter->copyData(); } /** \brief copy displayed data to cpliboard in Matlab syntax */ inline void copyDataMatlab() { plotter->copyDataMatlab(); } /** \brief this method zooms the graph so that all plotted datapoints are visible. * * \param zoomX if set \c true (default) zooms the x axis * \param zoomY if set \c true (default) zooms the y axis * \param includeX0 if this is \c true zoomToFit() will ensure that \f$ x=0 \f$ is visible in the plot (only for non-logx plots, default: false) * \param includeY0 if this is \c true zoomToFit() will ensure that \f$ y=0 \f$ is visible in the plot (only for non-logy plots, default: false) * \param scaleX the plot will have a width of \f$ \mbox{Xscale}\cdot\Delta x \f$ where \f$ \Delta x \f$ is the actual x-axis data range * For logx plots we actually use this on the logarithmized data! (default: 1.05) * \param scaleY the plot will have a height of \f$ \mbox{Yscale}\cdot\Delta < \f$ where \f$ \Delta < \f$ is the actual <-axis data range * For log< plots we actually use this on the logarithmized data! (default: 1.05) * */ inline void zoomToFit(bool zoomX=true, bool zoomY=true, bool includeX0=false, bool includeY0=false, double scaleX=1.05, double scaleY=1.05) { plotter->zoomToFit(zoomX, zoomY, includeX0, includeY0, scaleX, scaleY); } /** \brief zooms into the graph (the same as turning the mouse wheel) by the given factor */ inline void zoomIn(double factor=2.0) { plotter->zoomIn(factor); } /** \brief zooms out of the graph (the same as turning the mouse wheel) by the given factor */ inline void zoomOut(double factor=2.0) { plotter->zoomOut(factor); } /** \brief update the plot and the overlays */ void redrawPlot(); /** \brief replot overlays only (use redrawPlot() to replot the plot and the overlays) * * You can use this function, if you only changed the overlays but not the graphs in this plotter. * Then only the overlas are redrawn and the old (saved) image of the graphs and the coordinate syste, * is used as a base. This is significantly faster than redrawing the whole plot. */ void redrawOverlays(); /** \brief returns whether the toolbar is enabled * * \copydetails JKQTPlotterStyle::toolbarEnabled * * \see isToolbarEnabled(), JKQTPlotterStyle::toolbarEnabled */ void setToolbarEnabled(bool __value); /** \brief returns whether the toolbar is always visible or only when the mouse moves to the upper left area * * \copydetails JKQTPlotterStyle::toolbarAlwaysOn * * \see isToolbarAlwaysOn(), JKQTPlotterStyle::toolbarAlwaysOn */ void setToolbarAlwaysOn(bool __value); /** \brief specifies whether to display the current position of the mouse in the top border of the plot (this may automatically extent the * top border, so the position fits in. The default widget font is used for the output. * * \copydetails JKQTPlotterStyle::displayMousePosition * * \see isMousePositionShown(), JKQTPlotterStyle::displayMousePosition, \ref JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEMOVE */ void setMousePositionShown(bool __value); /** \brief set the fill color of the zoom rectangle * * \see getUserActionColor(), JKQTPlotterStyle::userActionColor \ref JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEDRAG */ void setUserActionColor(const QColor & __value); /** \brief set the QPainter::CompositionMode used to draw the zoom rectangle etc. * * \see getUserActionCompositionMode(), JKQTPlotterStyle::userActionColor \ref JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEDRAG */ void setUserActionCompositionMode(const QPainter::CompositionMode & __value); /** \brief sets the mode if the standard context menu \see JKQTPContextMenuModes, \ref JKQTPLOTTER_CONTEXTMENU , \ref JKQTPLOTTER_SPECIALCONTEXTMENU , \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void setContextMenuMode(JKQTPContextMenuModes mode); /** \brief may be connected to zoomChangedLocally() of a different plot and synchronizes the local x-axis to the other x-axis \see \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void synchronizeXAxis(double newxmin, double newxmax, double newymin, double newymax, JKQTPlotter* sender); /** \brief may be connected to zoomChangedLocally() of a different plot and synchronizes the local y-axis to the other y-axis \see \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void synchronizeYAxis(double newxmin, double newxmax, double newymin, double newymax, JKQTPlotter* sender); /** \brief may be connected to zoomChangedLocally() of a different plot and synchronizes the local x- and y-axis to the other x- and y-axis \see \ref JKQTBASEPLOTTER_SYNCMULTIPLOT */ void synchronizeXYAxis(double newxmin, double newxmax, double newymin, double newymax, JKQTPlotter* sender); /** \brief popuplate the given toolbar \a toolbar with all actions shown in a toolbar from this class ... * * This function can be used to populate an external toolbar with actions for this JKQTPlotter. */ void populateToolbar(QToolBar* toolbar) const; /** \brief open the context menu at the mouse position of the last click \see \ref JKQTPLOTTER_CONTEXTMENU , \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void openContextMenu(); /** \brief open the context menu at the mouse position \a x and \a y \see \ref JKQTPLOTTER_CONTEXTMENU , \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void openContextMenu(int x, int y); /** \brief open the standard context menu at the mouse position of the last click \see \ref JKQTPLOTTER_CONTEXTMENU , \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void openStandardContextMenu(); /** \brief open the standard context menu at the mouse position \a x and \a y \see \ref JKQTPLOTTER_CONTEXTMENU , \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void openStandardContextMenu(int x, int y); /** \brief open the special context menu at the mouse position of the last click \see \ref JKQTPLOTTER_SPECIALCONTEXTMENU, \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void openSpecialContextMenu(); /** \brief open the special context menu at the mouse position \a x and \a y \see \ref JKQTPLOTTER_SPECIALCONTEXTMENU, \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void openSpecialContextMenu(int x, int y); /** \brief open the standard context menu with the special context menu integrated at the mouse position of the last click \see \ref JKQTPLOTTER_SPECIALCONTEXTMENU, \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void openStandardAndSpecialContextMenu(); /** \brief open the standard context menu with the special context menu integrated at the mouse position \a x and \a y \see \ref JKQTPLOTTER_CONTEXTMENU , \ref JKQTPLOTTER_SPECIALCONTEXTMENU, \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void openStandardAndSpecialContextMenu(int x, int y); /** \brief sets absolutely limiting x-range of the plot * * \param xminn absolute minimum of x-axis * \param xmaxx absolute maximum of x-axis * * \note if the aspect ratio of this does not fit into the widget, it is possible that you don't see the complete contents! * * \see setAbsoluteXY(), setAbsoluteY(), JKQTBasePlotter::setAbsoluteX() */ inline void setAbsoluteX(double xminn, double xmaxx) { plotter->setAbsoluteX(xminn, xmaxx); } /** \brief sets absolute minimum and maximum y-value to plot * * \param yminn absolute minimum of y-axis * \param ymaxx absolute maximum of y-axis * * \note if the aspect ratio of this does not fit into the widget, it is possible that you don't see the complete contents! * * \see setAbsoluteXY(), setAbsoluteX(), JKQTBasePlotter::setAbsoluteY() */ inline void setAbsoluteY(double yminn, double ymaxx) { plotter->setAbsoluteY(yminn, ymaxx); } /** \brief sets absolutely limiting x- and y-range of the plot * * The user (or programmer) cannot zoom to a viewport that is larger than the range given to this function. * * \param xminn absolute minimum of x-axis * \param xmaxx absolute maximum of x-axis * \param yminn absolute minimum of y-axis * \param ymaxx absolute maximum of y-axis * * \note if the aspect ratio of this does not fit into the widget, it is possible that you don't see the complete contents! * * \see setAbsoluteX(), setAbsoluteY(), zoomToFit(), JKQTBasePlotter::setAbsoluteXY() */ inline void setAbsoluteXY(double xminn, double xmaxx, double yminn, double ymaxx) { plotter->setAbsoluteXY(xminn, xmaxx, yminn, ymaxx); } /** \brief sets the x-range of the plot (minimum and maximum x-value on the x-axis) * * \param xminn absolute minimum of x-axis * \param xmaxx absolute maximum of x-axis * * \note You cannot expand the x-range outside the absolute x-range set e.g. by setAbsoluteX()! * Also the range will be limited to possible values (e.g. to positive values if you use * logarithmic axes). * * Uppon setting, this function emits the signal zoomChangedLocally(), if emitting signals * is activated at the moment (e.g. using JKQTBasePlotter::setEmittingSignalsEnabled() ). * * \see setY(), setXY(), zoomToFit(), setAbsoluteXY(), JKQTBasePlotter::setY() */ inline void setX(double xminn, double xmaxx) { plotter->setX(xminn, xmaxx); } /** \brief sets the y-range of the plot (minimum and maximum y-value on the y-axis) * * \param yminn absolute minimum of y-axis * \param ymaxx absolute maximum of y-axis * * \note You cannot expand the y-range outside the absolute y-range set e.g. by setAbsoluteY()! * Also the range will be limited to possible values (e.g. to positive values if you use * logarithmic axes). * * Uppon setting, this function emits the signal zoomChangedLocally(), if emitting signals * is activated at the moment (e.g. using JKQTBasePlotter::setEmittingSignalsEnabled() ). * * \see setX(), setXY(), zoomToFit(), setAbsoluteXY(), JKQTBasePlotter::setX() */ inline void setY(double yminn, double ymaxx) { plotter->setY(yminn, ymaxx); } /** \brief sets the x- and y-range of the plot (minimum and maximum values on the x-/y-axis) * * \param xminn absolute minimum of x-axis * \param xmaxx absolute maximum of x-axis * \param yminn absolute minimum of y-axis * \param ymaxx absolute maximum of y-axis * * \note You cannot expand the ranges outside the absolute ranges set e.g. by setAbsoluteXY()! * Also the range will be limited to possible values (e.g. to positive values if you use * logarithmic axes). * * Uppon setting, this function emits the signal zoomChangedLocally(), if emitting signals * is activated at the moment (e.g. using JKQTBasePlotter::setEmittingSignalsEnabled() ). * * \see setX(), setX(), zoomToFit(), setAbsoluteXY(), JKQTBasePlotter::setXY() */ inline void setXY(double xminn, double xmaxx, double yminn, double ymaxx) { plotter->setXY(xminn, xmaxx, yminn, ymaxx); } signals: /** \brief emitted whenever the mouse moves * * \param x x-position of the mouse (in plot coordinates) * \param y y-position of the mouse (in plot coordinates) */ void plotMouseMove(double x, double y); /** \brief emitted when a single-click event from the mouse occurs inside the plot * * \param x x-position of the mouse (in plot coordinates) * \param y y-position of the mouse (in plot coordinates) * \param modifiers key-modifiers when the click occured * \param button mouse-button that was used for the click */ void plotMouseClicked(double x, double y, Qt::KeyboardModifiers modifiers, Qt::MouseButton button); /** \brief emitted when a double-click event from the mouse occurs inside the plot * * \param x x-position of the mouse (in plot coordinates) * \param y y-position of the mouse (in plot coordinates) * \param modifiers key-modifiers when the click occured * \param button mouse-button that was used for the click */ void plotMouseDoubleClicked(double x, double y, Qt::KeyboardModifiers modifiers, Qt::MouseButton button); /** \brief emitted when a single-click event from the mouse occurs inside the plot * * \param x x-position of the mouse (in plot coordinates) * \param y y-position of the mouse (in plot coordinates) * \param modifiers key-modifiers when the click occured * \param deltaAngleX amount of rotation (in eighths of a degree) of the wheel in x-direction * \param deltaAngleY amount of rotation (in eighths of a degree) of the wheel in y-direction */ void plotMouseWheelOperated(double x, double y, Qt::KeyboardModifiers modifiers, int deltaAngleX, int deltaAngleY); /** \brief emitted when the mouse action jkqtpmdaZoomByRectangle and the drawing of the new zoom rectangle is finished (=mouse key released) * * \param mouseDragRectXStart start of the selected x-range (in plot coordinates) * \param mouseDragRectXEnd end of the selected x-range (in plot coordinates) * \param mouseDragRectYStart start of the selected x-range (in plot coordinates) * \param mouseDragRectYEnd end of the selected x-range (in plot coordinates) * \param modifiers key-modifiers when the click occured */ void plotNewZoomRectangle(double mouseDragRectXStart, double mouseDragRectXEnd, double mouseDragRectYStart, double mouseDragRectYEnd, Qt::KeyboardModifiers modifiers); /** \brief emitted when the plot scaling has been recalculated */ void plotScalingRecalculated(); /** \brief emitted before the plot scaling has been recalculated */ void beforePlotScalingRecalculate(); /** \brief emitted whenever a context menu is opened. You can modify the menu via the parameter \a contextMenu! * * \param x x-position of the context-menu (in plot coordinates) * \param y y-position of the context-menu (in plot coordinates) * \param contextMenu QMenu-object of the context menu. This object may be altered to display additional items ... Here is an example: * \code * contextMenu->addSeparator(); * QAction* act=contextMenu->addMenu(QString("contextMenuOpened(x=%1, y=%2)").arg(x).arg(y))->addAction("user-added action"); * connect(act, &QAction::triggered, [x,y]() { QMessageBox::warning(nullptr, tr("Plot Context Menu"), * tr("Context Menu was opened at x/y=%1/%2!").arg(x).arg(y), * QMessageBox::Ok, * QMessageBox::Ok); }); * \endcode * Please read the warning below!!! * * \warning A note of care: This signal can be used to alter the context menu. It behaves differently, depending on * whether you use the standard context menu, or the special context menu (setSpecialContextMenu()). If the * standard menu is opened, your alterations are valid until it is shown the next time (i.e. the internal * context menu object is deleted in between). If you show the special context menu only, your alterations * are permanently stored in the menu object. I.e. if you use the code example above and open the menu * several times, it will accumulate additional menu entries! * If you must modify the special menu, just access actions and do not add or delete any in a slot bound to * this signal! You can recognize the special menu with code like this: * \code * if (contextMenu == plot->getSpecialContextMenu()) { * //... * // do something with the special menu, do not add/remove entries * } else { * //... * // do something with the standard menu, you are free to do anything! * } * \endcode * * \see \ref JKQTPLOTTER_CONTEXTMENU , \ref JKQTPLOTTER_SPECIALCONTEXTMENU, \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void contextMenuOpened(double x, double y, QMenu* contextMenu); /** \brief signal: emitted whenever the user selects a new x-y zoom range (by mouse) * * \param newxmin start of the selected x-range (in plot coordinates) * \param newxmax end of the selected x-range (in plot coordinates) * \param newymin start of the selected x-range (in plot coordinates) * \param newymax end of the selected x-range (in plot coordinates) * \param sender JKQTPlotter sending this event * * This signal is designed to be connected to these slots: synchronizeXAxis(), synchronizeYAxis(), synchronizeXYAxis() */ void zoomChangedLocally(double newxmin, double newxmax, double newymin, double newymax, JKQTPlotter* sender); /** \brief emitted when the mouse action JKQTPlotter::ScribbleEvents and a click event from the mouse occurs inside the plot, * or the mouse moved while the left button is pressed down * * \param x x-position of the mouse (in plot coordinates) * \param y y-position of the mouse (in plot coordinates) * \param modifiers key-modifiers when the event was generated * \param first if \c true: this is the first event of a series that starts with pressing the mouse-button down, within the series, this is \c false * \param last if \c true: this is the last event of a series that ends when releasing the mouse-button, within the series, this is \c false */ void userScribbleClick(double x, double y, Qt::KeyboardModifiers modifiers, bool first, bool last); /** \brief emitted when the mouse action JKQTPlotter::RectangleEvents and the drawing of the new rectangle is finished (=mouse key released) * * \param x x-coordinate of the bottom left corner of the rectangle (in plot coordinates) * \param y y-coordinate of the bottom left corner of the rectangle (in plot coordinates) * \param width width of the rectangle (in plot coordinates) * \param height height of the rectangle (in plot coordinates) * \param modifiers key-modifiers when the rectangle was finished */ void userRectangleFinished(double x, double y, double width, double height, Qt::KeyboardModifiers modifiers); /** \brief emitted when the mouse action JKQTPlotter::LineEvents and the drawing of the new line is finished (=mouse key released) * * \param x1 x-coordinate of the start of the line (in plot coordinates) * \param y1 y-coordinate of the start of the line (in plot coordinates) * \param x2 x-coordinate of the end of the line (in plot coordinates) * \param y2 y-coordinate of the end of the line (in plot coordinates) * \param modifiers key-modifiers when the rectangle was finished */ void userLineFinished(double x1, double y1, double x2, double y2, Qt::KeyboardModifiers modifiers); /** \brief emitted when the mouse action JKQTPlotter::CircleEvents and the drawing of the new circle is finished (=mouse key released) * * \param x x-coordinate of the center of the circle (in plot coordinates) * \param y y-coordinate of the center of the circle (in plot coordinates) * \param radius radius of the circle (in plot coordinates) * \param modifiers key-modifiers when the rectangle was finished */ void userCircleFinished(double x, double y, double radius, Qt::KeyboardModifiers modifiers); /** \brief emitted when the mouse action JKQTPlotter::EllipseEvents and the drawing of the new ellipse is finished (=mouse key released) * * \param x x-coordinate of the center of the ellipse (in plot coordinates) * \param y y-coordinate of the center of the ellipse (in plot coordinates) * \param radiusX half-axis in x-direction of the ellipse (in plot coordinates) * \param radiusY half-axis in y-direction of the ellipse (in plot coordinates) * \param modifiers key-modifiers when the rectangle was finished */ void userEllipseFinished(double x, double y, double radiusX, double radiusY, Qt::KeyboardModifiers modifiers); protected: /** \brief ties a MouseActionMode to a mouse-button and a keyboard-modifier * \internal * \ingroup jkqtpplotterclasses_tools */ struct JKQTP_LIB_EXPORT MouseDragAction { /** \brief constructs an invalid object */ MouseDragAction(); MouseDragAction(Qt::MouseButton _mouseButton, Qt::KeyboardModifiers _modifier, JKQTPMouseDragActions _mode); JKQTPMouseDragActions mode; Qt::KeyboardModifiers modifier; Qt::MouseButton mouseButton; bool isValid() const; void clear(); private: bool valid; }; /** \brief the currently executed MouseDragAction */ MouseDragAction currentMouseDragAction; /** \brief searches JKQTPlotterStyle::registeredMouseActionModes for a matching action */ JKQTPMouseDragActionsHashMapIterator findMatchingMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifiers modifiers) const; /** \brief searches JKQTPlotterStyle::registeredMouseWheelActions for a matching action */ JKQTPMouseWheelActionsHashMapIterator findMatchingMouseWheelAction(Qt::KeyboardModifiers modifiers) const; /** \brief searches JKQTPlotterStyle::registeredMouseDoubleClickActions for a matching action */ JKQTPMouseDoubleClickActionsHashMapIterator findMatchingMouseDoubleClickAction(Qt::MouseButton button, Qt::KeyboardModifiers modifiers) const; /** \brief you may overwrite this method to modify the given context menu before it is displayed. * * The plotter will fill the menu with the default items and then call this method. The default implementation does NOTHING. * * \see \ref JKQTPLOTTER_CONTEXTMENU , \ref JKQTPLOTTER_USERMOUSEINTERACTION */ void modifyContextMenu(QMenu* menu); /** \brief indicates whether the plot is updated automatically at the moment * * \see setPlotUpdateEnabled(), isPlotUpdateEnabled() */ bool doDrawing; /** \brief JKQTBasePlotter used to plot */ JKQTBasePlotter* plotter; /** \brief modifies the settings of \a plotter to match those of this object */ void fixBasePlotterSettings(); /** \brief this is set \c true if we are drawing a zoom rectangle */ bool mouseDragingRectangle; /** \brief when draging the mouse this contains the x-coordinate the user clicked on (in plot coordinates) */ double mouseDragRectXStart; /** \brief when draging the mouse this contains the x-coordinate the user clicked on (in pixels) */ int mouseDragRectXStartPixel; /** \brief when draging the mouse this contains the x-coordinate the mouse is currently * pointing to (in pixels) */ int mouseDragRectXEndPixel; /** \brief when draging the mouse this contains the y-coordinate the mouse is currently * pointing to (in pixels) */ int mouseDragRectYEndPixel; /** \brief when draging the mouse this contains the x-coordinate the mouse is currently * pointing to */ double mouseDragRectXEnd; /** \brief when draging the mouse this contains the y-coordinate the user clicked on (in plot coordinates) */ double mouseDragRectYStart; /** \brief when zooming by moving the mouse this contains the y-coordinate the user clicked on (in pixels) */ int mouseDragRectYStartPixel; /** \brief when zooming by moving the mouse this contains the y-coordinate the mouse is currently * pointing to */ double mouseDragRectYEnd; /** \brief this stores the currently displayed plot */ QImage image; /** \brief this stores the currently displayed plot */ QImage imageNoOverlays; /** \brief this can be used when drawing a zoom rectangle to store an unchanged * copy of the currently displayed image. */ QImage oldImage; /** \brief use this QMenu instance instead of the standard context menu of this widget * \see \ref JKQTPLOTTER_SPECIALCONTEXTMENU */ QMenu* menuSpecialContextMenu; /** \brief toolbar class used for user input */ JKVanishQToolBar* toolbar; /** \brief paint the user action (rectangle, ellipse, ... */ void paintUserAction(); /** \brief event handler for a double click * * \see registerMouseDoubleClickAction(), deregisterMouseDoubleClickAction() */ void mouseDoubleClickEvent ( QMouseEvent * event ); /*! \brief react on key presses. These shortcuts are defined: - ESC stops current zooming/drawing action . */ void keyReleaseEvent(QKeyEvent* event); /** \brief event handler for a mouse move * * This implements two behaviours: * - if displayMousePosition is \c true , stores the current mouse position in mousePosX, mousePosY * - if necessary, contributes to user-actions started by mousePressEvent() * - emits plotMouseMove() if the mouse is inside the plot rectangle . * . * * \see mousePosX, mousePosY */ void mouseMoveEvent ( QMouseEvent * event ); /** \brief event handler for a mouse down event * * This event determines the action to be performed from registeredMouseActionModes * and then sets currentMouseDragAction accordingly and starts the mouse action. * * \see registerMouseDragAction(), deregisterMouseDragAction(), registeredJKQTPMouseDragActions */ void mousePressEvent ( QMouseEvent * event ); /** \brief event handler for a mouse release event * * this finishes the action, started by mousePressEvent() */ void mouseReleaseEvent ( QMouseEvent * event ); /** \brief event handler for a turn of the mouse wheel * * Executes the user action defined for the mouse wheel. * * \see registerMouseWheelAction(), deregisterMouseWheelAction(), registeredMouseWheelActions */ void wheelEvent(QWheelEvent * event); /** \brief this simply paints the stored image to the widget's surface */ void paintEvent(QPaintEvent *event); /** \brief resizes the internal representation (image) of the graphs */ void resizeEvent(QResizeEvent *event); /** \brief called, when the mouse leaves the widget, hides the toolbar (if visible) */ void leaveEvent ( QEvent * event ); /** \brief update settings of the toolbar */ void updateToolbar(); /** \brief the master plotter, this plotter is connected to in x-direction. */ QPointer masterPlotterX; /** \brief the master plotter, this plotter is connected to in y-direction. */ QPointer masterPlotterY; /** \brief calculate the y-axis shift of the plot, so there is space for the potentially displayed mouse position label */ int getPlotYOffset(); /** \brief x-position of the mouse during the last mouseMoveEvent() calls (in plot coordinates) */ double mousePosX; /** \brief y-position of the mouse during the last mouseMoveEvent() calls (in plot coordinates) */ double mousePosY; /** \brief magnification factor for the display of the plot */ double magnification; /** \brief current minimal size of the JKQTPlotter widget to properly display the plot */ QSize minSize; /** \brief the context menu object used by this JKQTPlotter * * \note this might be \c ==nullptr occasionally, therefore you need to check it, before accessing it! * * \see \ref JKQTPLOTTER_CONTEXTMENU , resetContextMenu(), initContextMenu(), contextMenuMode */ QMenu* contextMenu; /** \brief current mode for the default context menu (i.e. the right-click context menu) \see \ref JKQTPLOTTER_CONTEXTMENU */ JKQTPContextMenuModes contextMenuMode; /** \brief x-position of the mouse (in plot coordinates) when a user mouse-action was started (e.g. drawing a rectangle) */ double mouseContextX; /** \brief y-position of the mouse (in plot coordinates) when a user mouse-action was started (e.g. drawing a rectangle) */ double mouseContextY; /** \brief x-position of the last mouse-click (in screen pixels) */ int mouseLastClickX; /** \brief y-position of the last mouse-click (in screen pixels) */ int mouseLastClickY; QList contextSubMenus; /** \brief fills the member contextMenu with all default and additionally registered actions, also calls modifyContextMenu() * * \note This function calls resetContextMenu() internally! * * \see resetContextMenu(), contextMenuMode */ void initContextMenu(); /** \brief set the current mouse cursor shappe according to currentMouseDragAction */ void updateCursor(); /** \brief current style properties for this JKQTPlotter * * \see JKQTPSetSystemDefaultStyle(), JKQTPSetSystemDefaultStyle(), getCurrentPlotterStyle(), \ref jkqtpplotter_styling */ JKQTPlotterStyle plotterStyle; /** \brief timer used while the graph is resized to delay the redrawing with new size (in the meantime, an intermediate graphic is displayed) * \internal * \see delayedResizeEvent() * * \image html jkqtplotter_fastresizing.gif */ QTimer resizeTimer; /** \brief destroys the internal contextMenu and optionally creates a new one * * \param createnew if \c ==true, contextMenu is reinitialized with a (shiny) new QMenu, * otherwise it is set to \c nullptr after destroying the old menu. * * \see initContextMenu(), contextMenuMode */ void resetContextMenu(bool createnew=true); protected slots: /** \brief while the window is resized, the plot is only redrawn after a restartable delay, implemented by this function and resizeTimer * \internal * \see resizeTimer * * \image html jkqtplotter_fastresizing.gif */ void delayedResizeEvent(); /** \brief connected to plotScalingRecalculated() of the masterPlotter */ void masterPlotScalingRecalculated(); /** \brief called whenever the zoom changes in plotter */ void pzoomChangedLocally(double newxmin, double newxmax, double newymin, double newymax, JKQTBasePlotter* sender); /** \brief emitted before the plot scaling has been recalculated */ void intBeforePlotScalingRecalculate(); /** \brief called from a menu entry that encodes the graph ID */ void reactGraphVisible(bool visible); }; /** \brief qHash-variant used by JKQTPlotter * \internal * \ingroup jkqtpplotterclasses_tools */ template<> inline uint qHash(const QPair &key, uint seed ) noexcept(noexcept(qHash(key.first, seed)) && noexcept(qHash(key.second, seed))) { return static_cast(key.first)+static_cast(key.second); } /** \brief qHash-variant used by JKQTPlotter * \internal * \ingroup jkqtpplotterclasses_tools */ template<> inline uint qHash(const Qt::MouseButton &key, uint /*seed*/ ) noexcept(noexcept(qHash(key))) { return static_cast(key); } /** \brief qHash-variant used by JKQTPlotter * \internal * \ingroup jkqtpplotterclasses_tools */ template<> inline uint qHash(const Qt::KeyboardModifiers &key, uint /*seed*/ ) noexcept(noexcept(qHash(key))) { return static_cast(key); } #endif // JKQTPLOTTER_H