plotsview2d.cpp 11.1 KB
Newer Older
1
/*************************************************************************************
2
 *  Copyright (C) 2007-2008 by Aleix Pol <aleixpol@kde.org>                          *
3
 *  Copyright (C) 2012-2013 by Percy Camilo T. Aucahuasi <percy.camilo.ta@gmail.com> *
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *                                                                                   *
 *  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   *
 *************************************************************************************/

20
#include "plotsview2d.h"
21

22 23 24 25 26 27 28 29 30 31
#include <QSvgGenerator>
#include <QWheelEvent>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QList>
#include <QPixmap>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QFile>
#include <QDebug>
32 33
#include <QTimer>
#include <QPropertyAnimation>
34
#include <QItemSelectionModel>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
35
#include <QCoreApplication>
36 37
#include <QApplication>
#include <QClipboard>
38

39
#include <analitza/analyzer.h>
40 41
#include <analitzaplot/plotter2d.h>
#include <analitzaplot/plotsmodel.h>
42
#include <cmath>
43

44 45
using namespace Analitza;

46
PlotsView2D::PlotsView2D(QWidget *parent)
47
    : QWidget(parent)
48
    , Plotter2D(size())
49 50 51 52
    , valid(false)
    , mode(None)
    , m_framed(false)
    , m_readonly(false)
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
53
    , m_selection(nullptr)
54
{
55 56 57 58 59
    this->setFocusPolicy(Qt::ClickFocus);
    this->setCursor(Qt::CrossCursor);
    
    this->setMouseTracking(!m_readonly);
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
60
    this->setMinimumSize(128, 128);
61
    
62
    //BEGIN setup plotter2d grid
63
    defViewport = QRectF(QPointF(-10.0, 10.0), QSizeF(20.0, -20.0));
64 65
    resetViewport();
    
66
    //colors
67
    QColor bgcolor = palette().color(QPalette::Base);
68 69
    setBackgroundColor(bgcolor);
    
70
    QColor gridcolor = palette().color(QPalette::Midlight);
71 72
    setGridColor(gridcolor);
    //END
73
    
74
    this->setAutoFillBackground(false);
75 76
}

77
PlotsView2D::~PlotsView2D() {}
78

79
void PlotsView2D::paintEvent(QPaintEvent * )
80
{
81 82 83 84 85
    if (!valid)
    {
        if (buffer.isNull() || buffer.size()!=size())
            buffer = QPixmap(size());
        buffer.fill(backgroundColor());
86
    
87
        drawFunctions(&buffer);
88 89 90

        valid=true;
    }
91 92
    QPainter p(this);
    p.drawPixmap(QRect(QPoint(0,0), size()), buffer);
93
    
94
    QPen ccursor;
95
    
96
//  finestra.setRenderHint(QPainter::Antialiasing, true);
97
    
98
    //NOTE GSOC 2012 better guards : model()->rowCount() > 0 && !mark.isNull() ... si no se cumplen que no dibuje las lineas rojas
99
    if(!m_readonly && mode==None) {
100 101
        //QPointF ultim = toWidget(mark);
        QPointF ultim(cursorPos);
102
        
103
        //Draw derivative
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
        if (!mark.isNull()) 
        {
            ultim = toWidget(mark); // si no es nulo apunto al lugar del punto de pendiente
            
            ccursor.setColor(palette().color(QPalette::Active, QPalette::Link));
            ccursor.setStyle(Qt::SolidLine);
            QLineF sl=slope(mark);
            sl.translate(mark);
            
            p.setPen(ccursor);
            p.setRenderHint(QPainter::Antialiasing, true);
    #ifndef Q_CC_MSVC
            if(!sl.isNull() && !std::isnan(sl.length()))
    #else
            if(!sl.isNull() && !_isnan(sl.length()))
    #endif
                p.drawLine(toWidget(sl));
            p.setRenderHint(QPainter::Antialiasing, false);
        }
123
        //EOderivative
124
        
125 126
        ccursor.setColor(QColor(0xc0,0,0));
        ccursor.setStyle(Qt::SolidLine);
127
        
128 129 130
        p.setPen(ccursor);
        p.drawLine(QPointF(0.,ultim.y()), QPointF(size().width(), ultim.y()));
        p.drawLine(QPointF(ultim.x(),0.), QPointF(ultim.x(), size().height()));
131
        
132
        int w=p.fontMetrics().boundingRect(m_posText).width()+15, h=p.fontMetrics().height();
133
        
134 135 136 137 138 139
        if(ultim.x()+w > size().width())
            ultim.setX(size().width()-w);
        if(ultim.y()+h > size().height())
            ultim.setY(size().height()-h);
        if(ultim.y() < 0.)
            ultim.setY(0.);
140
        
141 142 143
        p.setPen(QPen(Qt::black));
        p.drawText(QPointF(ultim.x()+15., ultim.y()+15.), m_posText);
    } else if(!m_readonly && mode==Selection) {
144 145 146 147 148
           //NOTE GSOC 2012 accessibility code, the selection follow system rules :)

//         ccursor.setColor(QColor(0xc0,0,0));
        QColor selcol = QPalette().highlight().color();
        ccursor.setColor(QPalette().highlightedText().color());
149 150
        ccursor.setStyle(Qt::SolidLine);
        p.setPen(ccursor);
151 152 153
//         p.setBrush(QColor(0xff,0xff, 0,0x90));
        selcol.setAlpha(0x90);
        p.setBrush(selcol);
154
        p.drawRect(QRect(press,last));
155
    }
156
    
157 158 159 160 161 162
    if(m_framed) {
        QPen bord(Qt::black);
        p.setPen(bord);
        p.drawRect(QRect(QPoint(0,0), size()-QSize(2,2)));
    }
    p.end();
163
    
164
//  qDebug() << "xxx2 " << viewport;
165 166
}

167
void PlotsView2D::wheelEvent(QWheelEvent *e)
168
{
169
    QRectF viewport=currentViewport();
170
    int steps = e->angleDelta().y()/(8*15);
171
    qreal d = (-0.03*steps) + 1;
172
    
173 174
    if(d>0 || (viewport.width()+d > 2 && viewport.height()+d < 2)) {
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
175
        scaleViewport(d, e->pos());
176 177 178 179
#else
        scaleViewport(d, e->position().toPoint());
#endif
    }
180 181
}

182
void PlotsView2D::mousePressEvent(QMouseEvent *e)
183
{
184
    if(!m_readonly && (e->button()==Qt::LeftButton || e->button()==Qt::MiddleButton)) {
185 186
        last = press = e->pos();
        ant = toViewport(e->pos());
187
        this->setCursor(QCursor(Qt::PointingHandCursor));
188
        if(e->button()==Qt::MiddleButton || (e->button()==Qt::LeftButton && e->modifiers()&Qt::ControlModifier))
189
            mode=Pan;
190 191
        else if(e->button()==Qt::LeftButton)
            mode=Selection;
192 193 194
    }
}

195
void PlotsView2D::mouseReleaseEvent(QMouseEvent *e)
196 197 198 199 200
{
    if(m_readonly)
        this->setCursor(Qt::ArrowCursor);
    else
        this->setCursor(Qt::CrossCursor);
201
    
202
    if(!m_readonly && mode==Selection) {
203
        QPointF pd = toViewport(e->pos())-toViewport(press);
204
        
205 206
        QPoint pd2 = e->pos()-press;
        QRect rr(press, QSize(pd2.x(), pd2.y()));
207
        
208
        if(rr.width()>20 && rr.height()>20) { //if selection is not very small
209
            QRectF r(fromWidget(press), QSizeF(pd.x(), pd.y()));
210
            
211
            if(r.top()<r.bottom()) {
212 213 214 215
                double aux = r.bottom();
                r.setBottom(r.top());
                r.setTop(aux);
            }
216
            
217
            if(r.right()<r.left()) {
218 219 220 221
                double aux = r.left();
                r.setLeft(r.right());
                r.setRight(aux);
            }
222
            
223
            setViewport(r);
224
        } else
225
            sendStatus(QCoreApplication::tr("Selected viewport too small"));
226
    }
227
    
228
    mode = None;
229 230 231
    this->repaint();
}

232
void PlotsView2D::mouseMoveEvent(QMouseEvent *e)
233
{
234
    cursorPos = e->pos();
235 236
    QPair<QPointF, QString> img=calcImage(fromWidget(e->pos()));
    mark=img.first;
237
    
238 239
    if(!m_readonly && mode==Pan && ant != toViewport(e->pos())){
        moveViewport(e->pos() - press);
240
        
241
        press = e->pos();
242
    } else if(e->buttons()&Qt::LeftButton) {
243
        last = e->pos();
244 245 246
    } else if(e->buttons()==0) {
        if(img.second.isEmpty()) {
            mark = fromWidget(e->pos());
247
            sendStatus(QCoreApplication::tr("x=%1 y=%2").arg(mark.x()).arg(mark.y()));
248 249 250
        } else
            sendStatus(img.second);
    }
251
    
252 253 254
    this->repaint();
}

255
void PlotsView2D::keyPressEvent(QKeyEvent * e)
256
{
257 258
    //TODO use grid info (inc) here, made a public method to return current scale increment
    const double xstep=currentViewport().width()/12., ystep=currentViewport().height()/10.;
259
    
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
    switch(e->key()) {
        case Qt::Key_Right:
            setViewport(lastUserViewport().translated(xstep, 0));
            break;
        case Qt::Key_Left:
            setViewport(lastUserViewport().translated(-xstep, 0));
            break;
        case Qt::Key_Down:
            setViewport(lastUserViewport().translated(0, -ystep));
            break;
        case Qt::Key_Up:
            setViewport(lastUserViewport().translated(0, ystep));
            break;
        case Qt::Key_Minus:
            zoomOut();
            break;
        case Qt::Key_Plus:
            zoomIn();
            break;
        default:
            return;
281 282 283
    }
}

284
void PlotsView2D::resizeEvent(QResizeEvent * ev)
285
{
286 287 288 289
    if (ev->size() != buffer.size()) {
        buffer = QPixmap(ev->size());
        setPaintedSize(ev->size());
    }
290 291
}

292
bool PlotsView2D::toImage(const QString &path, Format f)
293
{
294
    Q_ASSERT(!path.isEmpty());
295
    bool b=false;
296
    
297 298 299 300 301 302
    switch(f) {
        case SVG: {
            QFile f(path);
            QSvgGenerator gen;
            gen.setOutputDevice(&f);
            gen.setSize(this->size());
303
            drawFunctions(&gen);
304 305 306 307 308 309 310
            b=true;
            forceRepaint();
        }   break;
        case PNG:
            this->repaint();
            b=buffer.save(path, "PNG");
            break;
311
    }
312
    
313 314 315
    return b;
}

316 317 318 319 320 321 322
void PlotsView2D::snapshotToClipboard()
{
    QClipboard *cb = QApplication::clipboard();

    cb->setImage(buffer.toImage());
}

323
void Analitza::PlotsView2D::modelChanged()
324 325 326
{
}

327
void PlotsView2D::setReadOnly(bool ro)
328 329
{
    m_readonly=ro;
330
    setCursor(ro ? Qt::ArrowCursor : Qt::CrossCursor);
331 332 333
    setMouseTracking(!ro);
}

334
QRectF PlotsView2D::definedViewport() const
335
{
336
    return lastUserViewport();
337 338
}

339
void PlotsView2D::viewportChanged()
340
{
341
    QRectF userViewport=lastUserViewport(), viewport=currentViewport();
342
    
343
    sendStatus(QStringLiteral("(%1, %2)-(%3, %4)")
344 345 346
            .arg(viewport.left()).arg(viewport.top()).arg(viewport.right()).arg(viewport.bottom()));
    emit viewportChanged(userViewport);
}
347

348
int PlotsView2D::currentFunction() const
349
{
350 351
    if (!model())
        return -1;
352
    
353 354 355 356
    int ret=-1;
    if(m_selection) {
        ret=m_selection->currentIndex().row();
    }
357
    
358
    return ret;
359 360
}

361
void PlotsView2D::setSelectionModel(QItemSelectionModel* selection)
362
{
363 364
    Q_ASSERT(selection->model() == model());

365 366 367
    if (m_selection)
        disconnect(m_selection,SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(forceRepaint()));

368
    m_selection = selection;
369 370

    connect(m_selection,SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(forceRepaint()));
371
}