src/qvgui/qvcanvas.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00024 
00025 #include <math.h>
00026 #include <iostream>
00027 
00028 #include <QMouseEvent>
00029 #include <QPainter>
00030 #include <QScrollArea>
00031 #include <QScrollBar>
00032 #include <QGLWidget>
00033 #include <QToolButton>
00034 #include <QStatusBar>
00035 #include <QHBoxLayout>
00036 #include <QGridLayout>
00037 
00038 #include <qwt_scale_widget.h>
00039 #include <qwt_scale_engine.h>
00040 #include <qwt_scale_div.h>
00041 
00042 #include <qvcore/qvimage.h>
00043 #include <qvgui/qvcanvas.h>
00044 
00045 void QVPainter::drawQVImage(QVGenericImage *image,bool adaptSize,float low,float high)
00046 {
00047         imageArea->drawQVImage(image,adaptSize,low,high);
00048 }
00049 
00050 
00051 void QVPainter::drawTextUnscaled(const QPointF & position, const QString & text)
00052 {
00053         save();
00054         resetMatrix();
00055         translate(-imageArea->topLeft);
00056         drawText(imageArea->zoom*position,text);
00057         restore();
00058 }
00059 
00060 void QVPainter::drawTextUnscaled(const QPoint & position, const QString & text)
00061 {
00062         save();
00063         resetMatrix();
00064         translate(-imageArea->topLeft);
00065         drawText(imageArea->zoom*position,text);
00066         restore();
00067 }
00068 
00069 void QVPainter::drawTextUnscaled(const QRectF & rectangle, int flags,
00070                                           const QString & text, QRectF * boundingRect)
00071 {
00072         save();
00073         resetMatrix();
00074         translate(-imageArea->topLeft);
00075         drawText(QRectF(imageArea->zoom*rectangle.topLeft(),
00076                                     imageArea->zoom*rectangle.size()),flags,text,boundingRect);
00077         if(boundingRect != 0)
00078                 *boundingRect = QRectF(imageArea->zoom*boundingRect->topLeft(),
00079                                                            imageArea->zoom*boundingRect->size());
00080         restore();
00081 }
00082 
00083 void QVPainter::drawTextUnscaled(const QRect & rectangle, int flags,
00084                                           const QString & text, QRect * boundingRect)
00085 {
00086         save();
00087         resetMatrix();
00088         translate(-imageArea->topLeft);
00089         drawText(QRect(imageArea->zoom*rectangle.topLeft(),
00090                                    imageArea->zoom*rectangle.size()),flags,text,boundingRect);
00091         if(boundingRect != 0)
00092                 *boundingRect = QRect(imageArea->zoom*boundingRect->topLeft(),
00093                                                           imageArea->zoom*boundingRect->size());
00094         restore();
00095 }
00096 
00097 void QVPainter::drawTextUnscaled(int x, int y, const QString & text)
00098 {
00099         save();
00100         resetMatrix();
00101         translate(-imageArea->topLeft);
00102         drawText(imageArea->zoom*x,imageArea->zoom*y,text);
00103         restore();
00104 }
00105 
00106 void QVPainter::drawTextUnscaled(int x, int y, int width, int height, int flags,
00107                                           const QString & text, QRect * boundingRect)
00108 {
00109         save();
00110         resetMatrix();
00111         translate(-imageArea->topLeft);
00112         drawText(imageArea->zoom*x,imageArea->zoom*y,imageArea->zoom*width,
00113                          imageArea->zoom*height,flags,text,boundingRect);
00114         if(boundingRect != 0)
00115                 *boundingRect = QRect(imageArea->zoom*boundingRect->topLeft(),
00116                                                           imageArea->zoom*boundingRect->size());
00117         restore();
00118 }
00119 
00120 void QVPainter::drawTextUnscaled(const QRectF & rectangle, const QString & text,
00121                                           const QTextOption & option)
00122 {
00123         save();
00124         resetMatrix();
00125         translate(-imageArea->topLeft);
00126         drawText(QRectF(imageArea->zoom*rectangle.topLeft(),
00127                                     imageArea->zoom*rectangle.size()),text,option);
00128         restore();
00129 }
00130 
00131 
00132 void QVImageArea::initObject(int w, int h)
00133 {
00134         zoom = 1;
00135         origwidth = w;
00136         origheight = h;
00137         topLeft = QPoint(0,0);
00138         selRect = QRect();
00139         zoomRect = QRect();
00140         setAttribute(Qt::WA_NoSystemBackground);
00141         setMouseTracking(TRUE);
00142         setMinimumSize(qMin(w,max_zoom),qMin(h,max_zoom));
00143         setMaximumSize(w,h);
00144         resize(w,h);
00145         mouseMode = noneMode;
00146         dragging = FALSE;
00147         emit newGeometry(origwidth,origheight,topLeft.x(),topLeft.y(),width(),height(),zoom);
00148 }
00149 
00150 QVImageArea::QVImageArea(int w, int h,QWidget *parent)
00151         : QGLWidget(QGLFormat(QGL::DoubleBuffer|QGL::NoDepthBuffer|
00152                 QGL::DirectRendering|QGL::HasOverlay), parent), max_zoom(128)
00153 {
00154         initObject(w,h);
00155 }
00156 
00157 QVImageArea::QVImageArea(int w, int h,QWidget *parent,QGLWidget *other)
00158         : QGLWidget(parent,other), max_zoom(128)
00159 {
00160         initObject(w,h);
00161 }
00162 
00163 QVImageArea::QVImageArea *first_image_area=NULL;
00164 
00165 void QVImageArea::centerZoom(int zoom)
00166 {
00167         if((zoom != this->zoom) and (zoom >= 1) and (zoom <= max_zoom)) {
00168                 int old_zoom = this->zoom;
00169                 this->zoom = zoom;
00170                 setMaximumSize(zoom*origwidth,zoom*origheight);
00171                 QPoint newTopLeft = zoom*(topLeft+QPoint(width(),height())/2)/old_zoom
00172                                                         - QPoint(width(),height())/2;
00173                 if(newTopLeft.x() < 0)
00174                         newTopLeft.setX(0);
00175                 if(newTopLeft.y() < 0)
00176                         newTopLeft.setY(0);
00177                 if(newTopLeft.x()+width() > origwidth*zoom)
00178                         newTopLeft.setX(origwidth*zoom-width());
00179                 if(newTopLeft.y()+height() > origheight*zoom)
00180                         newTopLeft.setY(origheight*zoom-height());
00181                 topLeft = newTopLeft;
00182                 update();
00183                 emit newGeometry(origwidth,origheight,topLeft.x(),topLeft.y(),width(),height(),zoom);
00184         }
00185 }
00186 
00187 void QVImageArea::resizeGL(int width, int height)
00188 {
00189         QPoint newTopLeft = topLeft,newBottomRight = topLeft+QPoint(width,height);
00190         if(newBottomRight.x() > origwidth*zoom)
00191                 newTopLeft.setX(origwidth*zoom-width);
00192         if(newBottomRight.y() > origheight*zoom)
00193                 newTopLeft.setY(origheight*zoom-height);
00194         topLeft = newTopLeft;
00195         update();
00196         emit newGeometry(origwidth,origheight,topLeft.x(),topLeft.y(),width,height,zoom);
00197 }
00198 
00199 
00200 void QVImageArea::wheelEvent(QWheelEvent *event)
00201 {
00202     if (event->delta() > 0) {
00203                 centerZoom(2*zoom);
00204         } else {
00205                 centerZoom(zoom/2);
00206         }
00207 }
00208 
00209 // Auxiliary function to draw rects that draw themselves "intuitively" at the
00210 // borders:
00211 QRectF QVImageArea::intuitiveRect(QRect rect)
00212 {
00213         return QRectF(rect.x(),rect.y()+1.0/zoom,
00214                                   rect.width()-1.0/zoom,rect.height()-1.0/zoom);
00215 }
00216 
00217 
00218 QRect QVImageArea::innerRect()
00219 {
00220         QPoint q1(static_cast<int>(ceilf(static_cast<float>(topLeft.x())/zoom)),
00221                                 static_cast<int>(ceilf(static_cast<float>(topLeft.y())/zoom))),
00222                         q2(static_cast<int>(floor(static_cast<float>((topLeft.x()+width()))/zoom)-1),
00223                                 (static_cast<int>(floor(static_cast<float>(topLeft.y()+height()))/zoom))-1);
00224         return QRect(q1,q2);
00225 }
00226 
00227 QRect QVImageArea::outerRect()
00228 {
00229         QPoint q1(static_cast<int>(ceilf(static_cast<float>(topLeft.x())/zoom)-1),
00230                                 static_cast<int>(ceilf(static_cast<float>(topLeft.y())/zoom))-1),
00231                    q2(static_cast<int>(floor(static_cast<float>((topLeft.x()+width()))/zoom)),
00232                                 (static_cast<int>(floor(static_cast<float>(topLeft.y()+height()))/zoom)));
00233 
00234         return QRect(q1,q2) & QRect(0,0,origwidth,origheight);
00235 }
00236 
00237 void QVImageArea::paintEvent(QPaintEvent *event)
00238 {
00239         Q_UNUSED(event);
00240 
00241         painter = new QVPainter(this);
00242 
00243         painter->begin(this);
00244         //painter->setRenderHint(QPainter::TextAntialiasing);
00245 
00246         painter->setViewport(0,0,width(),height());
00247         painter->resetMatrix();
00248         painter->translate(-topLeft);
00249         painter->scale(zoom,zoom);
00250 
00251         // Now we call the user painting function:
00252         QVCanvas *image_viewer = qobject_cast<QVCanvas *>(parent());
00253         if(image_viewer == 0) {
00254                 qFatal("Error interno de QVision: El padre de una QVImageArea debería ser un QVCanvas");
00255         } else {
00256                 glClearColor(0,0,1,0);
00257                 glClear(GL_COLOR_BUFFER_BIT); // Blue background
00258                 image_viewer->viewer();
00259         }
00260 
00261         // Now, we render the selection (red) and zoom (blue) rectangles:
00262         if(selRect != QRect()) {
00263                 painter->setPen(QColor(Qt::red));
00264                 // Dirty trick for more intuitive behaviour of rectangle in the borders
00265                 // of the window:
00266                 painter->drawRect(intuitiveRect(selRect));
00267         }
00268         if(zoomRect != QRect()) {
00269                 painter->setPen(QColor(Qt::blue));
00270                 // Dirty trick for more intuitive behaviour of rectangle in the borders
00271                 // of the window:
00272                 painter->drawRect(intuitiveRect(zoomRect));
00273         }
00274 
00275         // Finally, if zoom is big enough, draw numbers with pixel values:
00276         if(zoom >= 32) {
00277                 painter->setPen(QColor(Qt::green));
00278                 QRect outer = outerRect();
00279                 for(int j=outer.y();j<outer.y()+outer.height();j++) {
00280                         for(int i=outer.x();i<outer.x()+outer.width();i++) {
00281                                 if(not imageList.isEmpty()) {
00282                                         QString value_string;
00283                                         int k;
00284                                         for(k=0;k<imageList.size();k++) {
00285                                                 QRect img_rect = QRect(imageList[k]->getAnchor()+imageList[k]->getROI().topLeft(),
00286                                                           QSize(imageList[k]->getROI().width(),imageList[k]->getROI().height()));       
00287                                                 if(i>=img_rect.left() and i<=img_rect.right() and j>=img_rect.top() and j<=img_rect.bottom()) {
00288                                                         //value_string = QString("-%1-").arg(k);
00289                                                         if(imageList[k]->isCompatibleWith("QVImage<uChar,1>")) {
00290                                                                 value_string =  QString("%1").arg((*(QVImage<uChar,1>*)imageList[k])(i-img_rect.topLeft().x()+imageList[k]->getROI().topLeft().x(),j-img_rect.topLeft().y()+imageList[k]->getROI().topLeft().y()));
00291                                                         } else if(imageList[k]->isCompatibleWith("QVImage<sFloat,1>")) {
00292                                                                 if(zoom >= 64) {
00293                                                                         value_string =  QString("%1").arg((*(QVImage<sFloat,1>*)imageList[k])(i-img_rect.topLeft().x()+imageList[k]->getROI().topLeft().x(),j-img_rect.topLeft().y()+imageList[k]->getROI().topLeft().y()),0,'g',-1);
00294                                                                 }
00295                                                         }else if(imageList[k]->isCompatibleWith("QVImage<uChar,3>")) {
00296                                                                 int red,green,blue;
00297                                                                 if(zoom >= 64) {
00298                                                                         red = (*(QVImage<uChar,3>*)imageList[k])(i-img_rect.topLeft().x()+imageList[k]->getROI().topLeft().x(),j-img_rect.topLeft().y()+imageList[k]->getROI().topLeft().y(),0);
00299                                                                         green = (*(QVImage<uChar,3>*)imageList[k])(i-img_rect.topLeft().x()+imageList[k]->getROI().topLeft().x(),j-img_rect.topLeft().y()+imageList[k]->getROI().topLeft().y(),1);
00300                                                                         blue = (*(QVImage<uChar,3>*)imageList[k])(i-img_rect.topLeft().x()+imageList[k]->getROI().topLeft().x(),j-img_rect.topLeft().y()+imageList[k]->getROI().topLeft().y(),2);
00301                                                                         value_string =  QString("R:%1\nG:%2\nB:%3").arg(red).arg(green).arg(blue);
00302                                                                 }
00303                                                         } else {
00304                                                                 // alternate code for that type of image ...
00305                                                                 qFatal("Type of QVGenericImage still not supported in paintEvent");
00306                                                         }
00307                                                         break;
00308                                                 }
00309                                         }
00310                                         if(k==imageList.size()) {
00311                                                 value_string = QString("X");
00312                                         }
00313 
00314                                         /* Alternative 1 (renderText):
00315                                         renderText((i*zoom-topLeft.x()), ((j+1)*zoom-topLeft.y()),
00316                                                            value_string);*/
00317 
00318                                         /* Alternative 2 (drawText with painter manipulation):*/
00319                                         /*painter->resetMatrix();
00320                                         painter->translate(-topLeft);
00321                                         painter->drawText(
00322                                                 QRect(zoom*QPoint(i,j),zoom*QPoint(i+1,j+1)),
00323                                                                   Qt::AlignCenter|Qt::TextDontClip,value_string);
00324                                         painter->scale(zoom,zoom);*/
00325 
00326                                         /* Alternative 3 (drawTextUnscaled, with QRectF):*/
00327                                         /*painter->drawTextUnscaled(
00328                                                 QRectF(QPointF(i,j),QSize(1,1)),
00329                                                           Qt::AlignCenter|Qt::TextDontClip,value_string);*/
00330 
00331                                         /* Alternative 4 (drawTextUnscaled, with QRect): */
00332                                         // OJO, (!) error de QT (poco importante) en construcción de
00333                                         // rectangulos del tipo QRect(QPoint(x,y),QPoint(x+1,y+1)).
00334                                         painter->drawTextUnscaled(
00335                                                 QRect(QPoint(i,j),QSize(1,1)),
00336                                                           Qt::AlignCenter|Qt::TextDontClip,value_string);
00337                                 }
00338                         }
00339                 }
00340         }
00341 
00342         // End of painting:
00343         painter->end();
00344         delete painter;
00345 
00346         //imageList.clear();
00347         while (!imageList.isEmpty())
00348          delete imageList.takeFirst();
00349 }
00350 
00351 void QVImageArea::resizeImageArea(int w,int h)
00352 {
00353         if(w != origwidth or h != origheight) {
00354                 zoom = 1;
00355                 origwidth = w;
00356                 origheight = h;
00357                 topLeft = QPoint(0,0);
00358                 selRect = QRect();
00359                 zoomRect = QRect();
00360                 setMinimumSize(qMin(w,max_zoom),qMin(h,max_zoom));
00361                 setMaximumSize(w,h);
00362                 resize(w,h);
00363                 emit newGeometry(origwidth,origheight,topLeft.x(),topLeft.y(),width(),height(),zoom);
00364         }
00365 }
00366 
00367 void QVImageArea::drawQVImage(QVGenericImage *image,bool adaptSize,float low, float high)
00368 {
00369 
00370         QVGenericImage *imagecopy=NULL;
00371         if(image->isCompatibleWith("QVImage<uChar,1>")) {
00372                 imagecopy = new QVImage<uChar,1>;
00373                 *(dynamic_cast<QVImage<uChar,1>*>(imagecopy)) = *(dynamic_cast<QVImage<uChar,1>*>(image));
00374         } else if(image->isCompatibleWith("QVImage<sFloat,1>")) {
00375                 imagecopy = new QVImage<sFloat,1>;
00376                 *(dynamic_cast<QVImage<sFloat,1>*>(imagecopy)) = *(dynamic_cast<QVImage<sFloat,1>*>(image));
00377         }else if(image->isCompatibleWith("QVImage<uChar,3>")) {
00378                 imagecopy = new QVImage<uChar,3>;
00379                 *(dynamic_cast<QVImage<uChar,3>*>(imagecopy)) = *(dynamic_cast<QVImage<uChar,3>*>(image));
00380         } else {
00381         // alternate code for that type of image ...
00382                 qFatal("Type of QVGenericImage still not supported in drawQVImage");
00383         }
00384 
00385         // Image to the top of the stack (front of the list)
00386         imageList.push_front(imagecopy);
00387 
00388         if(adaptSize) {
00389                 this->resizeImageArea(image->getAnchor().x()+image->getROI().x()+image->getROI().width(),image->getAnchor().y()+image->getROI().y()+image->getROI().height());
00390         }
00391 
00392         // Push the current OpenGL projection and modelview matrices onto their
00393         // respective stacks:
00394         glPushAttrib(GL_ALL_ATTRIB_BITS);
00395         glPushClientAttrib(GL_ALL_ATTRIB_BITS);
00396         glMatrixMode(GL_PROJECTION);
00397         glPushMatrix();
00398         glMatrixMode(GL_MODELVIEW);
00399         glPushMatrix();
00400 
00401         // Set the correct viewport and perspective and model transformation
00402         // for native OpenGL calls:
00403         glViewport(0,0,width(),height());
00404         glMatrixMode(GL_PROJECTION);
00405         glLoadIdentity();
00406         glOrtho(topLeft.x(),topLeft.x()+width(),
00407                         topLeft.y()+height(),topLeft.y(),-1,1);
00408         glMatrixMode(GL_MODELVIEW);
00409         glLoadIdentity();
00410 
00411         // Intersection of current window viewport and image rectangles:
00412         QRect final_rect,outer_rect = outerRect(),
00413                   img_rect = QRect(imagecopy->getAnchor()+imagecopy->getROI().topLeft(),
00414                                                   QSize(imagecopy->getROI().width(),imagecopy->getROI().height()));
00415         final_rect = outer_rect & img_rect;
00416 
00417         // Now, render the image using OpenGL calls:
00418 
00419         // First, WHERE to draw...
00420         QPoint where,dirty; // Dirty trick for offset (bitmap trick).
00421         if(outer_rect.topLeft().x() >= img_rect.topLeft().x()) {
00422                 where.setX(outer_rect.topLeft().x());
00423                 dirty.setX(1);
00424         } else {
00425                 where.setX(img_rect.topLeft().x());
00426                 dirty.setX(0);
00427         }
00428         if(outer_rect.topLeft().y() >= img_rect.topLeft().y()) {
00429                 where.setY(outer_rect.topLeft().y());
00430                 dirty.setY(1);
00431         } else {
00432                 where.setY(img_rect.topLeft().y());
00433                 dirty.setY(0);
00434         }
00435         // Now the dirty trick for offset, using glBitmap:
00436         glRasterPos2f(zoom*(where.x()+dirty.x()+0.0001),zoom*(where.y()+dirty.y()+0.0001));
00437         glBitmap(0, 0, 0, 0, -zoom*dirty.x(), +zoom*dirty.y(), NULL); 
00438 
00439         // ... and second, WHAT to draw:
00440         QRect what;
00441         int img_step = imagecopy->getStep();
00442         glPixelZoom(zoom,-zoom);
00443         if(outer_rect.topLeft().x() >= img_rect.topLeft().x()) {
00444                 what.setX(outer_rect.topLeft().x() - img_rect.topLeft().x() + imagecopy->getROI().topLeft().x());
00445         } else {
00446                 what.setX(imagecopy->getROI().topLeft().x());
00447         }
00448         what.setWidth(final_rect.width());
00449         if(outer_rect.topLeft().y() >= img_rect.topLeft().y()) {
00450                 what.setY(outer_rect.topLeft().y() - img_rect.topLeft().y() + imagecopy->getROI().topLeft().y());
00451         } else {
00452                 what.setY(imagecopy->getROI().topLeft().y());
00453         }
00454         what.setHeight(final_rect.height());
00455 
00456         if(image->isCompatibleWith("QVImage<uChar,1>")) {
00457                 glPixelStorei(GL_UNPACK_ROW_LENGTH,img_step);
00458                 glDrawPixels(what.width(),what.height(),
00459                                          GL_LUMINANCE,GL_UNSIGNED_BYTE,
00460                                          static_cast<QVImage<uchar,1> *>(imagecopy)->getReadData() +
00461                                          what.y()*img_step+what.x());
00462         } else if(image->isCompatibleWith("QVImage<sFloat,1>")) {
00463                 glPixelStorei(GL_UNPACK_ROW_LENGTH,img_step/sizeof(sFloat));
00464 
00465                 float scale=1.0/(high-low),bias=-low*scale;
00466 
00467                 //float scale = 1.0/ (high-low),bias=0;
00468                 glPixelTransferf(GL_RED_BIAS,bias);
00469                 glPixelTransferf(GL_GREEN_BIAS,bias);
00470                 glPixelTransferf(GL_BLUE_BIAS,bias);
00471                 glPixelTransferf(GL_RED_SCALE,scale);
00472                 glPixelTransferf(GL_GREEN_SCALE,scale);
00473                 glPixelTransferf(GL_BLUE_SCALE,scale);
00474 
00475 
00476 /*              glPixelTransferf(GL_RED_SCALE,float(1.0)/(float)127.0);
00477                 glPixelTransferf(GL_GREEN_SCALE,float(1.0)/(float)127.0);
00478                 glPixelTransferf(GL_BLUE_SCALE,float(1.0)/(float)127.0);*/
00479                 // Take care with last parameter (pointer) in this call: it works
00480                 // because of the float* arithmetic:
00481                 glDrawPixels(what.width(),what.height(),
00482                                          GL_LUMINANCE,GL_FLOAT,
00483                                          static_cast<QVImage<sFloat,1> *>(imagecopy)->getReadData() +
00484                                          what.y()*img_step/sizeof(sFloat)+what.x());
00485         } else if(image->isCompatibleWith("QVImage<uChar,3>")) {
00486                 glPixelStorei(GL_UNPACK_ROW_LENGTH,img_step/3);
00487                 glDrawPixels(what.width(),what.height(),
00488                                         GL_RGB,GL_UNSIGNED_BYTE,
00489                                         static_cast<QVImage<uchar,3> *>(imagecopy)->getReadData() +
00490                                         what.y()*img_step+3*what.x());
00491         } else {
00492         // alternate code for that type of image ...
00493                 qFatal("Type of QVGenericImage still not supported in drawQVImage");
00494         }
00495 
00496         // Pop the OpenGL projection and modelview matrices off their respective
00497         // stacks. Pop the OpenGL attributes off the attribute stack.
00498     glPopClientAttrib();
00499     glPopAttrib();
00500     glMatrixMode(GL_MODELVIEW);
00501     glPopMatrix();
00502     glMatrixMode(GL_PROJECTION);
00503     glPopMatrix();
00504 }
00505 
00506 
00507 void QVImageArea::mousePressEvent(QMouseEvent *event)
00508 {
00509         firstPos = event->pos();
00510         dragging = TRUE;
00511         if(mouseMode == dragMode) {
00512                 //setCursor(Qt::ClosedHandCursor);
00513         }
00514 }
00515 
00516 void QVImageArea::mouseMoveEvent(QMouseEvent *event)
00517 {
00518         if(dragging) {
00519                 lastPos = event->pos();
00520                 switch(mouseMode) {
00521                 case dragMode: {
00522                         QPoint minDesp = -topLeft,
00523                                 maxDesp = QPoint(origwidth*zoom,origheight*zoom) -
00524                                                         (topLeft + QPoint(width(),height()));
00525                         QPoint desp = firstPos-lastPos,
00526                                 boundDesp = QPoint(qBound(minDesp.x(),desp.x(),maxDesp.x()),
00527                                                                         qBound(minDesp.y(),desp.y(),maxDesp.y()));
00528                         if(boundDesp != QPoint(0,0)) {
00529                                 topLeft = topLeft+boundDesp;
00530                                 update();
00531                                 emit newGeometry(origwidth,origheight,topLeft.x(),topLeft.y(),width(),height(),zoom);
00532                         }
00533                         firstPos = lastPos;
00534                         emit mouseLeavesImageArea(FALSE);
00535                         emit newMousePosition(static_cast<float>(event->x()+topLeft.x())/zoom,static_cast<float>(event->y()+topLeft.y())/zoom);
00536                         break;
00537                         }
00538                 case zoomMode:
00539                 case selMode:
00540                         {
00541                         QPoint p1(qRound(static_cast<float>(firstPos.x()+topLeft.x())/zoom),
00542                                         qRound(static_cast<float>(firstPos.y()+topLeft.y())/zoom)),
00543                                 p2(qRound(static_cast<float>(lastPos.x()+topLeft.x())/zoom)-1,
00544                                         qRound(static_cast<float>(lastPos.y()+topLeft.y())/zoom)-1);
00545                         if(mouseMode == zoomMode) {
00546                                 // Warning: QT (lesser) error when constructing rectangles of type QRect(QPoint(x,y),QPoint(x-1,y')),
00547                                 // as well QRect(QPoint(x,y),QPoint(x',y-1)). In practice, it is not important, so we won't
00548                                 // blur the code.
00549                                 zoomRect = QRect(p1,p2) & innerRect(); // Intersection
00550                                 emit mouseLeavesImageArea(FALSE);
00551                                 emit newMousePosition(lastPos.x()>firstPos.x()?zoomRect.right():zoomRect.left(),
00552                                                                           lastPos.y()>firstPos.y()?zoomRect.bottom():zoomRect.top());
00553                         } else {
00554                                 selRect = QRect(p1,p2) & innerRect(); // Intersection
00555                                 emit mouseLeavesImageArea(FALSE);
00556                                 emit newMousePosition(lastPos.x()>firstPos.x()?selRect.right():selRect.left(),
00557                                                                           lastPos.y()>firstPos.y()?selRect.bottom():selRect.top());
00558                         }
00559                         update();
00560                         break;
00561                         }
00562                 case noneMode: {
00563                         break;
00564                         }
00565                 }
00566         } else {
00567                 emit mouseLeavesImageArea(FALSE);
00568                 emit newMousePosition(static_cast<float>(event->x()+topLeft.x())/zoom,static_cast<float>(event->y()+topLeft.y())/zoom);
00569         }
00570 }
00571 
00572 
00573 void QVImageArea::mouseReleaseEvent(QMouseEvent *event)
00574 {
00575         //Q_UNUSED(event);
00576         if(mouseMode == dragMode) {
00577                 //setCursor(Qt::OpenHandCursor);
00578         }
00579         dragging = FALSE;
00580         lastPos = event->pos();
00581         switch(mouseMode) {
00582           case dragMode: {
00583                 break;
00584           }
00585           case zoomMode: {
00586                 int newzoom = zoom;
00587                 do {
00588                         newzoom = 2*newzoom;
00589                 } while(newzoom*zoomRect.width() < minimumWidth() or
00590                                 newzoom*zoomRect.height() < minimumHeight());
00591                 if(newzoom <= max_zoom) {
00592                         zoom = newzoom;
00593                         topLeft = zoom*zoomRect.topLeft();
00594                         setMaximumSize(zoom*origwidth,zoom*origheight);
00595                         resize(zoom*zoomRect.width(),zoom*zoomRect.height());
00596                         zoomRect = QRect();
00597                         update();
00598                         emit newGeometry(origwidth,origheight,topLeft.x(),topLeft.y(),width(),height(),zoom);
00599                 } else {
00600                         zoomRect = QRect();
00601                         update();
00602                 }
00603                 break;
00604           }
00605           case selMode: {
00606                 if(firstPos == lastPos) {
00607                         selRect = QRect();
00608                         update();
00609                 }
00610                 break;
00611           }
00612           case noneMode: {
00613                 break;
00614           }
00615         }
00616 }
00617 
00618 void QVImageArea::leaveEvent(QEvent *event)
00619 {
00620         Q_UNUSED(event);
00621         emit mouseLeavesImageArea(TRUE);
00622 }
00623 
00624 
00625 /******************************************************************************/
00626 
00627 void QVCanvas::resizeEvent(QResizeEvent *event)
00628 {
00629         QFontMetrics fm(font());
00630 
00631         int w = event->size().width() - scaleWidgetsFixedWidth - 1;
00632         int h = event->size().height() - scaleWidgetsFixedWidth - statusBarWidgetFixedHeight - 1;
00633         imageArea->setGeometry(scaleWidgetsFixedWidth,scaleWidgetsFixedWidth,w,h);
00634 }
00635 
00636 QString QVCanvas::statusMessage()
00637 {
00638         if(mouseIsOut) {
00639                 return QString("z=%1").arg(imageArea->zoom);
00640         } else {
00641                 return QString("(%1,%2) z=%3").arg(mousePosX).arg(mousePosY).arg(imageArea->zoom);
00642         }
00643 }
00644 
00645 QVCanvas::QVCanvas(QWidget *parent) : QWidget(parent)
00646 {
00647         mouseIsOut = TRUE;
00648         int w = 1, h = 1;
00649         // Scale widgets fixed width proportional to font height:
00650         QFontMetrics fm(font());
00651         scaleWidgetsFixedWidth = 5*fm.height()/3;
00652 
00653         // Scale widgets creation:
00654         scaleWidgetX = new QwtScaleWidget(QwtScaleDraw::TopScale,this);
00655         //scaleWidgetX->setLabelRotation(0.0);
00656         scaleWidgetX->setLabelAlignment(Qt::AlignHCenter|Qt::AlignTop);
00657         scaleWidgetX->setMargin(1);
00658         // Left and right (top & bottom) scaleWidgetsFixedWidth for scale widgets
00659         // (Otherwise, setBorderDist does not work!);
00660         //scaleWidgetX->setBorderDist(scaleWidgetsFixedWidth,0);
00661         scaleWidgetX->setBorderDist(scaleWidgetsFixedWidth,scaleWidgetsFixedWidth);
00662         
00663         scaleWidgetY = new QwtScaleWidget(QwtScaleDraw::LeftScale,this);
00664         scaleWidgetY->setLabelRotation(-90.0);
00665         scaleWidgetY->setLabelAlignment(Qt::AlignVCenter|Qt::AlignTop);
00666         scaleWidgetY->setMargin(1);
00667         // Left and right (top & bottom) scaleWidgetsFixedWidth for scale widgets
00668         // (Otherwise, setBorderDist does not work!);
00669         //scaleWidgetY->setBorderDist(scaleWidgetsFixedWidth,0);
00670         scaleWidgetY->setBorderDist(scaleWidgetsFixedWidth,scaleWidgetsFixedWidth);
00671 
00672         // Scale engines creation:
00673         scaleEngineX = new QwtLinearScaleEngine;
00674         scaleEngineY = new QwtLinearScaleEngine;
00675 
00676         // QVImageArea creation:
00677         if(first_image_area == NULL) {
00678                 // If first instance, create widget with brand new context:
00679                 imageArea = new QVImageArea(w,h,this);
00680                 first_image_area = imageArea;
00681         } else {
00682                 // For the rest of instances, create with the initial context:
00683                 imageArea = new QVImageArea(w,h,this,first_image_area);
00684         }
00685 
00686         statusBar = new QStatusBar(this);
00687         statusBar->addPermanentWidget(buttonZoomIn = new QToolButton(statusBar));
00688         statusBar->addPermanentWidget(buttonZoomOut = new QToolButton(statusBar));
00689         statusBar->addPermanentWidget(buttonZoomOriginal = new QToolButton(statusBar));
00690         statusBar->addPermanentWidget(buttonZoomRect = new QToolButton(statusBar));
00691         statusBar->addPermanentWidget(buttonSelRect = new QToolButton(statusBar));
00692         statusBar->addPermanentWidget(buttonDrag = new QToolButton(statusBar));
00693         buttonZoomIn->setCheckable(FALSE);
00694         buttonZoomIn->setIcon(QIcon(":/images/zoom-in.png"));
00695         buttonZoomOut->setCheckable(FALSE);
00696         buttonZoomOut->setIcon(QIcon(":/images/zoom-out.png"));
00697         buttonZoomOriginal->setCheckable(FALSE);
00698         buttonZoomOriginal->setIcon(QIcon(":/images/zoom-original.png"));
00699         buttonZoomRect->setCheckable(TRUE);
00700         buttonZoomRect->setIcon(QIcon(":/images/zoom-best-fit.png"));
00701         buttonSelRect->setCheckable(TRUE);
00702         buttonSelRect->setIcon(QIcon(":/images/select.png"));
00703         buttonDrag->setCheckable(TRUE);
00704         buttonDrag->setIcon(QIcon(":/images/hand.png"));
00705 
00706         statusBar->showMessage(statusMessage());
00707         statusBarWidgetFixedHeight = statusBar->height();
00708 
00709         setMinimumSize(scaleWidgetsFixedWidth + imageArea->minimumWidth() + 1,
00710                                    scaleWidgetsFixedWidth + imageArea->minimumHeight() + 1 +
00711                                    statusBarWidgetFixedHeight);
00712         setMaximumSize(scaleWidgetsFixedWidth + w + 1,
00713                                    scaleWidgetsFixedWidth + h + 1 +
00714                                    statusBarWidgetFixedHeight);
00715         resize(scaleWidgetsFixedWidth + w + 1,
00716                    scaleWidgetsFixedWidth + h + 1 +
00717                    statusBarWidgetFixedHeight);
00718         connect(imageArea,SIGNAL(newGeometry(int,int,int,int,int,int,int)),
00719                         this,SLOT(setGeometry(int,int,int,int,int,int,int)));
00720         connect(imageArea,SIGNAL(newMousePosition(float,float)),
00721                         this,SLOT(newMousePositionSlot(float,float)));
00722         connect(imageArea,SIGNAL(mouseLeavesImageArea(bool)),
00723                         this,SLOT(mouseLeavesImageAreaSlot(bool)));
00724         connect(buttonZoomRect,SIGNAL(clicked(bool)),this,SLOT(zoomRectClicked(bool)));
00725         connect(buttonSelRect,SIGNAL(clicked(bool)),this,SLOT(selRectClicked(bool)));
00726         connect(buttonDrag,SIGNAL(clicked(bool)),this,SLOT(dragClicked(bool)));
00727         connect(buttonZoomIn,SIGNAL(clicked()),this,SLOT(zoomInClicked()));
00728         connect(buttonZoomOut,SIGNAL(clicked()),this,SLOT(zoomOutClicked()));
00729         connect(buttonZoomOriginal,SIGNAL(clicked()),this,SLOT(zoomOriginalClicked()));
00730 
00731 }
00732 
00733 void QVCanvas::zoomInClicked() {
00734         imageArea->centerZoom(2*imageArea->zoom);
00735 }
00736 
00737 void QVCanvas::zoomOutClicked() {
00738         imageArea->centerZoom(imageArea->zoom/2);
00739 }
00740 
00741 void QVCanvas::zoomOriginalClicked() {
00742         // (Tricky) force redraw at initial size:
00743         int w = imageArea->origwidth, h = imageArea->origheight;
00744         imageArea->origwidth = imageArea->origheight = 0;
00745         QRect saveSelRect = imageArea->selRect;
00746         imageArea->resizeImageArea(w,h);
00747         imageArea->selRect = saveSelRect;
00748 }
00749 
00750 
00751 void QVCanvas::zoomRectClicked(bool checked) {
00752         if(checked)
00753                 imageArea->setCursor(Qt::CrossCursor);
00754         else
00755                 imageArea->setCursor(Qt::ArrowCursor);
00756         imageArea->mouseMode = (checked ? QVImageArea::zoomMode :
00757                                                                           QVImageArea::noneMode);
00758         buttonSelRect->setChecked(false);
00759         buttonDrag->setChecked(false);
00760 }
00761 
00762 void QVCanvas::selRectClicked(bool checked) {
00763         if(checked)
00764                 imageArea->setCursor(Qt::CrossCursor);
00765         else
00766                 imageArea->setCursor(Qt::ArrowCursor);
00767         imageArea->mouseMode = (checked ? QVImageArea::selMode :
00768                                                                           QVImageArea::noneMode);
00769         buttonZoomRect->setChecked(false);
00770         buttonDrag->setChecked(false);
00771 }
00772 
00773 void QVCanvas::dragClicked(bool checked) {
00774         if(checked)
00775                 ;//imageArea->setCursor(Qt::OpenHandCursor);
00776         else
00777                 imageArea->setCursor(Qt::ArrowCursor);
00778 
00779         imageArea->mouseMode = (checked ? QVImageArea::dragMode :
00780                                                                           QVImageArea::noneMode);
00781         buttonSelRect->setChecked(false);
00782         buttonZoomRect->setChecked(false);
00783 }
00784 
00785 
00786 void QVCanvas::newMousePositionSlot(float x,float y) {
00787         mousePosX = x;
00788         mousePosY = y;
00789         statusBar->showMessage(statusMessage());
00790 }
00791 
00792 void QVCanvas::mouseLeavesImageAreaSlot(bool leaves) {
00793 /*      if(leaves)
00794                 std::cout << "SALGO-----------------------------" << std::endl;
00795         else
00796                 std::cout << "ENTRO-----------------------------" << std::endl;*/
00797         mouseIsOut = leaves;
00798         statusBar->showMessage(statusMessage());
00799 }
00800 
00801 
00802 QVCanvas::~QVCanvas()
00803 {
00804         delete scaleEngineX;
00805         delete scaleEngineY;
00806 }
00807 
00808 void QVCanvas::refreshImageArea()
00809 {
00810         imageArea->update();
00811 }
00812 
00813 
00814 void QVCanvas::setGeometry(int origwidth,int origheight,int topleftx,int toplefty,int width,int height, int zoom)
00815 {
00816         Q_UNUSED(origwidth);
00817         Q_UNUSED(origheight);
00818 
00819         QFontMetrics fm(font());
00820 
00821         // virtual QwtScaleDiv divideScale(double x1, double x2,
00822         //     int numMajorSteps, int numMinorSteps, double stepSize=0.0) const
00823         QwtScaleDiv scaleDivX = scaleEngineX->divideScale(
00824                                         ((double)topleftx)/zoom,((double)(topleftx+width))/zoom,
00825                                         qMin(width/zoom+1,static_cast<int>(width/(fm.width("999")))),
00826                                         10,0);
00827         scaleWidgetX->setScaleDiv(scaleEngineX->transformation(),scaleDivX);
00828 
00829         QwtScaleDiv scaleDivY = scaleEngineY->divideScale(
00830                                         ((double)toplefty+height)/zoom,((double)(toplefty))/zoom,
00831                                         qMin(height/zoom+1,static_cast<int>(height/(fm.width("999")))),
00832                                         10,0);
00833         scaleWidgetY->setScaleDiv(scaleEngineY->transformation(),scaleDivY);
00834 
00835 
00836         setMinimumSize(scaleWidgetsFixedWidth + imageArea->minimumWidth() + 1,
00837                                    scaleWidgetsFixedWidth + imageArea->minimumHeight() + 1 +
00838                                    statusBarWidgetFixedHeight);
00839 
00840 
00841 
00842         setMaximumSize(scaleWidgetsFixedWidth+zoom*imageArea->origwidth + 1,
00843                                    scaleWidgetsFixedWidth+zoom*imageArea->origheight + 1 +
00844                                    statusBarWidgetFixedHeight);
00845 
00846         resize(scaleWidgetsFixedWidth+width+1,
00847                         scaleWidgetsFixedWidth+height+1+statusBarWidgetFixedHeight);
00848 
00849         // Left and right (top & bottom) scaleWidgetsFixedWidth for scale widgets
00850         // (Otherwise, setBorderDist does not work!);
00851 
00852         scaleWidgetX->setGeometry(0,0,
00853                 2*scaleWidgetsFixedWidth+width+1,scaleWidgetsFixedWidth);
00854         scaleWidgetY->setGeometry(0,0,
00855                 scaleWidgetsFixedWidth,2*scaleWidgetsFixedWidth+height+1);
00856 
00857         statusBar->setGeometry(
00858                 0,scaleWidgetsFixedWidth+height+1,
00859                 scaleWidgetsFixedWidth+width+1,statusBarWidgetFixedHeight);
00860 
00861         statusBar->showMessage(statusMessage());
00862 
00863 
00864 }

Generated on Thu Mar 13 19:18:16 2008 for QVision by  doxygen 1.5.3