Logo Search packages:      
Sourcecode: kdeedu-kde4 version File versions  Download package

view.h

/*
* KmPlot - a math. function plotter for the KDE-Desktop
*
* Copyright (C) 1998, 1999, 2000, 2002  Klaus-Dieter Möller <kd.moeller@t-online.de>
*                     2006 David Saxton <david@bluehaze.org>
*               
* This file is part of the KDE Project.
* KmPlot is part of the KDE-EDU Project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*
*/

#ifndef View_included
#define View_included

#include "function.h"

// Qt includes
#include <qpixmap.h>
#include <QPointer>
#include <QMouseEvent>
#include <QResizeEvent>
#include <QKeyEvent>
#include <QEvent>
#include <ktoggleaction.h>

// KDE includes
#include <kdebug.h>
#include <kmenu.h>
#include <kpushbutton.h>

class KSliderWindow;
class MainDlg;
class QPaintEvent;
class QTextDocument;
class QTextEdit;
class QTime;

//@{
/// Some abbreviations for horizontal and vertical lines.
#define Line drawLine
#define Lineh(x1, y, x2) drawLine( QPointF(x1, y), QPointF(x2, y) )
#define Linev(x, y1, y2) drawLine( QPointF(x, y1), QPointF(x, y2) )
//@}


/**
 * For drawing the area of a (Cartesian) plot.
 */
00063  class IntegralDrawSettings
{
      public:
            IntegralDrawSettings();
            
            Plot plot;
            double dmin, dmax;
            /// Set to true when calculating the area under the graph
00071             bool draw;
};


/**
 * @short This class contains the plots. 
 *
 * It is the central widget of MainDlg.
 * @see MainDlg, MainDlg::view
 */
00081 class View : public QWidget
{
      Q_OBJECT
      public:
            /// Contructor
            View( bool readOnly, KMenu * functionPopup, QWidget* parent );
            virtual ~View();
      
            /// There is only one view.
00090             static View * self() { return m_self; }

            enum PlotMedium
            {
                  Screen,
                  Printer,
                  SVG,
                  Pixmap
            };
            /**
             * Draw the plot to \p dev, which is of the given \p medium.
             */
            void draw( QPaintDevice * dev, PlotMedium medium );
            
            enum ExtremaType { Minimum, Maximum };
            /**
            * Finding the minimum or maximum value.
            * \return The (x,y) coordinates of the extrema point.
            */
            QPointF findMinMaxValue( const Plot & plot, ExtremaType type, double dmin, double dmax );
            /**
            * Calculates the area between the given plot and the x-axis
            * (from x = \p dmin to x = \p dmax). The area will also be colored in.
            * \return the area.
            */
            double areaUnderGraph( IntegralDrawSettings settings );
            /**
             * \return if the calculation was cancelled by the user.
             */
            bool isCalculationStopped();
            /**
             * Used in posToString for requesting how the position string is to be
             * created.
             */
00124             enum PositionFormatting
            {
00126                   DecimalFormat,          ///< Plain text, using no scientific notation; just decimal expansion.
00127                   ScientificFormat  ///< Rich text possibly using scientific notation (mult x 10 ^ exp).
            };
            /**
             * @return a string for displaying the x or y coordinate in the statusbar.
             * \param x The number to convert to a string.
             * \param delta is the amount by which the value varies over one pixel in
             * the view. This is for choosing an appropriate number of decimals so that
             * moving the cursor shows a nice change in the string.
             * \param format How the number should be represented as a string.
             * \param color If using scientific mode, the color to format the text.
             */
            QString posToString( double x, double delta, PositionFormatting format, const QColor &color = Qt::black ) const;

            /// Slider controlling parameter values
00141             QPointer<KSliderWindow> m_sliderWindow;
            /// Menu actions for the sliders
00143             KToggleAction * m_menuSliderAction;
            void updateSliders(); /// show only needed sliders
            
            /**
             * Convert \p width_mm (millimeters) to the equivalent length when
             * drawing using \p painter.
             */
            double millimetersToPixels( double width_mm, QPaintDevice * device ) const;
            /**
             * The inverse of millimetersToPixels().
             */
            double pixelsToMillimeters( double width_pixels, QPaintDevice * device ) const;

            /** Current plot range endge. */
00157             double m_xmin;
            double m_xmax;
            /** Current plot range endge. */
00160             double m_ymin;
            double m_ymax;

            /// trace mode stuff, must be accessible in FunctionTools
00164             Plot m_currentPlot;
            /**
             * Convenience function for calculating the value of \p eq using the
             * given \p mode
             */
            double value( const Plot & plot, int eq, double x, bool updateFunction );
            /**
             * \return the real position of the function (similar to calling
             * value(), but returns both coordinates).
             */
            QPointF realValue( const Plot & plot, double x, bool updateFunction );
            /**
             * \return the (signed) curvature (in screen coordinates) of the plot
             * at \p x (and \p y for implicit functions).
             */
            double pixelCurvature( const Plot & plot, double x, double y = 0 );
            /**
             * \return the angle of the normal (in radians) of the plot when viewed
             * on the screen.
             */
            double pixelNormal( const Plot & plot, double x, double y = 0 );
            /**
             * Animates zooming from the current zoom rect to the one given (in real
             * coordinates)
             */
            void animateZoom( const QRectF & newCoords );

            ///Methods for the Print Dialog to set options for drawing
            void setPrintHeaderTable( bool status );
            void setPrintBackground( bool status );
            void setPrintWidth( double width );
            void setPrintHeight( double height );

      public slots:
            /// Called when the user want to cancel the drawing
            void stopDrawing();
            /// A slider window has been closed
            void slidersWindowClosed();
      
            /// Called when the graph should be updated
            void drawPlot();
            ///Slots for the three first items in popup menu
            void hideCurrentFunction();
            void removeCurrentPlot();
            void editCurrentPlot();
            void animateFunction();
            ///Slots for the zoom menu
            void zoomIn();
            void zoomOut();
            void zoomToTrigonometric();

      protected slots:
            void sliderWindowClosed();
            /// Restore the mouse cursor when a drawing is finished
            void updateCursor();
      
      signals:
            void setStatusBarText(const QString &);
      
      protected:
            /// called when focus is lost
            virtual void focusOutEvent( QFocusEvent * );
            /// called when focus is gained
            virtual void focusInEvent( QFocusEvent * );
            void paintEvent(QPaintEvent *);
            void resizeEvent(QResizeEvent *);
            /// Updating the cross hair.
            void mouseMoveEvent(QMouseEvent *);
            /// Toggles the trace mode if the cursor is near to a plot.
            void mousePressEvent(QMouseEvent *);
            /// when a key is pressed and the graph widget has focus
            void keyPressEvent(QKeyEvent * );
            /// called when a mouse key is released
            void mouseReleaseEvent ( QMouseEvent * e );
            /// Is needed to be reimplement so that the user can stop a preview-drawing
            bool event( QEvent * e );
            /**
             * Updates csxpos and csypos from the current mouse position.
             * @return whether the crosshair is within the bounds of the diagram.
             */
            bool updateCrosshairPosition();
      
      private:
            /**
             * Fills the popup menu according to the currently selected plot.
             */
            void fillPopupMenu();
            /**
             * For using in automatic tic spacing. Given \p range (e.g. x_max-x_min)
             * and the \p length_mm (in millimeters), it aims to find a "nice"
             * spacing distance that is visually pleasing and also fits the base 10
             * number system in use (i.e. is a decimal multiple of 1, 2 or 5).
             */
            double niceTicSpacing( double length_mm, double range );
            /**
             * When zoomed in on part of a circle, it looks nearly straight. KmPlot
             * uses this to quickly draw curves that are mostly straight. Given the
             * curvature, this function returns the maximum length of line that can
             * be used to draw a part of a curve with the given curvature without
             * the curve starting to look jagged.
             */
            static double maxSegmentLength( double curvature );
            /**
             * \return an appropriate value to use in numerical differentiation.
             */
            double h( const Plot & plot ) const;
            /**
             * Initializes the size, scaling, etc variables from the given paint
             * device.
             */
            void initDrawing( QPaintDevice * device, PlotMedium medium );
            /**
            * Print out table with additional information. Only for printing.
            */
            void drawHeaderTable(QPainter *);
            /// Draw the grid.
            void drawGrid( QPainter* );
            /**
             * Draw the axes.
             */
            void drawAxes( QPainter *painter );
            /**
             * Draw the axes' labels.
             */
            void drawLabels( QPainter *painter );
            /**
             * Draw the labels for the x-axis (this function is called from
             * drawLabels).
             * \a painter The QPainter to draw the labels with
             * \a endLabelWidth_mm the distance of the "x" label from the edge.
             */
            void drawXAxisLabels( QPainter *painter, double endLabelWidth_mm );
            /**
             * Draw the labels for the y-axis (this function is called from
             * drawLabels).
             */
            void drawYAxisLabels( QPainter *painter );
            /**
             * Draw a non-implicit function.
             */
            void drawFunction( Function * function, QPainter * painter );
            /**
             * Draw the function plots (other than implicit).
             */
            void drawPlot( const Plot & plot, QPainter*);
            /**
             * Draw the tangent field (for a differential function).
             */
            void drawTangentField( const Plot & plot, QPainter * painter );
            /**
             * Draw an implicit function.
             */
            void drawImplicit( Function * function, QPainter * );
            /**
             * Draw the extrema points, function names, etc. This needs to be done
             * after the functions have all been drawn so that the label positioning
             * knows where the plots have been drawn.
             */
            void drawFunctionInfo( QPainter * painter );
            /**
             * Initializes for the drawLabel function, called before drawing has
             * started.
             */
            void initDrawLabels();
            /**
             * Draw text (e.g. showing the value of an extrema point or a function
             * name) at the given (real) position.
             */
            void drawLabel( QPainter * painter, const QColor & color, const QPointF & realPos, const QString & text );
            /**
             * Used by plotImplicit to draw the plot in the square associated with
             * the given point.
             */
            void drawImplicitInSquare( const Plot & plot, QPainter *, double x, double y, Qt::Orientations orientation, QList<QPointF> * singular );
            /**
            * \return whether should draw the pixel from the given line length,
            * according to the given pen style (used in plotfkt).
            */
            bool penShouldDraw( double totalLength, const Plot & plot );
            /**
            * \return An appropriate pen for drawing the plot.
            */
            QPen penForPlot( const Plot & plot, QPainter * painter ) const;
            /**
             * Used in findRoot.
             */
00350             enum RootAccuracy
            {
00352                   PreciseRoot,      ///< Will potential spend a long time finding a root to a high degree of accuracy
00353                   RoughRoot         ///< Won't spend too long making a root accurate, giving up quickly if failed to find root
            };
            /**
             * Used in trace mode. Attempts to find the root of equation \p eq near
             * \p x (which is then set to the exact root if found).
             * \returns whether a root was found.
             */
            bool findRoot( double * x, const Plot & plot, RootAccuracy accuracy );
            /**
             * Equivalent function as above for implicit functions.
             */
            bool findRoot( double * x, double * y, const Plot & plot, RootAccuracy accuracy );
            /**
             * For use in the findRoot functions.
             * \p max_k maximum number of iterations
             * \p max_f the largest value of y which is deemed a root found
             */
            void setupFindRoot( const Plot & plot, RootAccuracy accuracy, double * max_k, double * max_f, int * n );
            /**
             * Finds the list of points (in function coordinates) at which the
             * derivative of the given plot is zero in the range of the currently
             * viewable segment of the plot.
             */
            QList<QPointF> findStationaryPoints( const Plot & plot );
            /**
             * Find all roots (at which the given plot is zero) in the range
             * [min,max].
             */
            QList<double> findRoots( const Plot & plot, double min, double max, RootAccuracy accuracy );
            /**
             * Which part of the status bar.
             */
00385             enum StatusBarSection
            {
                  XSection          = 1,
                  YSection          = 2,
                  RootSection       = 3,
                  FunctionSection   = 4
            };
            /**
             * Changes the text in the statusbar.
             */
            void setStatusBar( const QString &text, StatusBarSection section );
            /**
            * \return whether the crosshairs should be shown for the current mouse
            * position, zoom mode, etc.
            */
            bool shouldShowCrosshairs() const;
            /**
            * Zooms in by amount \p zoomFactor (which will zooming out if less than 1)
            * from clicking at \p mousePos (in widget coordinates).
            */
            void zoomIn( const QPoint & mousePos, double zoomFactor );
            /**
            * Zooms in from having drawn \p zoomRect (which is in widget coordinates).
            */
            void zoomIn( const QRectF & zoomRect );
            /**
            * Zooms out from havoutg drawn \p zoomRect (which is out widget
            * coordinates).
            */
            void zoomOut( const QRectF & zoomRect );
            /**
            * Translates the view by \p dx, \p dy (in widget coordinates).
            */
            void translateView( int dx, int dy );
            /**
            * Finds the plot (if any) under the last mouse pos as recorded by
            * updateCrosshairPosition(). This sets csmode, cstype, csparam. If no plot
            * was found, then csmode is set to -1.
             * \return the function position of the closest plot if one was found.
            */
            QPointF getPlotUnderMouse();
            /**
            * Finds the closest point to \p pos (which is in real coordinates) to
             * the given function.
            * \return the parametization (angle, x or t) that gives the closest
             * point.
            */
            double getClosestPoint( const QPointF & pos, const Plot & plot );
            /**
            * Calculates the pixel distance from \p pos to the display point of the
            * given function at \p x.
            */
            double pixelDistance( const QPointF & pos, const Plot & plot, double x, bool updateFunction );
            /**
             * \param overlapEdge whether to give values that are slightly either
             * side of the view; this is useful for thick pens
             * \return an appropriate xmin value for the given function
             * plotting.
             */
            double getXmin( Function * function, bool overlapEdge = false );
            /**
             * \param overlapEdge whether to give values that are slightly either
             * side of the view; this is useful for thick pens
             * \return an appropriate xmax value for the given function for
             * plotting.
             */
            double getXmax( Function * function, bool overlapEdge = false );
            
            /**
             * How to behave in the *ToPixel functions.
             */
00456             enum ClipBehaviour
            {
00458                   ClipAll,          ///< Clips any points going over the edge of the diagram
00459                   ClipInfinite      ///< Clips only infinite and NaN points going over the edge
            };
            /**
             * @name Transformations
             * These functions convert real coordinates to pixel coordinates and vice
             * versa.
             */
            double xToPixel( double x, ClipBehaviour clipBehaviour = ClipAll, double xIfNaN = 0 );
            double yToPixel( double y, ClipBehaviour clipBehaviour = ClipAll, double yIfNaN = 0 );
            QPointF toPixel( const QPointF & real, ClipBehaviour clipBehaviour = ClipAll, const QPointF & pixelIfNaN = QPointF() );
            double xToReal( double x );
            double yToReal( double y );
            QPointF toReal( const QPointF & pixel );
00472             bool xclipflg;    ///< clipflg is set to 1 if the plot is out of the plot area.
00473             bool yclipflg;    ///< clipflg is set to 1 if the plot is out of the plot area.
            /**
             * Contains the settings for drawing the area under a graph (when
             * calculating the area from function tools.
             */
00478             IntegralDrawSettings m_integralDrawSettings;
            /**
             * Separation distance between the grid lines.
             */
00482             Value ticSepX, ticSepY;
            /**
             * Positions of the first grid line.
             */
00486             double ticStartX, ticStartY;
      
            QPointF m_crosshairPixelCoords;
00489             QPointF m_crosshairPosition;  ///< in real coordinates
      
            /**
             * The t- or x- (angle) coordinate of the traced curve - when tracing a
             * polar or parametric curve.
             */
00495             double m_trace_x;
            /**
             * When tracing a Cartesian plot and the trace position nears the
             * x-axis, an attempt to find a root will be found. If found, this will
             * be set to true, and no further attempts will be made at finding a
             * root. Once the plot position moves away from the x-axis again, this
             * will be set to false.
             */
00503             bool m_haveRoot;

            /// @return whether cspos is in the range of the view or in the custom range for the given \p plot
            bool crosshairPositionValid( Function * plot ) const;
            
            /// represents the Printer options set by user in the Print Dialog
            /// @see KPrinterDlg
00510             bool m_printHeaderTable;
            bool m_printBackground;
            double m_printWidth;
            double m_printHeight;
            /// if stop_calculating is true, the user has canceled drawing of an integral graph
00515             bool m_stopCalculating;
            /// the background color of the graph
00517             QColor m_backgroundColor;
            ///buffer the current window so all functions don't need to be re-drawed
00519             QPixmap buffer;
            /// the popup menu
00521             KMenu *m_popupMenu;
            /// The pointer to the popup menu's title
00523             QAction *m_popupMenuTitle;
            /// is set to true if an integral is calculated
00525             bool m_isDrawing;
            /**
             * Describes the state of the popup menu.
             */
00529             enum PopupStatus
            {
                  NoPopup,
                  Popup,
                  PopupDuringTrace
            };
            ///status of the popup menu
00536             PopupStatus m_popupMenuStatus;
            /// False if KmPlot is started as a program, otherwise true
00538             bool const m_readonly;
            /// For drawing diagram labels
00540             QFont m_labelFont;
            /**
             * The resolution of label positioning.
             */
00544             static const int LabelGridSize = 50;
            /**
             * Indicate which parts of the diagram have content (e.g. axis or
             * plots), so that they can be avoided when drawing diagram labels
             */
00549             bool m_usedDiagramArea[LabelGridSize][LabelGridSize];
            /**
             * Marks the given diagram rectangle (in screen coords) as 'used'.
             */
            void markDiagramAreaUsed( const QRectF & rect );
            /**
             * Marks the given diagram point (in screen coords) as 'used'.
             */
            void markDiagramPointUsed( const QPointF & point );
            /**
             * \return the m_usedDiagramArea coords for the screen rect.
             */
            QRect usedDiagramRect( const QRectF & rect ) const;
            /**
             * \return the cost of occupying the given rectangle (as in whether it
             * overlaps other diagram content, etc).
             */
            int rectCost( QRectF rect ) const;
      
00568             enum ZoomMode
            {
00570                   Normal,                       ///< no zooming
00571                   AnimatingZoom,          ///< animating a current zooming
00572                   ZoomIn,                       ///< zoom in
00573                   ZoomOut,                ///< zoom out
00574                   ZoomInDrawing,          ///< drawing a rectangle for zooming in
00575                   ZoomOutDrawing,         ///< drawing a rectangle for zooming out
00576                   AboutToTranslate, ///< user has clicked on an empty spot, but hasn't moved the mouse yet
00577                   Translating             ///< dragging the view with the mouse
            };
                  
            /// The current editing status
00581             ZoomMode m_zoomMode;
            /// for zoom-mode
00583             QPoint m_zoomRectangleStart;
            /// for animating zoom; contains the rectangle (in real coordinates) to draw
00585             QRectF m_animateZoomRect;
            /// for translating the view via dragging
00587             QPoint m_prevDragMousePos;
            /// timer that is started when the mouse is pressed
00589             QTime * m_mousePressTimer;
            
            /**
             * The rectangle (in painter, and hence pixel, coordinates) that the
             * plots must be in. This is also the size of the image being drawn to,
             * since the painter remains untransformed.
             */
00596             QRect m_clipRect;
            /**
             * This matrix transforms from real coordinates to painter coordinates.
             * (Note that the painter does not have any transformation applied).
             */
00601             QMatrix m_realToPixel;
            /**
             * The inverse matrix of m_realToPixel; it maps from pixel coordinates
             * to real X-Y coordinates.
             */
00606             QMatrix m_pixelToReal;
      
            QString m_statusBarText[4];
            
            enum Cursor { CursorWait, CursorBlank, CursorArrow, CursorCross, CursorMagnify, CursorLessen, CursorMove };
            Cursor m_prevCursor;
            
            static View * m_self;
            
00615             QTextEdit * m_textEdit; ///< Contains m_textDocument
00616             QTextDocument * m_textDocument; ///< Used for layout of axis labels
};

#endif // View_included

Generated by  Doxygen 1.6.0   Back to index