selectionInterface.cpp

Go to the documentation of this file.
00001 //==============================================
00002 //  copyright            : (C) 2003-2005 by Will Stokes
00003 //==============================================
00004 //  This program is free software; you can redistribute it 
00005 //  and/or modify it under the terms of the GNU General 
00006 //  Public License as published by the Free Software 
00007 //  Foundation; either version 2 of the License, or  
00008 //  (at your option) any later version.         
00009 //==============================================
00010 
00011 //Systemwide includes
00012 #include <qsize.h>
00013 #include <qapplication.h>
00014 #include <qpainter.h>
00015 #include <qevent.h>
00016 #include <qpoint.h>
00017 #include <qaccel.h>
00018 #include <qcursor.h>
00019 
00020 //Projectwide includes
00021 #include "selectionInterface.h"
00022 #include "../cursors.h"
00023 #include "../../config.h"
00024 #include "../../backend/tools/imageTools.h"
00025 #include "../window.h"
00026 #include "../../configuration/configuration.h"
00027 
00028 //a mouse press within DRAG_THRESHOLD will move corners or sides
00029 //if mouse press is not within DRAG_THRESHOLD of any corner or side of
00030 //current selection a new selection will be started and both press and drag points will be reset
00031 #define DRAG_THRESHOLD 8
00032 
00033 //a mouse press within MOVE_THRESHOLD of the center along both x and y axis will
00034 //move the entier selection
00035 #define MOVE_THRESHOLD 150
00036 
00037 //minimum size of a valid selection
00038 #define MINIMUM_SELECTION_SIZE 3
00039 
00040 //==============================================
00041 SelectionInterface::SelectionInterface(QWidget *parent, const char* name ) : QWidget(parent,name)
00042 { 
00043   //avoid flicker when repainting
00044   setWFlags(WRepaintNoErase);
00045 
00046   //set default selection off screen
00047   mousePressPoint = QPoint(-1,-1);
00048   mouseDragPoint = QPoint(-1,-1);
00049   
00050   //by default mouse movement does not effect the current selection
00051   currentDragMode = NO_EFFECT;
00052   currentMouseShape = NO_EFFECT;
00053     
00054   QAccel *keyAccel = new QAccel( this );
00055   keyAccel->connectItem( keyAccel->insertItem( CTRL + Key_A),
00056                          this, SLOT(selectAll()) );
00057   keyAccel->connectItem( keyAccel->insertItem( CTRL + SHIFT + Key_A ),
00058                          this, SLOT(selectNone()) );
00059   
00060   //watch mouse movements in order to change mouse cursor
00061   setMouseTracking(true);
00062 
00063   //accept focus when clicked on
00064   setFocusPolicy( QWidget::ClickFocus );
00065   
00066   //initialize cached mouse position to be offscreen by default
00067   cachedMousePosition = QPoint(-1,-1);  
00068 
00069   //no crop size by default
00070   cropMaxDimen = -1.0;
00071 }
00072 //==============================================
00073 SelectionInterface::~SelectionInterface() { }
00074 //==============================================
00075 void SelectionInterface::setPhoto(QString imageFilename, bool resetSelection)
00076 {  
00077   //store original image filename
00078   origImageFilename = imageFilename;
00079 
00080   //store original image dimensions
00081   getImageSize( origImageFilename, origImageSize );
00082     
00083   //resize image to current screen size for faster
00084   //scaling during resize events
00085   QRect screenSize = qApp->desktop()->availableGeometry();
00086   scaleImage( origImageFilename, fullScreenImage, screenSize.width(), screenSize.height() );
00087 
00088   //construct display images  
00089   constructDisplayImages();
00090   
00091   //reset selection area to nothing
00092   if(resetSelection)
00093   {
00094     mousePressPoint = QPoint(-1,-1);
00095     mouseDragPoint  = QPoint(-1,-1);
00096     cropMaxDimen = -1.0;
00097     SHIFT_Pressed = false;
00098     CTRL_Pressed = false;
00099     emit selectionChanged();
00100   }
00101 
00102   //repaint widget
00103   //if we are resetting the selection then aspect ratio may have changed
00104   //so a full repaint (with erase) is necessary
00105   repaint(resetSelection);
00106 }
00107 //==============================================
00108 void SelectionInterface::resizeEvent( QResizeEvent * )
00109 {  
00110   //if image has yet to be set return
00111   if( fullScreenImage.isNull() ) return;
00112   
00113   //construct new images for painting
00114   constructDisplayImages();
00115 }
00116 //==============================================
00117 void SelectionInterface::constructDisplayImages()
00118 {  
00119   //rescale image to fit on screen
00120   scaledImage = fullScreenImage.scale( width(), height(), QImage::ScaleMin );     
00121   
00122   //construct an unselected scaled image
00123   unselectedScaledImage = scaledImage.copy();  
00124   int x, y;
00125   QRgb* rgb;
00126   uchar* scanLine;
00127   for( y=0; y<unselectedScaledImage.height(); y++)
00128   {   
00129     //iterate over each selected pixel in scanline
00130     scanLine = unselectedScaledImage.scanLine(y);
00131     for( x=0; x<unselectedScaledImage.width(); x++)
00132     {
00133       //compress dynamic range to 25% of original
00134       rgb = ((QRgb*)scanLine+x);
00135       
00136       double r = ((double)qRed(*rgb)   )/255.0;
00137       double g = ((double)qGreen(*rgb) )/255.0;
00138       double b = ((double)qBlue(*rgb)  )/255.0;
00139       
00140       //convert to hsv
00141       double h,s,v;
00142       RGBtoHSV(r,g,b,&h,&s,&v);
00143       
00144       //scale and clamp v
00145       v*=0.25;
00146       
00147       //convert adjusted color back to rgb colorspace and clamp
00148       HSVtoRGB( &r,&g,&b, h,s,v);         
00149       int rp = (int) QMIN( QMAX((r*255), 0), 255 );
00150       int gp = (int) QMIN( QMAX((g*255), 0), 255 );
00151       int bp = (int) QMIN( QMAX((b*255), 0), 255 );
00152       
00153       //set adjusted color value
00154       *rgb = qRgb(rp,gp,bp);          
00155     }
00156   }  
00157   
00158   
00159 }
00160 //==============================================
00161 void SelectionInterface::paintEvent(QPaintEvent *e)
00162 {  
00163     //if no scaled image just return
00164   if(scaledImage.isNull()) { return; }
00165     
00166   //create buffer to draw in
00167   QRect rct = rect();
00168   rct.moveBy(-x(), -y());
00169   QPixmap buffer( size() );
00170   
00171   //create a painter pointing to the buffer
00172   QPainter bufferPainter( &buffer );
00173 
00174   //turn off clipping to make painting operations faster
00175   bufferPainter.setClipping(false);
00176   
00177   //initialize buffer with background brush
00178   bufferPainter.fillRect( buffer.rect(), backgroundBrush() );
00179   
00180   //paint the image
00181   int xOffset = (width() - scaledImage.width()) / 2;
00182   int yOffset = (height() - scaledImage.height()) / 2;
00183 
00184   //if in draw line mode paint the image normall and then the currently selected line
00185   //if the two points are set
00186   if(currentDragMode == DRAW_LINE)
00187   {
00188     //paint entire image normally
00189     bufferPainter.drawImage( QPoint(xOffset, yOffset), scaledImage );       
00190 
00191     //if the first and 2nd points have been set draw the line as well
00192     if( mousePressPoint.x() != -1 &&
00193         mouseDragPoint.x() != -1 )
00194     {
00195       //get points in display space
00196       QPoint p1, p2;
00197       p1 = ConvertImageToDisplayCoordinate( mousePressPoint );
00198       p2 = ConvertImageToDisplayCoordinate( mouseDragPoint  );
00199 
00200       //setup painter to use green color
00201       QPen pen;
00202       pen.setStyle( Qt::SolidLine );
00203       pen.setCapStyle( Qt::RoundCap );
00204       pen.setWidth( 2 );
00205       pen.setColor( green );
00206       bufferPainter.setPen( pen);
00207       
00208       //draw line
00209       bufferPainter.drawLine( p1.x(), p1.y(), p2.x(), p2.y() );
00210     }
00211   }
00212   //else we're in normal selection mode
00213   else
00214   {  
00215     //if selected region is empty paint entire image in color
00216     if( mousePressPoint.x() == -1 ||
00217         (
00218          currentDragMode == NO_EFFECT &&
00219          (
00220           mousePressPoint.x() - mouseDragPoint.x() == 0 ||
00221           mousePressPoint.y() - mouseDragPoint.y() == 0 
00222           )
00223          ))
00224     {
00225       bufferPainter.drawImage( QPoint(xOffset, yOffset), scaledImage );       
00226     }
00227     //otherwise paint using a two-pass approach,
00228     //first in monochrome and then the selected region in color
00229     else
00230     {
00231       //first paint using unselected coloring
00232       bufferPainter.drawImage( QPoint(xOffset, yOffset), unselectedScaledImage );
00233       
00234       //construct topLeft and bottomRight points to make logic easier
00235       QPoint topLeft( QMIN(mousePressPoint.x(), mouseDragPoint.x()),
00236                       QMIN(mousePressPoint.y(), mouseDragPoint.y()) );
00237       QPoint bottomRight( QMAX(mousePressPoint.x(), mouseDragPoint.x()),
00238                           QMAX(mousePressPoint.y(), mouseDragPoint.y()) );  
00239       
00240       //convert coordinates from original image space to display space
00241       topLeft = ConvertImageToDisplayCoordinate( topLeft );
00242       bottomRight = ConvertImageToDisplayCoordinate( bottomRight );
00243       
00244       //now paint selected region in color
00245       bufferPainter.drawImage( topLeft.x(), 
00246                                topLeft.y(),
00247                                scaledImage,
00248                                topLeft.x()-xOffset, topLeft.y()-yOffset,
00249                                bottomRight.x() - topLeft.x(),
00250                                bottomRight.y() - topLeft.y() );                                   
00251       
00252       //determine color for painting selection rectangle and dimensions
00253       //use gray/white if cropping to a custom size (and thus real world dimensions
00254       //are not known). If the crop size is known (eg 5"x7") use green if above
00255       //resolution is great enough, otherwise use red to indicate that cropping to
00256       //the specified size will result in pixelation during printing
00257       QPen pen;
00258       QColor selectionColor = gray;
00259       QColor textColor = white;
00260       int selectedWidth = QABS( mouseDragPoint.x() - mousePressPoint.x() ) + 1;
00261       int selectedHeight = QABS( mouseDragPoint.y() - mousePressPoint.y() ) + 1;
00262       if(selectedWidth == 1) selectedWidth = 0;
00263       if(selectedHeight == 1) selectedHeight = 0;
00264       
00265       int DPI = -1;
00266       int minDPI = -1;
00267       if( cropMaxDimen != -1.0 )
00268       {
00269         //compute DPI that will be used in dominant direction
00270         int maxDimen = QMAX( selectedWidth, selectedHeight );
00271         DPI = (int) (maxDimen / cropMaxDimen);          
00272         
00273         //if DPI is below minimum use red color for selection rectangle to indicate pixalation may occur
00274         minDPI = ((Window*)qApp->mainWidget())->getConfig()->getInt( "misc", "minDPI" );      
00275         if( DPI < minDPI ) 
00276         { selectionColor = QColor( 200, 0, 0 ); }
00277         //otherwise use green to signal cropping to this size is safe
00278         else { selectionColor = QColor( 0, 200, 0 ); }
00279       } 
00280       pen.setStyle( Qt::SolidLine );
00281       pen.setWidth( 2 );
00282       bufferPainter.setPen( pen);
00283       
00284       //paint selection size in lower right corner of selected area
00285       QString selectionText;
00286       if( cropMaxDimen != -1.0 &&
00287           DPI < minDPI )
00288         selectionText = QString("%1 x %2 (DPI: %3!)").arg(selectedWidth).arg(selectedHeight).arg(DPI);
00289       else
00290         selectionText = QString("%1 x %2").arg(selectedWidth).arg(selectedHeight);
00291       
00292       QFontMetrics fm( this->font() );
00293       int stringWidth = fm.width(selectionText);
00294       int stringHeight = fm.ascent();
00295       
00296       int textX = 0;
00297       int textY = 0;
00298       const int TEXT_MARGIN = 4;
00299       if( mouseDragPoint.x() > mousePressPoint.x() )
00300       { 
00301         textX = QMIN( xOffset + unselectedScaledImage.width() - TEXT_MARGIN - stringWidth,
00302                       bottomRight.x() + TEXT_MARGIN ); 
00303       }
00304       else
00305       { 
00306         textX = QMAX( xOffset + TEXT_MARGIN, 
00307                       topLeft.x() - TEXT_MARGIN - stringWidth ); 
00308       }
00309       
00310       if( mouseDragPoint.y() > mousePressPoint.y() )
00311       { 
00312         textY = QMIN( yOffset + unselectedScaledImage.height() - TEXT_MARGIN,
00313                       bottomRight.y() + TEXT_MARGIN + stringHeight); 
00314       }
00315       else
00316       { 
00317         textY = QMAX( yOffset + TEXT_MARGIN + stringHeight, 
00318                       topLeft.y() - TEXT_MARGIN ); 
00319       }
00320       
00321       //paint a thin outline around the selection
00322       pen.setColor( selectionColor );
00323       bufferPainter.setPen( pen);
00324       QRect selection( topLeft, bottomRight );
00325       bufferPainter.drawRect(selection);       
00326       
00327       //paint image under selected dimension using selected coloring to help make it more visible
00328       bufferPainter.drawImage( textX, textY-stringHeight,
00329                                unselectedScaledImage,
00330                                textX - xOffset, textY-stringHeight-yOffset,
00331                                stringWidth, fm.height() );
00332       
00333       
00334       //paint selected dimensions    
00335       pen.setColor( textColor );
00336       bufferPainter.setPen( pen);
00337       bufferPainter.drawText( textX, textY, selectionText );
00338     }        
00339   }
00340   
00341   bufferPainter.end();
00342   
00343   //blit buffer to screen
00344   bitBlt( this,
00345           e->rect().x(), e->rect().y(),
00346           &buffer, 
00347           e->rect().x(), e->rect().y(),
00348           e->rect().width(), e->rect().height() );
00349 }
00350 //==============================================
00351 DRAG_MODE SelectionInterface::mouseActionByPosition(QPoint p)
00352 {   
00353   //If SHIFT_Pressed is set then scaling a selection
00354   if(SHIFT_Pressed) { return SCALE_SELECTION; }
00355   
00356   //construct topLeft and bottomRight points to make logic easier
00357   QPoint topLeft( QMIN(mousePressPoint.x(), mouseDragPoint.x()),
00358                   QMIN(mousePressPoint.y(), mouseDragPoint.y()) );
00359   QPoint bottomRight( QMAX(mousePressPoint.x(), mouseDragPoint.x()),
00360                       QMAX(mousePressPoint.y(), mouseDragPoint.y()) );  
00361    
00362   //convert selelection bounary to display space since thresholds are all in display space
00363   topLeft = ConvertImageToDisplayCoordinate( topLeft );
00364   bottomRight = ConvertImageToDisplayCoordinate( bottomRight );
00365     
00366   //compute selection center
00367   QPoint center( (topLeft.x() + bottomRight.x()) / 2,
00368                  (topLeft.y() + bottomRight.y()) / 2);
00369   
00370   //if pointer is not over image no effect will occur when clicking
00371   int xOffset = (width() - scaledImage.width()   ) / 2;
00372   int yOffset = (height() - scaledImage.height() ) / 2;  
00373   if(p.x() < xOffset || p.x() >= scaledImage.width() + xOffset ||
00374      p.y() < yOffset || p.y() >= scaledImage.height() + yOffset )
00375   { return NO_EFFECT; }
00376     
00377   //if either there is no selection or the entire image is selected, new
00378   //mouse clicks are interpreted as being for selecting new regions
00379   if( mousePressPoint.x() == -1 ||
00380       ( bottomRight.x() - topLeft.x() == origImageSize.width() - 1 &&
00381         bottomRight.y() - topLeft.y() == origImageSize.height() - 1 )
00382       )
00383   { return DRAW_SELECTION; }
00384   //move entire selection
00385   //mouse is within MOVE_THRESH of center and outside
00386   //DRAG_THRESH of any side
00387   else if( p.x() >= QMAX( center.x() - MOVE_THRESHOLD, topLeft.x() ) &&
00388            p.x() <= QMIN( center.x() + MOVE_THRESHOLD, bottomRight.x() ) &&
00389            p.y() >= QMAX( center.y() - MOVE_THRESHOLD, topLeft.y() ) &&
00390            p.y() <= QMIN( center.y() + MOVE_THRESHOLD, bottomRight.y() ) &&
00391            p.x() > topLeft.x() + DRAG_THRESHOLD &&
00392            p.x() < bottomRight.x() - DRAG_THRESHOLD &&
00393            p.y() > topLeft.y() + DRAG_THRESHOLD &&
00394            p.y() < bottomRight.y() - DRAG_THRESHOLD )
00395 { return MOVE_SELECTION; } 
00396   //drag top left
00397   else if( QABS(topLeft.x() - p.x()) <= DRAG_THRESHOLD &&
00398            QABS(topLeft.y() - p.y()) <= DRAG_THRESHOLD )  
00399   { return MOVE_TOP_LEFT_CORNER; }
00400   //drag top right    
00401   else if( QABS(bottomRight.x() - p.x()) <= DRAG_THRESHOLD &&
00402            QABS(topLeft.y()     - p.y()) <= DRAG_THRESHOLD )  
00403   { return MOVE_TOP_RIGHT_CORNER; }
00404   //drag bottom left    
00405   else if( QABS(topLeft.x() - p.x()) <= DRAG_THRESHOLD &&
00406            QABS(bottomRight.y() - p.y()) <= DRAG_THRESHOLD )  
00407   { return MOVE_BOTTOM_LEFT_CORNER; }
00408   //drag bottom right
00409   else if( QABS(bottomRight.x() - p.x()) <= DRAG_THRESHOLD &&
00410            QABS(bottomRight.y() - p.y()) <= DRAG_THRESHOLD )  
00411   { return MOVE_BOTTOM_RIGHT_CORNER; }
00412   //drag left
00413   else if( QABS(topLeft.x() - p.x()) <= DRAG_THRESHOLD &&
00414            p.y() >= topLeft.y() &&
00415            p.y() <= bottomRight.y() )
00416   { return MOVE_LEFT_SIDE; }
00417   //drag right
00418   else if( QABS(bottomRight.x() - p.x()) <= DRAG_THRESHOLD &&
00419            p.y() >= topLeft.y() &&
00420            p.y() <= bottomRight.y() )
00421   { return MOVE_RIGHT_SIDE; }
00422   //drag top
00423   else if( QABS(topLeft.y() - p.y()) <= DRAG_THRESHOLD &&
00424            p.x() >= topLeft.x() &&
00425            p.x() <= bottomRight.x() )
00426   { return MOVE_TOP_SIDE; }
00427   //drag bottom
00428   else if( QABS(bottomRight.y() - p.y()) <= DRAG_THRESHOLD &&
00429            p.x() >= topLeft.x() &&
00430            p.x() <= bottomRight.x() )
00431   { return MOVE_BOTTOM_SIDE; }
00432   //else new selection
00433   else { return DRAW_SELECTION; }
00434 }
00435 //==============================================
00436 void SelectionInterface::mousePressEvent(QMouseEvent *e)
00437 {        
00438   //If CTRL pressed then emit ctrlClick event
00439   if( CTRL_Pressed) 
00440   {    
00441     emit ctrlClick();
00442     return;
00443   }
00444   
00445   //get mouse position in original image coordinates
00446   QPoint p = ConvertDisplayToImageCoordinate( e->pos() );
00447 
00448   //in draw line mode a mouse press has not immediate effect, 
00449   //mouse release is how a point is finally selected
00450   if( currentDragMode == DRAW_LINE )
00451   { return; }
00452   
00453   //construct topLeft and bottomRight points to make logic easier
00454   QPoint topLeft( QMIN(mousePressPoint.x(), mouseDragPoint.x()),
00455                   QMIN(mousePressPoint.y(), mouseDragPoint.y()) );
00456   QPoint bottomRight( QMAX(mousePressPoint.x(), mouseDragPoint.x()),
00457                       QMAX(mousePressPoint.y(), mouseDragPoint.y()) );  
00458 
00459   //determine action mouse click will cause
00460   currentDragMode = mouseActionByPosition(e->pos());
00461 
00462   switch(currentDragMode)
00463   {
00464     case DRAW_SELECTION:
00465       mousePressPoint = p;
00466       mouseDragPoint = p;
00467       cropMaxDimen = -1.0;
00468       emit aspectRatioChanged();
00469       break;
00470     case MOVE_SELECTION:
00471       //nothing done until mouse moves
00472       break;
00473     case MOVE_TOP_LEFT_CORNER:
00474       mousePressPoint = bottomRight;
00475       mouseDragPoint = topLeft;
00476       break;
00477     case MOVE_BOTTOM_RIGHT_CORNER:
00478       mousePressPoint = topLeft;
00479       mouseDragPoint = bottomRight;
00480       break;
00481     case MOVE_TOP_RIGHT_CORNER:
00482       mousePressPoint = QPoint( topLeft.x(), bottomRight.y() );
00483       mouseDragPoint = QPoint( bottomRight.x(), topLeft.y() );
00484       break;
00485     case MOVE_BOTTOM_LEFT_CORNER:
00486       mousePressPoint = QPoint( bottomRight.x(), topLeft.y() );
00487       mouseDragPoint = QPoint( topLeft.x(), bottomRight.y() );
00488       break;
00489     case MOVE_LEFT_SIDE:
00490       mousePressPoint = bottomRight;
00491       mouseDragPoint  = topLeft;
00492       break;
00493     case MOVE_RIGHT_SIDE:
00494       mousePressPoint = topLeft;
00495       mouseDragPoint  = bottomRight;
00496       break;
00497     case MOVE_TOP_SIDE:
00498       mousePressPoint = bottomRight;
00499       mouseDragPoint  = topLeft;
00500       break;
00501     case MOVE_BOTTOM_SIDE:
00502       mousePressPoint = topLeft;
00503       mouseDragPoint  = bottomRight;
00504       break;
00505     //no effect
00506     default:
00507       return;
00508   }
00509   
00510   //repaint the selection  
00511   repaint(false);
00512   emit selectionChanged();
00513 }
00514 //==============================================
00515 void SelectionInterface::updateCursorShape( QPoint rawP )
00516 {  
00517   //if resizing a selection always use size all cursor
00518   if(SHIFT_Pressed) 
00519   { 
00520     setCursor( getCursor(SCALE_SELECTION_CURSOR) );
00521     return;
00522   }
00523   
00524   //if ctrl pressed show rotate selection cursor  
00525   if(CTRL_Pressed) 
00526   { 
00527     setCursor( getCursor(ROTATE_CURSOR) );
00528     return;
00529   }
00530    
00531   //if selecting a line the cursor is always the same
00532   if( currentDragMode == DRAW_LINE )
00533   {
00534     setCursor( getCursor(TARGET_CURSOR) );
00535     return;
00536   }
00537   
00538   //update mouse cursor based on coordinates
00539   currentMouseShape = mouseActionByPosition( rawP ); 
00540   switch(currentMouseShape)
00541   {
00542     case DRAW_SELECTION:
00543       setCursor( getCursor(CROSS_CURSOR) ); break;
00544     case MOVE_SELECTION:
00545       setCursor( getCursor(MOVE_SELECTION_CURSOR) ); break;
00546     case MOVE_TOP_LEFT_CORNER:
00547     case MOVE_BOTTOM_RIGHT_CORNER:
00548       setCursor( getCursor(MOVE_TL_CURSOR) ); break;
00549     case MOVE_TOP_RIGHT_CORNER:
00550     case MOVE_BOTTOM_LEFT_CORNER:
00551       setCursor( getCursor(MOVE_TR_CURSOR) ); break;
00552     case MOVE_LEFT_SIDE:
00553     case MOVE_RIGHT_SIDE:
00554       setCursor( getCursor(MOVE_HOR_CURSOR) ); break;
00555     case MOVE_TOP_SIDE:
00556     case MOVE_BOTTOM_SIDE:
00557       setCursor( getCursor(MOVE_VERT_CURSOR) ); break;
00558       break;
00559     default:
00560       setCursor( Qt::ArrowCursor );
00561       break;
00562   }  
00563 }
00564 //==============================================
00565 bool SelectionInterface::scaleSelection( int delta )
00566 {
00567   //construct topLeft and bottomRight points to make logic easier
00568   QPoint topLeft( QMIN(mousePressPoint.x(), mouseDragPoint.x()),
00569                   QMIN(mousePressPoint.y(), mouseDragPoint.y()) );
00570   QPoint bottomRight( QMAX(mousePressPoint.x(), mouseDragPoint.x()),
00571                       QMAX(mousePressPoint.y(), mouseDragPoint.y()) );     
00572 
00573   //compute new selection dimension
00574   int curSelectionWidth = bottomRight.x() - topLeft.x() + 1;
00575   int curSelectionHeight = bottomRight.y()- topLeft.y() + 1;      
00576   int newSelectionWidth = -1; 
00577   int newSelectionHeight = -1;      
00578 
00579   //adjust in dimension of greater resolution
00580   if( curSelectionWidth > curSelectionHeight )
00581   {
00582     newSelectionWidth = QMIN( curSelectionWidth + delta, origImageSize.width() );
00583     newSelectionHeight = (newSelectionWidth * cachedSelectionSize.height()) / cachedSelectionSize.width();
00584   }
00585   else
00586   {
00587     newSelectionHeight = QMIN( curSelectionHeight + delta, origImageSize.height() );
00588     newSelectionWidth = (newSelectionHeight * cachedSelectionSize.width()) / cachedSelectionSize.height();    
00589   }
00590   
00591   //if selection width or height already maxed out then ignore attempt to make selection bigger
00592   if(delta > 0 &&
00593      ( curSelectionWidth == origImageSize.width() ||
00594        curSelectionHeight == origImageSize.height() ) ) 
00595   { 
00596     return false;
00597   }  
00598   
00599   //again prevent from growing too big, now along y-axis
00600   if(newSelectionHeight > origImageSize.height())
00601   {
00602     newSelectionHeight = origImageSize.height();
00603     newSelectionWidth = (newSelectionHeight * cachedSelectionSize.width()) / cachedSelectionSize.height();
00604   }        
00605   
00606   //prevent selection becoming empty
00607   if(newSelectionWidth <= 0 || newSelectionHeight <= 0)
00608   {
00609     newSelectionWidth = curSelectionWidth;
00610     newSelectionHeight = curSelectionHeight;
00611   }
00612   
00613   //center new selection over current selection , move if necessary
00614   topLeft = QPoint(QMAX( cachedSelctionCenter.x() - newSelectionWidth/2, 0 ),
00615                    QMAX( cachedSelctionCenter.y() - newSelectionHeight/2, 0 ));
00616   bottomRight = QPoint( topLeft.x() + newSelectionWidth - 1,
00617                         topLeft.y() + newSelectionHeight - 1 );   
00618   
00619   //too far right
00620   if(bottomRight.x() > origImageSize.width() - 1 )
00621   {
00622     int diff = bottomRight.x() - (origImageSize.width() - 1);        
00623     topLeft.setX( topLeft.x() - diff );
00624     bottomRight.setX( bottomRight.x() - diff );
00625 
00626     //recompute center
00627     cachedSelctionCenter = QPoint( ( mouseDragPoint.x() + mousePressPoint.x() )/2,
00628                                    ( mouseDragPoint.y() + mousePressPoint.y() )/2 );          
00629   }                     
00630   
00631   //too far down
00632   if(bottomRight.y() > origImageSize.height() - 1 )
00633   {
00634     int diff = bottomRight.y() - (origImageSize.height() - 1);        
00635     topLeft.setY( topLeft.y() - diff );
00636     bottomRight.setY( bottomRight.y() - diff );
00637     
00638     //recompute center
00639     cachedSelctionCenter = QPoint( ( mouseDragPoint.x() + mousePressPoint.x() )/2,
00640                                    ( mouseDragPoint.y() + mousePressPoint.y() )/2 );      
00641   }                     
00642   
00643   //set new selection
00644   mousePressPoint = topLeft;
00645   mouseDragPoint = bottomRight;  
00646   
00647   //success
00648   return true;  
00649 }
00650 //==============================================
00651 void SelectionInterface::mouseMoveEvent(QMouseEvent *e)
00652 {
00653   //if the SHIFT_Pressed state variable is true but SHIFT is now not pressed
00654   //reset bool and mouse cursor!
00655   if( SHIFT_Pressed && !(e->state() & Qt::ShiftButton) )
00656   {
00657     SHIFT_Pressed = false;
00658     updateCursorShape( ConvertImageToDisplayCoordinate( e->pos() ) );   
00659   }
00660       
00661   //if the CTRL_Pressed state variable is true but CTRL is now not pressed
00662   //reset bool and mouse cursor!
00663   if( CTRL_Pressed && !(e->state() & Qt::ControlButton) )
00664   {
00665     CTRL_Pressed = false;
00666     updateCursorShape( ConvertImageToDisplayCoordinate( e->pos() ) );   
00667   }  
00668   
00669   //if mouse not pressed update mouse cursor if 
00670   //mode will change if user presses mouse button
00671   if(currentDragMode == NO_EFFECT)
00672   {  
00673     //only update the mouse cursor shape if it will change
00674     if( mouseActionByPosition( e->pos() ) != currentMouseShape )
00675       updateCursorShape( e->pos() );
00676     
00677     cachedMousePosition = ConvertDisplayToImageCoordinate( cropSelectedPoint(e->pos()) );
00678   }
00679   //if currently in draw line mode update the selected line
00680   else if(currentDragMode == DRAW_LINE)
00681   {
00682     //if the 1st point hasn't been set yet do nothing
00683     if( mousePressPoint.x() == -1 )
00684       return;
00685     
00686     //1st point set, set 2nd point to current mouse position and redraw
00687     mouseDragPoint = ConvertDisplayToImageCoordinate( cropSelectedPoint(e->pos()) );
00688 
00689     //repaint the line
00690     repaint(false);
00691   }  
00692   //update selection rectangle or selected line
00693   else
00694   {     
00695     //get mouse position in original image coordinates
00696     QPoint p = ConvertDisplayToImageCoordinate( cropSelectedPoint(e->pos()) );
00697 
00698     //construct topLeft and bottomRight points to make logic easier
00699     QPoint topLeft( QMIN(mousePressPoint.x(), mouseDragPoint.x()),
00700                     QMIN(mousePressPoint.y(), mouseDragPoint.y()) );
00701     QPoint bottomRight( QMAX(mousePressPoint.x(), mouseDragPoint.x()),
00702                         QMAX(mousePressPoint.y(), mouseDragPoint.y()) );     
00703     
00704     //if SHIFT pressed and both selction dimensions non-empty then scale selection
00705     if(SHIFT_Pressed && 
00706        bottomRight.x() > topLeft.x() && 
00707        bottomRight.y() > topLeft.y() )
00708     {
00709       //update width, prevent from growing beyond image boundaries
00710       int delta = p.x() - cachedMousePosition.x(); 
00711       if( !scaleSelection( delta ) )
00712       {
00713         //cache the current mouse position before returning without change
00714         cachedMousePosition = p;
00715         return;
00716       }
00717     }    
00718     //if draging the entire selection, update x and y coordinates for
00719     //both mousePress and mouseDrag points and update the dragSelectionPoint
00720     else if( currentDragMode == MOVE_SELECTION )
00721     {
00722       //compute offset
00723       QPoint offset( p.x() - cachedMousePosition.x(),
00724                      p.y() - cachedMousePosition.y() );
00725       
00726       //construct topLeft and bottomRight points to make logic easier
00727       QPoint topLeft( QMIN(mousePressPoint.x(), mouseDragPoint.x()),
00728                       QMIN(mousePressPoint.y(), mouseDragPoint.y()) );
00729       QPoint bottomRight( QMAX(mousePressPoint.x(), mouseDragPoint.x()),
00730                           QMAX(mousePressPoint.y(), mouseDragPoint.y()) );  
00731       
00732       //clip offset so selected area is always within image boundaries
00733       
00734       //left
00735       if(offset.x() < 0 && topLeft.x() + offset.x() < 0 )
00736         offset.setX( -topLeft.x() );
00737       
00738       //right
00739       if(offset.x() > 0 && bottomRight.x() + offset.x() >= origImageSize.width() )
00740         offset.setX( origImageSize.width() - 1 - bottomRight.x() );          
00741       
00742       //top
00743       if(offset.y() < 0 && topLeft.y() + offset.y() < 0 )
00744         offset.setY( -topLeft.y() );
00745       
00746       //bottom
00747       if(offset.y() > 0 && bottomRight.y() + offset.y() >= origImageSize.height() )
00748         offset.setY( origImageSize.height() - 1 - bottomRight.y() );            
00749       
00750       //update press and drag points
00751       mousePressPoint+= offset;
00752       mouseDragPoint+= offset;      
00753       
00754       //recompute selection center
00755       cachedSelctionCenter = QPoint( ( mouseDragPoint.x() + mousePressPoint.x() )/2,
00756                                      ( mouseDragPoint.y() + mousePressPoint.y() )/2 );          
00757     }        
00758     //if moving any corner or drawing the original selection, 
00759     //update x and y coords of drag point
00760     else if( currentDragMode == DRAW_SELECTION ||
00761              currentDragMode == MOVE_TOP_LEFT_CORNER ||
00762              currentDragMode == MOVE_TOP_RIGHT_CORNER ||
00763              currentDragMode == MOVE_BOTTOM_LEFT_CORNER ||
00764              currentDragMode == MOVE_BOTTOM_RIGHT_CORNER )
00765     {
00766       mouseDragPoint.setX( p.x() );
00767       mouseDragPoint.setY( p.y() );
00768       cropMaxDimen = -1.0;
00769       
00770       //cache selection size and center, necessary for computing next size
00771       cachedSelectionSize = QSize( QABS( mouseDragPoint.x() - mousePressPoint.x() )+1,
00772                                    QABS( mouseDragPoint.y() - mousePressPoint.y() )+1);
00773       cachedSelctionCenter = QPoint( ( mouseDragPoint.x() + mousePressPoint.x() )/2,
00774                                      ( mouseDragPoint.y() + mousePressPoint.y() )/2 );    
00775       
00776       
00777       emit aspectRatioChanged();
00778     }
00779     //else if moving the left or right sides just update the x coordinate of 
00780     //the drag point
00781     else if( currentDragMode == MOVE_LEFT_SIDE ||
00782              currentDragMode == MOVE_RIGHT_SIDE )
00783     {
00784       mouseDragPoint.setX( p.x() );
00785       cropMaxDimen = -1.0;
00786       emit aspectRatioChanged();
00787       
00788       //cache selection size and center, necessary for computing next size
00789       cachedSelectionSize = QSize( QABS( mouseDragPoint.x() - mousePressPoint.x() )+1,
00790                                    QABS( mouseDragPoint.y() - mousePressPoint.y() )+1);                                               
00791       cachedSelctionCenter = QPoint( ( mouseDragPoint.x() + mousePressPoint.x() )/2,
00792                                      ( mouseDragPoint.y() + mousePressPoint.y() )/2 );    
00793     }
00794     //else if moving the top or bottom sides just update the x coordinate of 
00795     //the drag point
00796     else if( currentDragMode == MOVE_TOP_SIDE ||
00797              currentDragMode == MOVE_BOTTOM_SIDE )
00798     {
00799       mouseDragPoint.setY( p.y() );
00800       cropMaxDimen = -1.0;
00801       emit aspectRatioChanged();
00802       
00803       //cache selection size and center, necessary for computing next size
00804       cachedSelectionSize = QSize( QABS( mouseDragPoint.x() - mousePressPoint.x() )+1,
00805                                    QABS( mouseDragPoint.y() - mousePressPoint.y() )+1);                                               
00806       cachedSelctionCenter = QPoint( ( mouseDragPoint.x() + mousePressPoint.x() )/2,
00807                                      ( mouseDragPoint.y() + mousePressPoint.y() )/2 );    
00808       
00809     }    
00810     
00811     //cache current mouse position
00812     cachedMousePosition = p;
00813 
00814     //repaint the selection
00815     repaint(false);
00816     emit selectionChanged();
00817 
00818     //only update the mouse cursor shape if it will change
00819     if( mouseActionByPosition( e->pos() ) != currentMouseShape )
00820       updateCursorShape( e->pos() );
00821   }
00822 }
00823 //==============================================
00824 void SelectionInterface::mouseReleaseEvent(QMouseEvent *e)
00825 {
00826   //if in draw line mode
00827   if( currentDragMode == DRAW_LINE )
00828   {
00829     //get mouse location in image space
00830     QPoint p = ConvertDisplayToImageCoordinate( e->pos() );
00831 
00832     //if first point has not been set set it now
00833     if( mousePressPoint.x() == -1 )
00834     {
00835       mousePressPoint = p;
00836       repaint(false);
00837     }
00838     //else first point has been set then we're setting the 2nd point, emit the selected line
00839     else
00840     {
00841       //get two points on line
00842       QPoint p1 = mousePressPoint;
00843       QPoint p2 = p;
00844       
00845       //reset mode, press and drag points so there is no selection
00846       currentDragMode = NO_EFFECT;
00847       selectNone();
00848       updateCursorShape( ConvertImageToDisplayCoordinate(cachedMousePosition) );   
00849       
00850       //emit the selected line
00851       emit lineSelected( p1, p2 );       
00852     }
00853     return; 
00854   }
00855   
00856   //disable move moving from having an effect on the selection
00857   currentDragMode = NO_EFFECT;
00858   
00859   //construct topLeft and bottomRight points to make logic easier
00860   QPoint topLeft( QMIN(mousePressPoint.x(), mouseDragPoint.x()),
00861                   QMIN(mousePressPoint.y(), mouseDragPoint.y()) );
00862   QPoint bottomRight( QMAX(mousePressPoint.x(), mouseDragPoint.x()),
00863                       QMAX(mousePressPoint.y(), mouseDragPoint.y()) );  
00864 
00865   //convert selection region to display space to check for tiny selections to ignore
00866   topLeft = ConvertImageToDisplayCoordinate( topLeft );
00867   bottomRight = ConvertImageToDisplayCoordinate( bottomRight );
00868   
00869   //if selection is very small reset to select nothing
00870   if( bottomRight.x() - topLeft.x() + 1 < MINIMUM_SELECTION_SIZE ||
00871       bottomRight.y() - topLeft.y() + 1 < MINIMUM_SELECTION_SIZE ) { selectNone(); }  
00872 }
00873 //==============================================
00874 QPoint SelectionInterface::ConvertDisplayToImageCoordinate( QPoint p )
00875 {  
00876   QPoint newPoint = p;
00877   
00878   //remove display offset
00879   int xOffset = (width() - scaledImage.width()   ) / 2;
00880   int yOffset = (height() - scaledImage.height() ) / 2;  
00881   newPoint.setX( newPoint.x() - xOffset );
00882   newPoint.setY( newPoint.y() - yOffset );
00883   
00884   //if coordinate is at max set new value explicitly to avoid roundoff error,
00885   //otherwise scale to full image dimensions
00886   if(newPoint.x() == scaledImage.width() - 1)
00887     newPoint.setX( origImageSize.width() - 1);
00888   else 
00889     newPoint.setX( (int) (0.5 + ((double)(newPoint.x() * (origImageSize.width()-1))) / (scaledImage.width()-1) ) );
00890   
00891   if(newPoint.y() == scaledImage.height() - 1)
00892     newPoint.setY( origImageSize.height() - 1);
00893   else 
00894     newPoint.setY( (int) (0.5 + ((double)(newPoint.y() * (origImageSize.height()-1))) / (scaledImage.height()-1) ) );
00895   
00896   //return point in image coordinates
00897   return newPoint;
00898 }
00899 //==============================================
00900 QPoint SelectionInterface::ConvertImageToDisplayCoordinate( QPoint p )
00901 {       
00902   QPoint newPoint = p;
00903   
00904   //if coordinate is at max set new value explicitly to avoid roundoff error,
00905   //otherwise scale to full image dimensions
00906   if(newPoint.x() == origImageSize.width() - 1)
00907     newPoint.setX( scaledImage.width() - 1);
00908   else 
00909     newPoint.setX( (newPoint.x() * (scaledImage.width()-1)) / (origImageSize.width()-1) );
00910   
00911   if(newPoint.y() == origImageSize.height() - 1)
00912     newPoint.setY( scaledImage.height() - 1);
00913   else 
00914     newPoint.setY( (newPoint.y() * (scaledImage.height()-1)) / (origImageSize.height()-1) );
00915   
00916   //add display offset
00917   int xOffset = (width() - scaledImage.width()   ) / 2;
00918   int yOffset = (height() - scaledImage.height() ) / 2;  
00919   newPoint.setX( newPoint.x() + xOffset );
00920   newPoint.setY( newPoint.y() + yOffset );
00921     
00922   //return point in image coordinates
00923   return newPoint;
00924 }
00925 //==============================================
00926 QPoint SelectionInterface::cropSelectedPoint(QPoint p)
00927 {    
00928   int xOffset = (width() - scaledImage.width()   ) / 2;
00929   int yOffset = (height() - scaledImage.height() ) / 2;
00930 
00931   QPoint croppedPoint;
00932   croppedPoint.setX( QMIN( QMAX(xOffset, p.x()), xOffset + scaledImage.width() - 1 ) );
00933   croppedPoint.setY( QMIN( QMAX(yOffset, p.y()), yOffset + scaledImage.height() - 1 ) );
00934   return croppedPoint;
00935 }
00936 //==============================================
00937 bool SelectionInterface::selectionEmpty()
00938 {
00939   return (
00940           mousePressPoint.x() == -1 ||
00941           mouseDragPoint.x() - mousePressPoint.x() == 0 ||
00942           mouseDragPoint.y() - mousePressPoint.y() == 0
00943          );  
00944 }
00945 //==============================================
00946 void SelectionInterface::selectAll()
00947 {
00948   mousePressPoint.setX( 0 );
00949   mousePressPoint.setY( 0 );
00950   mouseDragPoint.setX( origImageSize.width() - 1 );
00951   mouseDragPoint.setY( origImageSize.height() - 1);
00952 
00953   //cache selection size and center, necessary for computing next size
00954   cachedSelectionSize = QSize( QABS( mouseDragPoint.x() - mousePressPoint.x() )+1,
00955                                QABS( mouseDragPoint.y() - mousePressPoint.y() )+1);           
00956   cachedSelctionCenter = QPoint( ( mouseDragPoint.x() + mousePressPoint.x() )/2,
00957                                  ( mouseDragPoint.y() + mousePressPoint.y() )/2 );      
00958   
00959   cropMaxDimen = -1.0;
00960   repaint(false);
00961   emit selectionChanged();
00962   emit aspectRatioChanged();
00963 }
00964 //==============================================
00965 void SelectionInterface::selectNone()
00966 {
00967   mousePressPoint = QPoint(-1,-1);
00968   mouseDragPoint = QPoint(-1,-1);
00969   cropMaxDimen = -1.0;
00970   repaint(false);
00971   emit selectionChanged();
00972   emit aspectRatioChanged();
00973 }
00974 //==============================================
00975 void SelectionInterface::setSelection(QPoint topLeft, QPoint bottomRight,
00976                                       double cropMaxDimen)
00977 {
00978   mousePressPoint = topLeft;
00979   mouseDragPoint = bottomRight;
00980   
00981   this->cropMaxDimen = cropMaxDimen;
00982   
00983   //cache selection size and center, necessary for computing next size
00984   cachedSelectionSize = QSize( QABS( mouseDragPoint.x() - mousePressPoint.x() )+1,
00985                                QABS( mouseDragPoint.y() - mousePressPoint.y() )+1);           
00986   cachedSelctionCenter = QPoint( ( mouseDragPoint.x() + mousePressPoint.x() )/2,
00987                                  ( mouseDragPoint.y() + mousePressPoint.y() )/2 );    
00988   
00989   repaint(false);
00990   emit selectionChanged();
00991 }
00992 //==============================================
00993 void SelectionInterface::getSelection(QPoint &topLeft, QPoint &bottomRight)
00994 {
00995   //if none selected just return immediately
00996   if(mousePressPoint.x() == -1)
00997   {
00998     topLeft.setX(-1); topLeft.setY(-1);
00999     bottomRight.setX(-1); bottomRight.setY(-1);
01000     return;
01001   }
01002 
01003   //set coordinates based on raw selection  
01004   topLeft.setX( QMIN(mousePressPoint.x(), mouseDragPoint.x()) );
01005   topLeft.setY( QMIN(mousePressPoint.y(), mouseDragPoint.y()) );
01006   bottomRight.setX( QMAX( mousePressPoint.x(), mouseDragPoint.x()) );                
01007   bottomRight.setY( QMAX( mousePressPoint.y(), mouseDragPoint.y()) );                  
01008 }
01009 //==============================================
01010 void SelectionInterface::getDisplaySize(int &width, int &height)
01011 {
01012   width = scaledImage.width();
01013   height = scaledImage.height();  
01014 }
01015 //==============================================
01016 void SelectionInterface::keyPressEvent(QKeyEvent *e)
01017 {
01018   //if currently drawing a line, allow the user
01019   //to escape the current acction by hiting escape, all other
01020   //key presses are ignored
01021   if( currentDragMode == DRAW_LINE )
01022   {
01023     if(e->key() == Qt::Key_Escape )
01024     {
01025       //reset mode, press and drag points so there is no selection, and mouse cursor
01026       currentDragMode = NO_EFFECT;
01027       selectNone();
01028       updateCursorShape( ConvertImageToDisplayCoordinate(cachedMousePosition) );   
01029     
01030       //emit an invalid line
01031       emit lineSelected( QPoint(-1,-1), QPoint(-1,-1) );       
01032     }
01033 
01034     return; 
01035   }
01036   
01037   //if user pressed SHIFT button and selection non-empty 
01038   //then note state change, 
01039   //this will effect resizing selections during drag events
01040   if(e->key() == Qt::Key_Shift && !selectionEmpty() )
01041   {    
01042     SHIFT_Pressed = true;
01043     updateCursorShape( ConvertImageToDisplayCoordinate(cachedMousePosition) );   
01044     return;
01045   }
01046 
01047   //if user pressed CTRL button and selection non-empty 
01048   //then note state change, 
01049   //this will effect mouse clicks by rotating the current selection
01050   if(e->key() == Qt::Key_Control && !selectionEmpty() && !SHIFT_Pressed )
01051   {    
01052     CTRL_Pressed = true;
01053     updateCursorShape( ConvertImageToDisplayCoordinate(cachedMousePosition) );   
01054     return;
01055   }
01056     
01057   //ignore keypress if selection is empty
01058   if(mousePressPoint.x() == -1 ||
01059      mousePressPoint.x() - mouseDragPoint.x() == 0 ||
01060      mousePressPoint.y()  - mouseDragPoint.y() == 0)
01061   {
01062     e->ignore();
01063     return;
01064   }
01065 
01066   //ignore keypresses while mouse button is down since
01067   //intended behavious is unclear
01068   if( currentDragMode != NO_EFFECT )
01069   {
01070     e->ignore();
01071     return;
01072   }
01073   
01074   //-------  
01075   //if += / -_ keys are pressed scale selection
01076   if( e->key() == Qt::Key_Plus ||
01077       e->key() == Qt::Key_Equal ||
01078       e->key() == Qt::Key_Minus ||
01079       e->key() == Qt::Key_Underscore )
01080   {
01081     int delta = 2*QMAX( origImageSize.width(), scaledImage.width() ) / scaledImage.width();
01082     
01083     delta = 1;
01084     
01085     //negate delta if decreasing size
01086     if( e->key() == Qt::Key_Minus ||
01087         e->key() == Qt::Key_Underscore )
01088       delta = -delta;
01089     
01090     if( scaleSelection( delta ) )
01091     {    
01092       //repaint the selection
01093       repaint(false);
01094       emit selectionChanged();
01095     }
01096     return;
01097   }
01098   //-------  
01099   
01100   //find topleft and bottom right of current selection
01101   QPoint topLeft, bottomRight;
01102   topLeft.setX( QMIN(mousePressPoint.x(), mouseDragPoint.x()) );
01103   topLeft.setY( QMIN(mousePressPoint.y(), mouseDragPoint.y()) );
01104   bottomRight.setX( QMAX( mousePressPoint.x(), mouseDragPoint.x()) );                
01105   bottomRight.setY( QMAX( mousePressPoint.y(), mouseDragPoint.y()) );                  
01106   
01107   //compute the number of pixels in the image correspond to one display pixel
01108   //this is the unit by which the selection will be moved
01109   int moveBy = 0;
01110   if( e->key() == Qt::Key_Left ||
01111       e->key() == Qt::Key_Right )
01112   {
01113     moveBy = QMAX( origImageSize.width(), scaledImage.width() ) / scaledImage.width();
01114   }
01115   else
01116   {
01117     moveBy = QMAX( origImageSize.height(), scaledImage.height() ) / scaledImage.height();
01118   }
01119   
01120   //boundary checked moved by value. must be decalred outside switch statement below
01121   int dx = 0;
01122   int dy = 0;
01123   switch( e->key() )
01124   {
01125     case Qt::Key_Left:
01126       dx = QMAX( topLeft.x() - moveBy, 0) - topLeft.x();
01127       break;
01128     case Qt::Key_Right:
01129       dx = QMIN( bottomRight.x() + moveBy, origImageSize.width() - 1) - bottomRight.x();
01130       break;
01131     case Qt::Key_Up:
01132       dy = QMAX( topLeft.y() - moveBy, 0) - topLeft.y();
01133       break;
01134     case Qt::Key_Down:
01135       dy = QMIN( bottomRight.y() + moveBy, origImageSize.height() - 1) - bottomRight.y();
01136       break;
01137     default:
01138       e->ignore();
01139       return;
01140   }
01141   
01142   //shift by dx
01143   mousePressPoint.setX( mousePressPoint.x() + dx );
01144   mouseDragPoint.setX( mouseDragPoint.x() + dx );      
01145  
01146   //shift by dy
01147   mousePressPoint.setY( mousePressPoint.y() + dy );
01148   mouseDragPoint.setY( mouseDragPoint.y() + dy );      
01149 
01150   //recompute center
01151   cachedSelctionCenter = QPoint( ( mouseDragPoint.x() + mousePressPoint.x() )/2,
01152                                  ( mouseDragPoint.y() + mousePressPoint.y() )/2 );    
01153   
01154   //only bother with repaint and updating cursor shape if shift actually occured
01155   if(dx != 0 || dy != 0) 
01156   { 
01157     repaint(false);
01158     updateCursorShape( ConvertImageToDisplayCoordinate(cachedMousePosition) );  
01159   }
01160 }
01161 //==============================================
01162 void SelectionInterface::keyReleaseEvent(QKeyEvent *e)
01163 {
01164   //if user released SHIFT button then note state change, 
01165   //this will effect resizing selections during drag events
01166   if(e->key() == Qt::Key_Shift)
01167   {
01168     SHIFT_Pressed = false;
01169     updateCursorShape( ConvertImageToDisplayCoordinate(cachedMousePosition) );   
01170   }
01171   //if user released CTRL button then note state change, 
01172   //this will effect mouse clicks
01173   else  if(e->key() == Qt::Key_Control)
01174   {
01175     CTRL_Pressed = false;
01176     updateCursorShape( ConvertImageToDisplayCoordinate(cachedMousePosition) );   
01177   }
01178   //unhandled key press: pass up the object tree
01179   else { e->ignore(); }
01180 }
01181 //==============================================
01182 void SelectionInterface::enterDrawLineMode()
01183 {
01184   //set the current mode
01185   currentDragMode = DRAW_LINE;
01186 
01187   //during draw line mode ignore control and shift keys, they are only useful for adjusting
01188   //selections, not lines
01189   SHIFT_Pressed = false;
01190   CTRL_Pressed = false;
01191   
01192   //reset 1st point
01193   mousePressPoint = QPoint( -1, -1 );
01194   mouseDragPoint = QPoint( -1, -1 );
01195   
01196   //repaint and reset the mouse cursor
01197   updateCursorShape( ConvertImageToDisplayCoordinate(cachedMousePosition) );   
01198   repaint(false);
01199 }
01200 //==============================================
01201 

Generated on Wed Jan 24 05:38:28 2007 for AlbumShaper by  doxygen 1.5.1