editingInterface.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 <qlayout.h>
00013 #include <qlabel.h>
00014 #include <qfont.h>
00015 #include <qframe.h>
00016 #include <qsize.h>
00017 #include <qtoolbutton.h>
00018 #include <qimage.h>
00019 #include <qcursor.h>
00020 #include <qapplication.h>
00021 #include <math.h>
00022 #include <qtooltip.h>
00023 #include <qhgroupbox.h>
00024 #include <qpushbutton.h>
00025 #include <qcombobox.h>
00026 #include <math.h>
00027 
00028 //Projectwide includes
00029 #include "../clickableLabel.h"
00030 #include "editingInterface.h"
00031 #include "selectionInterface.h"
00032 #include "histogramEditor.h"
00033 #include "grainEditor.h"
00034 #include "manipulations/mosaicOptionsDialog.h"
00035 #include "../statusWidget.h"
00036 #include "../layoutWidget.h"
00037 #include "../window.h"
00038 #include "../titleWidget.h"
00039 #include "../dialogs/questionDialog.h"
00040 #include "../../config.h"
00041 #include "../../backend/album.h"
00042 #include "../../backend/subalbum.h"
00043 #include "../../backend/photo.h"
00044 #include "../../backend/tools/fileTools.h"
00045 #include "../../backend/tools/imageTools.h"
00046 
00047 #include "../../backend/enhancements/color.h"
00048 #include "../../backend/enhancements/contrast.h"
00049 #include "../../backend/enhancements/redEye.h"
00050 #include "../../backend/enhancements/tilt.h"
00051 
00052 #include "../../backend/manipulations/manipulationOptions.h"
00053 #include "../../backend/manipulations/blackWhite.h"
00054 #include "../../backend/manipulations/crop.h"
00055 #include "../../backend/manipulations/emboss.h"
00056 #include "../../backend/manipulations/invert.h"
00057 #include "../../backend/manipulations/mosaic.h"
00058 #include "../../backend/manipulations/painting.h"
00059 #include "../../backend/manipulations/pointillism.h"
00060 #include "../../backend/manipulations/sepia.h"
00061 
00062 #include "../../configuration/configuration.h"
00063 
00064 #define EFFECT_PREVIEW_WIDTH 107
00065 #define EFFECT_PREVIEW_HEIGHT 80
00066 
00067 #include <iostream>
00068 using namespace std;
00069 
00070 //==============================================
00071 EditingInterface::EditingInterface(QWidget *parent, const char* name ) 
00072                                  : QWidget(parent,name)
00073 {
00074   //create a smaller font for drawing various labels and items
00075   QFont smallerFont = font();
00076   smallerFont.setPointSize( smallerFont.pointSize() - 1 );  
00077 
00078   setFocusPolicy(QWidget::StrongFocus);
00079 
00080   //set photo pointer to null by default
00081   photo = NULL;
00082 
00083   //store layout pointer
00084   layout = (LayoutWidget*)parent;
00085 
00086   //----------  
00087   //Construct photo frame that houses photo being edited and prev and next buttons
00088   QFrame* photoFrame = new QFrame(this, "photoFrame" );
00089   
00090   //Construct the frame that houses all the controls
00091   QFrame* controlsFrame = new QFrame(this, "controlsFrame");
00092 
00093   //Place photo fram and control widgets in a top level grid
00094   QGridLayout* mainGrid = new QGridLayout( this, 3, 3, 0 );
00095   mainGrid->addWidget( photoFrame, 0, 1 );
00096   mainGrid->setRowStretch(0, 1);
00097   mainGrid->addMultiCellWidget( controlsFrame, 1,1, 0,2 );
00098   mainGrid->setRowSpacing( 2, WIDGET_SPACING );
00099   //----------  
00100   //Previous photo button
00101   previousButton = new ClickableLabel( photoFrame, "previousButton" );
00102   previousButton->setPixmap( QPixmap(QString(IMAGE_PATH)+"buttonIcons/previous.png") ); 
00103   connect( previousButton, SIGNAL(clicked()), SLOT(showPrevPhoto()) );    
00104 
00105   //Create widget for displaying and selecting regions of the current photo
00106   selectionInterface = new SelectionInterface( photoFrame, "selectionInterface" );
00107   connect( selectionInterface, SIGNAL( selectionChanged() ), this, SLOT( handleSelectionChanged() ) );
00108   connect( selectionInterface, SIGNAL( aspectRatioChanged() ), this, SLOT( handleAspectRatioChanged() ) );
00109   connect( selectionInterface, SIGNAL( ctrlClick() ), this, SLOT( rotateSelection() ) );
00110   
00111   //Next photo button
00112   nextButton = new ClickableLabel( photoFrame, "nextButton" );
00113   nextButton->setPixmap( QPixmap(QString(IMAGE_PATH)+"buttonIcons/next.png") ); 
00114   connect( nextButton, SIGNAL(clicked()), SLOT(showNextPhoto()) );    
00115 
00116   //Place above widgets in grid, allow seletion interface to take up extra room
00117   QGridLayout* selectionGrid = new QGridLayout( photoFrame, 1, 5, 0 );
00118   selectionGrid->setColSpacing( 0, WIDGET_SPACING );
00119   selectionGrid->addWidget( previousButton,     0, 1, Qt::AlignCenter );
00120   selectionGrid->addWidget( selectionInterface, 0, 2 );
00121   selectionGrid->setColStretch( 2, 1 );
00122   selectionGrid->addWidget( nextButton,         0, 3, Qt::AlignCenter );
00123   selectionGrid->setColSpacing( 4, WIDGET_SPACING );
00124   selectionGrid->setSpacing( WIDGET_SPACING );
00125   //-----------
00126   //construct the frames each set of controls is placed in
00127   QHGroupBox* frameControls   = new QHGroupBox( tr("Frame"),   controlsFrame, "frameControls"   );
00128   frameControls->setAlignment( Qt::AlignHCenter );
00129   frameControls->setInsideMargin( WIDGET_SPACING );
00130 
00131   QHGroupBox* enhanceControls = new QHGroupBox( tr("Enhance"), controlsFrame, "enhanceControls" );
00132   enhanceControls->setAlignment( Qt::AlignHCenter ); 
00133   enhanceControls->setInsideMargin( WIDGET_SPACING );
00134   
00135   QHGroupBox* manipulateControls = new QHGroupBox( tr("Manipulate"), controlsFrame, "applyEffect" );
00136   manipulateControls->setAlignment( Qt::AlignHCenter );
00137   manipulateControls->setInsideMargin( WIDGET_SPACING );
00138       
00139   //layout groups of controls
00140   QGridLayout* controlsGrid = new QGridLayout( controlsFrame, 1, 5, 0 );
00141   controlsGrid->addWidget( frameControls,      0, 1 );  
00142   controlsGrid->addWidget( enhanceControls,    0, 2 );  
00143   controlsGrid->addWidget( manipulateControls, 0, 3 );  
00144   
00145   controlsGrid->setSpacing( WIDGET_SPACING );    
00146   controlsGrid->setColSpacing(0, WIDGET_SPACING );
00147   controlsGrid->setColStretch(0, 1);
00148   controlsGrid->setColSpacing(4, WIDGET_SPACING );
00149   controlsGrid->setColStretch(4, 1);
00150   
00151   //----------   
00152   //Frame Controls
00153   //----------    
00154   QFrame* frameControlsFrame = new QFrame( frameControls );
00155  
00156   //-----
00157   //rotate and flip buttons
00158   QFrame* rotateFlipFrame = new QFrame( frameControlsFrame );
00159   
00160   QToolButton* rotateRightButton = new QToolButton( rotateFlipFrame, "rotateRight" );
00161   rotateRightButton->setIconSet( QPixmap(QString(IMAGE_PATH)+"buttonIcons/rotate90.png") );
00162   rotateRightButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
00163   connect( rotateRightButton, SIGNAL(clicked()), SLOT(rotateRight()) );
00164   QToolTip::add( rotateRightButton, tr("Rotate clockwise") );  
00165   
00166   QToolButton* rotateLeftButton = new QToolButton( rotateFlipFrame, "rotateLeft" );
00167   rotateLeftButton->setIconSet( QPixmap(QString(IMAGE_PATH)+"buttonIcons/rotate270.png") ); 
00168   rotateLeftButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
00169   connect( rotateLeftButton, SIGNAL(clicked()), SLOT(rotateLeft()) );
00170   QToolTip::add( rotateLeftButton, tr("Rotate counterclockwise") );  
00171 
00172   QToolButton* flipHorizontalButton = new QToolButton( rotateFlipFrame, "flipHorizontal" );
00173   flipHorizontalButton->setIconSet( QPixmap(QString(IMAGE_PATH)+"buttonIcons/flipHorizontally.png") );
00174   flipHorizontalButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
00175   connect( flipHorizontalButton, SIGNAL(clicked()), SLOT(flipHorizontal()) );
00176   QToolTip::add( flipHorizontalButton, tr("Flip horizontally") );  
00177   
00178   QToolButton* flipVerticalButton = new QToolButton( rotateFlipFrame, "flipVertical" );
00179   flipVerticalButton->setIconSet( QPixmap(QString(IMAGE_PATH)+"buttonIcons/flipVertically.png") ); 
00180   flipVerticalButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
00181   connect( flipVerticalButton, SIGNAL(clicked()), SLOT(flipVertical()) );  
00182   QToolTip::add( flipVerticalButton, tr("Flip vertically") );  
00183   
00184   correctTiltButton = new QToolButton( rotateFlipFrame, "correctTilt" );
00185   correctTiltButton->setIconSet( QPixmap(QString(IMAGE_PATH)+"buttonIcons/correctTilt.png") ); 
00186   correctTiltButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
00187   
00188   connect( correctTiltButton, SIGNAL(clicked()), SLOT(startCorrectTilt()) );
00189 
00190   connect( selectionInterface, SIGNAL(lineSelected(QPoint, QPoint)),
00191            this, SLOT(finishCorrectTilt( QPoint, QPoint)) );
00192 
00193   QToolTip::add( correctTiltButton, tr("Correct tilt") );  
00194 
00195   //Place buttons in grid
00196   QGridLayout* rotateFlipGrid = new QGridLayout( rotateFlipFrame, 1, 5, 0 );
00197   rotateFlipGrid->setSpacing(TIGHT_WIDGET_SPACING);  
00198   rotateFlipGrid->addWidget( rotateRightButton,    0, 0 );
00199   rotateFlipGrid->addWidget( rotateLeftButton,     0, 1 );
00200   rotateFlipGrid->addWidget( flipHorizontalButton, 0, 2 );
00201   rotateFlipGrid->addWidget( flipVerticalButton,   0, 3 );
00202   rotateFlipGrid->addWidget( correctTiltButton,    0, 4 );
00203   //-----
00204   //aspect ratio selection and crop controls
00205   aspectRatios = new QComboBox( frameControlsFrame );
00206   aspectRatios->setFont( smallerFont );
00207   connect( aspectRatios, SIGNAL(activated(int)), this, SLOT(selectAspectRatio()) );  
00208   aspectRatioValues = new QSize[8];
00209   maxDimensions = new double[8];
00210   int curAspectRatio = 0;
00211   //--
00212   aspectRatios->insertItem( tr("Custom") );
00213   maxDimensions[curAspectRatio] = -1.0;
00214   aspectRatioValues[curAspectRatio++] = QSize( -1, -1 );
00215   //--  
00216   aspectRatios->insertItem( tr("Photo (3.5 x 5)") );
00217   maxDimensions[curAspectRatio] = 5.0;
00218   aspectRatioValues[curAspectRatio++] = QSize( 10, 7 );
00219   //--  
00220   aspectRatios->insertItem( tr("Photo (4 x 6)") );
00221   maxDimensions[curAspectRatio] = 6.0;
00222   aspectRatioValues[curAspectRatio++] = QSize( 6, 4 );
00223   //--  
00224   aspectRatios->insertItem( tr("Photo (5 x 7)") );
00225   maxDimensions[curAspectRatio] = 7.0;
00226   aspectRatioValues[curAspectRatio++] = QSize( 7, 5 );
00227   //--  
00228   aspectRatios->insertItem( tr("Photo (8 x 10)") );
00229   maxDimensions[curAspectRatio] = 10.0;
00230   aspectRatioValues[curAspectRatio++] = QSize( 10, 8 );
00231   //--  
00232   aspectRatios->insertItem( tr("Postcard") );
00233   maxDimensions[curAspectRatio] = 6.0;
00234   aspectRatioValues[curAspectRatio++] = QSize( 6, 4 );
00235   //--  
00236   aspectRatios->insertItem( tr("Wallet") );
00237   maxDimensions[curAspectRatio] = 3.0;
00238   aspectRatioValues[curAspectRatio++] = QSize( 3, 2 );
00239   //--  
00240   aspectRatios->insertItem( tr("Desktop") );
00241   displayResolutionIndex = curAspectRatio;
00242   maxDimensions[curAspectRatio] = -1.0;
00243   aspectRatioValues[curAspectRatio++] = qApp->desktop()->screenGeometry().size();
00244   //--  
00245   //connect signal emitted when screen resolution changes 
00246   //so as to update this stored value (and selction if necessary)
00247   connect( qApp->desktop(), SIGNAL( resized(int)), this, SLOT(screenResolutionChanged()) );
00248 
00249   QToolTip::add( aspectRatios, tr("Select region for cropping using a particular aspect ratio") );  
00250 
00251   QLabel* aspectRatioLabel = new QLabel( tr("Aspect Ratio"), frameControlsFrame );
00252   aspectRatioLabel->setFont( smallerFont );
00253   //--
00254 
00255   //Crop button
00256   cropButton = new QToolButton( frameControlsFrame );
00257   QIconSet cropIcon;
00258   cropIcon.setPixmap( QString(IMAGE_PATH)+"buttonIcons/crop.png",
00259                       QIconSet::Automatic,
00260                       QIconSet::Normal );
00261                        
00262   cropIcon.setPixmap( QString(IMAGE_PATH)+"buttonIcons/crop_disabled.png",
00263                       QIconSet::Automatic,
00264                       QIconSet::Disabled );
00265   cropButton->setIconSet( cropIcon );
00266   connect( cropButton, SIGNAL(clicked()), SLOT(crop()) );
00267   QToolTip::add( cropButton, tr("Crop photo to selected region") );  
00268 
00269   QLabel* cropLabel = new QLabel( tr("Crop"), frameControlsFrame );
00270   cropLabel->setFont( smallerFont );  
00271   
00272   //--  
00273 
00274   //Place frame controls in a grid
00275   QGridLayout* frameControlsGrid = new QGridLayout( frameControlsFrame, 3, 2, 0 );
00276   frameControlsGrid->setSpacing(TIGHT_WIDGET_SPACING);  
00277   frameControlsGrid->addMultiCellWidget( rotateFlipFrame, 0,0,  0,1 );
00278   frameControlsGrid->addWidget( aspectRatios,     1, 0, Qt::AlignHCenter );  
00279   frameControlsGrid->addWidget( cropButton,       1, 1, Qt::AlignHCenter );  
00280   frameControlsGrid->addWidget( aspectRatioLabel, 2, 0, Qt::AlignHCenter );  
00281   frameControlsGrid->addWidget( cropLabel,        2, 1, Qt::AlignHCenter );    
00282 
00283   //----------  
00284   //Enhance Controls
00285   //----------    
00286   QFrame* enhanceControlsFrame = new QFrame( enhanceControls );  
00287   
00288   //setup params for large buttons  
00289   int numLargeButtons = 3;
00290   int curButtonIndex=0;
00291   ClickableLabel** largeButtons = new ClickableLabel*[numLargeButtons];
00292   
00293 
00294   //--------------------
00295   //Frame for semi-automatic enhance controls
00296   QFrame* autoEnhanceControlsFrame = new QFrame( enhanceControlsFrame );  
00297 
00298   //Enhance Color
00299   ClickableLabel* enhanceColorButton = largeButtons[curButtonIndex] = 
00300     new ClickableLabel( autoEnhanceControlsFrame );
00301   largeButtons[curButtonIndex]->setPixmap( QPixmap(QString(IMAGE_PATH)+"buttonIcons/improveColorBalance.png") );
00302   connect( largeButtons[curButtonIndex], SIGNAL(clicked()), SLOT(colorBalance()) );
00303   QToolTip::add( largeButtons[curButtonIndex], tr("Enhance color balance") );  
00304   curButtonIndex++;
00305 
00306   QLabel* enhanceColorLabel = new QLabel( tr("Color"), autoEnhanceControlsFrame );
00307   enhanceColorLabel->setFont( smallerFont );  
00308   
00309   //Enhance Contrast
00310   ClickableLabel* enhanceContrastButton = largeButtons[curButtonIndex] = 
00311     new ClickableLabel( autoEnhanceControlsFrame );
00312   largeButtons[curButtonIndex]->setPixmap( QPixmap(QString(IMAGE_PATH)+"buttonIcons/enhanceContrast.png") );
00313   connect( largeButtons[curButtonIndex], SIGNAL(clicked()), SLOT(enhanceContrast()) );
00314   QToolTip::add( largeButtons[curButtonIndex], tr("Enhance contrast") );  
00315   curButtonIndex++;
00316   
00317   QLabel* enhanceContrastLabel = new QLabel( tr("Contrast"), autoEnhanceControlsFrame );
00318   enhanceContrastLabel->setFont( smallerFont );  
00319 
00320   //Remove Red-Eye  
00321   redEyeReductionButton = largeButtons[curButtonIndex] = new ClickableLabel( autoEnhanceControlsFrame );
00322   redEyeReductionButton->setEnabled( false );
00323   
00324   largeButtons[curButtonIndex]->setPixmap( QPixmap( QString(IMAGE_PATH)+"buttonIcons/redEyeReduction.png" ) );
00325   connect( largeButtons[curButtonIndex], SIGNAL(clicked()), SLOT(removeRedeye()) );
00326   QToolTip::add( largeButtons[curButtonIndex], tr("Remove red-eye") );  
00327   curButtonIndex++;
00328 
00329   QLabel* removeRedyEyeLabel = new QLabel( tr("Red Eye"), autoEnhanceControlsFrame );
00330   removeRedyEyeLabel->setFont( smallerFont );  
00331 
00332   //Place semi-automatic enhance controls in grid
00333   QGridLayout* autoEnhanceControlsGrid = new QGridLayout( autoEnhanceControlsFrame, 2, 3, 0 );
00334   autoEnhanceControlsGrid->setSpacing(TIGHT_WIDGET_SPACING);  
00335   autoEnhanceControlsGrid->addWidget( enhanceColorButton,    0, 0, Qt::AlignHCenter );
00336   autoEnhanceControlsGrid->addWidget( enhanceColorLabel,     1, 0, Qt::AlignHCenter );  
00337 
00338   autoEnhanceControlsGrid->addWidget( enhanceContrastButton, 0, 1, Qt::AlignHCenter );
00339   autoEnhanceControlsGrid->addWidget( enhanceContrastLabel,  1, 1, Qt::AlignHCenter );  
00340 
00341   autoEnhanceControlsGrid->addWidget( redEyeReductionButton, 0, 2, Qt::AlignHCenter );
00342   autoEnhanceControlsGrid->addWidget( removeRedyEyeLabel,    1, 2, Qt::AlignHCenter );  
00343   //--------------------
00344   //Frame for more labor intensive enhance controls
00345   QFrame* manualEnhanceControlsFrame = new QFrame( enhanceControlsFrame );  
00346   
00347   //Tune Levels Button
00348   ClickableLabel* tuneLevelsButton = new ClickableLabel( manualEnhanceControlsFrame );
00349   tuneLevelsButton->setPixmap( QPixmap(QString(IMAGE_PATH)+"buttonIcons/tuneLevels.png") );
00350   connect( tuneLevelsButton, SIGNAL(clicked()), SLOT(tuneLevels()) );
00351   QToolTip::add( tuneLevelsButton, tr("Fine tune brightness, contrast, and colors") );  
00352   
00353   QLabel* tuneLevelsLabel = new QLabel( tr("Levels..."), manualEnhanceControlsFrame );
00354   tuneLevelsLabel->setFont( smallerFont );  
00355 
00356   //Adjust Grain Button
00357   ClickableLabel* adjustGrainButton = new ClickableLabel( manualEnhanceControlsFrame );
00358   adjustGrainButton->setPixmap( QPixmap(QString(IMAGE_PATH)+"buttonIcons/adjustGrain.png") );
00359   connect( adjustGrainButton, SIGNAL(clicked()), SLOT(adjustGrain()) );
00360   QToolTip::add( adjustGrainButton, tr("Blur or sharpen image") );  
00361 
00362   QLabel* adjustGrainLabel = new QLabel( tr("Grain..."), manualEnhanceControlsFrame );
00363   adjustGrainLabel->setFont( smallerFont );  
00364 
00365   //Place manual enhance controls in grid
00366   QGridLayout* manualEnhanceControlsGrid = new QGridLayout( manualEnhanceControlsFrame, 2, 3, 0 );
00367   manualEnhanceControlsGrid->setSpacing(TIGHT_WIDGET_SPACING);  
00368   manualEnhanceControlsGrid->addWidget( tuneLevelsButton,    0, 0, Qt::AlignHCenter );
00369   manualEnhanceControlsGrid->addWidget( tuneLevelsLabel,     1, 0, Qt::AlignHCenter );
00370   manualEnhanceControlsGrid->setColSpacing( 1, WIDGET_SPACING );
00371   manualEnhanceControlsGrid->addWidget( adjustGrainButton, 0, 2, Qt::AlignHCenter );
00372   manualEnhanceControlsGrid->addWidget( adjustGrainLabel,  1, 2, Qt::AlignHCenter );
00373   //--------------------
00374 
00375   //Place enhance controls in a grid
00376   QGridLayout* enhanceControlsGrid = new QGridLayout( enhanceControlsFrame, 4, 2, 0 );
00377   enhanceControlsGrid->setSpacing(WIDGET_SPACING);  
00378   enhanceControlsGrid->addWidget( autoEnhanceControlsFrame,   0, 0, Qt::AlignHCenter );
00379   enhanceControlsGrid->addWidget( manualEnhanceControlsFrame, 1, 0, Qt::AlignHCenter );
00380   enhanceControlsGrid->setRowStretch( 0, 1 );
00381   enhanceControlsGrid->setRowStretch( 3, 1 );
00382   
00383   //----------  
00384   //Effects Controls
00385   //----------  
00386   QFrame* manipulateControlsFrame = new QFrame( manipulateControls, "manipulateControlsFrame" );
00387   //--  
00388   //Effects
00389   effectsList = new QComboBox( manipulateControlsFrame );
00390   effectsList->setFont( smallerFont );  
00391   connect( effectsList, SIGNAL(activated(int)), this, SLOT(selectEffect()) );
00392 
00393   int i;
00394   for(i=0; i<NUM_MANIPULATIONS; i++)
00395   {
00396     switch(i)
00397     {
00398       case BW_EFFECT:          effectsList->insertItem( tr("B + W") );       break;
00399       case SEPIA_EFFECT:       effectsList->insertItem( tr("Sepia") );       break;
00400       case INVERT_EFFECT:      effectsList->insertItem( tr("Invert") );      break;
00401       case EMBOSS_EFFECT:      effectsList->insertItem( tr("Emboss") );      break;
00402       case MOSAIC_EFFECT:      effectsList->insertItem( tr("Mosaic") );       break;
00403       case PAINTING_EFFECT:    effectsList->insertItem( tr("Painting") );    break;
00404       case POINTILLISM_EFFECT: effectsList->insertItem( tr("Pointillism") ); break;
00405     }
00406   }
00407 
00408   //Apply effect button
00409   applyEffectButton = new QPushButton( tr("Apply"), manipulateControlsFrame );
00410   applyEffectButton->setFont( smallerFont );  
00411   connect( applyEffectButton, SIGNAL(clicked()), SLOT(applyEffect()) );   
00412   
00413   //preview of seleted effect
00414   effectPreview = new QLabel( manipulateControlsFrame );
00415  
00416   //Place effects controls in a grid
00417   QGridLayout* manipulateControlsGrid = new QGridLayout( manipulateControlsFrame, 2, 2, 0 );
00418   manipulateControlsGrid->setSpacing(TIGHT_WIDGET_SPACING);  
00419   manipulateControlsGrid->addWidget( effectsList, 0, 0 );
00420   manipulateControlsGrid->addWidget( applyEffectButton, 1, 0, Qt::AlignHCenter );  
00421   manipulateControlsGrid->addMultiCellWidget( effectPreview, 0,1, 1,1, Qt::AlignHCenter );  
00422 
00423   //make sure preview image always requires EFFECT_PREVIEW_WIDTH width so contorls don't
00424   //move around when rotating photos
00425   manipulateControlsGrid->setColSpacing(1, 85 );
00426 }
00427 //==============================================
00428 EditingInterface::~EditingInterface() { }
00429 //==============================================
00430 Photo* EditingInterface::getPhoto() { return photo; }
00431 //==============================================
00432 void EditingInterface::setPhoto(Subalbum* collection, Photo* photo)
00433 {
00434   //store photo and collection object handles
00435   this->collection = collection;
00436   this->photo = photo;
00437 
00438   //update visibility of prev and next buttons
00439   previousButton->setInvisible( photo->getPrev() == NULL );
00440   nextButton->setInvisible( photo->getNext() == NULL );
00441   
00442   //reset combo menu's back to first entries
00443   aspectRatios->setCurrentItem(0);
00444   effectsList->setCurrentItem(0);
00445 
00446   //reset selectionRotated bool to false
00447   selectionRotated = false;
00448   
00449   //update view of photo
00450   selectionInterface->setPhoto( photo->getImageFilename() );  
00451  
00452   //created effect preview image  
00453   effectPreviewImageFilename = ((Window*)qApp->mainWidget())->getTitle()->getAlbum()->getTmpDir() + 
00454                                "/effectPreviewImage.jpg";
00455   scaleImage( photo->getImageFilename(), effectPreviewImageFilename, EFFECT_PREVIEW_WIDTH, EFFECT_PREVIEW_HEIGHT );
00456   selectEffect();
00457   
00458   //get full size photo dimensions
00459   getImageSize( photo->getImageFilename(), imageWidth, imageHeight );
00460   
00461   //get display size photo dimensions
00462   selectionInterface->getDisplaySize( displayWidth, displayHeight );
00463 
00464   //disable the crop and reset buttons
00465   cropButton->setEnabled( false );
00466   redEyeReductionButton->setEnabled( false );  
00467 }
00468 //==============================================
00469 void EditingInterface::showPrevPhoto()
00470 { 
00471   Photo* prevPhoto = photo->getPrev();
00472 
00473   if( prevPhoto != NULL && 
00474       prevPhoto != photo )
00475   { showNextPrevFirstLastPhoto( prevPhoto ); }
00476 }
00477 //==============================================
00478 void EditingInterface::showNextPhoto()
00479 { 
00480   Photo* nextPhoto = photo->getNext();
00481 
00482   if( nextPhoto != NULL &&
00483       nextPhoto != photo )
00484   { showNextPrevFirstLastPhoto( nextPhoto ); }
00485 }  
00486 //==============================================
00487 void EditingInterface::showFirstPhoto()
00488 { 
00489   Photo* firstPhoto = collection->getFirst();
00490 
00491   if(firstPhoto != photo)
00492   { showNextPrevFirstLastPhoto( firstPhoto ); }
00493 }
00494 //==============================================
00495 void EditingInterface::showLastPhoto()
00496 { 
00497   Photo* lastPhoto = collection->getLast();
00498   
00499   if(lastPhoto != photo)
00500   { showNextPrevFirstLastPhoto( lastPhoto ); }
00501 }
00502 //==============================================
00503 void EditingInterface::showNextPrevFirstLastPhoto( Photo* newPhoto )
00504 {  
00505   //set busy pointer
00506   qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
00507   qApp->processEvents();
00508 
00509   //reset photo object handle
00510   photo = newPhoto;
00511 
00512   //reset selectionRotated bool to false
00513   selectionRotated = false;
00514   
00515   //update visibility of prev and next buttons
00516   previousButton->setInvisible( photo->getPrev() == NULL );
00517   nextButton->setInvisible( photo->getNext() == NULL );
00518     
00519   //update view of photo
00520   selectionInterface->setPhoto( photo->getImageFilename() );  
00521 
00522   //created effect preview image  
00523   effectPreviewImageFilename = ((Window*)qApp->mainWidget())->getTitle()->getAlbum()->getTmpDir() +     "/effectPreviewImage.jpg";
00524   scaleImage( photo->getImageFilename(), effectPreviewImageFilename, EFFECT_PREVIEW_WIDTH, EFFECT_PREVIEW_HEIGHT );
00525   selectEffect();
00526 
00527   //get full size photo dimensions
00528   getImageSize( photo->getImageFilename(), imageWidth, imageHeight );
00529 
00530   //get display size photo dimensions
00531   selectionInterface->getDisplaySize( displayWidth, displayHeight );
00532 
00533   //auto select region if custom not selected, else select nothing
00534   if(aspectRatios->currentItem() != 0)
00535   { selectAspectRatio(); }
00536   else  
00537   { selectionInterface->setSelection( QPoint(-1,-1), QPoint(-1, -1) ); }
00538   
00539   //emit signal that photo state possibly has changed
00540   emit photoModified();
00541   
00542   //remove busy cursor
00543   qApp->restoreOverrideCursor();
00544   qApp->processEvents();
00545 }
00546 //==============================================
00547 void EditingInterface::rotateRight()
00548 {
00549   rotateFlip( ROTATE_90 );
00550 }
00551 //==============================================
00552 void EditingInterface::rotateLeft()
00553 {
00554   rotateFlip( ROTATE_270 );
00555 }
00556 //==============================================
00557 void EditingInterface::flipHorizontal()
00558 {
00559   rotateFlip( FLIP_H );
00560 }
00561 //==============================================
00562 void EditingInterface::flipVertical()
00563 {
00564   rotateFlip( FLIP_V );
00565 }
00566 //==============================================
00567 void EditingInterface::rotateFlip( TRANSFORM_CODE rotationFlipType )
00568 {
00569   //set busy pointer
00570   qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
00571   qApp->processEvents();
00572   
00573   //disable user input
00574   layout->getWindow()->getStatus()->grabInput();
00575   
00576   //rotate image, bail if rotation fails
00577   QString editedImagePath = ((Window*)qApp->mainWidget())->getTitle()->getAlbum()->getTmpDir() + "/editedImage.jpg";
00578   transformImage( photo->getImageFilename(), editedImagePath, rotationFlipType );
00579 
00580   //apply changes to photo
00581   photo->setImage( editedImagePath );
00582   
00583   //Reload photo view
00584   bool aspectRatioChanged = ( rotationFlipType == ROTATE_90 || rotationFlipType == ROTATE_270 );  
00585   selectionInterface->setPhoto( editedImagePath, aspectRatioChanged );  
00586   
00587   //update image dimension variables
00588   getImageSize( photo->getImageFilename(), imageWidth, imageHeight );  
00589   
00590   //get display size photo dimensions
00591   selectionInterface->getDisplaySize( displayWidth, displayHeight );
00592   
00593   //reapply selected aspect ratio selection if aspect ratio changed
00594   if( aspectRatioChanged )
00595   {
00596     //reset selectionRotated bool to false
00597     selectionRotated = false;
00598     selectAspectRatio();      
00599   }
00600   
00601   //update effect preview
00602   scaleImage( photo->getImageFilename(), effectPreviewImageFilename, EFFECT_PREVIEW_WIDTH, EFFECT_PREVIEW_HEIGHT );
00603   selectEffect();
00604   
00605   //emit modified signal
00606   emit photoModified();
00607   
00608   //enable user input
00609   layout->getWindow()->getStatus()->releaseInput();
00610 
00611   //remove busy cursor
00612   qApp->restoreOverrideCursor();
00613   qApp->processEvents();
00614 }
00615 //==============================================
00616 void EditingInterface::screenResolutionChanged()
00617 {
00618   //reset display resolution
00619   aspectRatioValues[displayResolutionIndex] = qApp->desktop()->screenGeometry().size();
00620 
00621   //if user is currently constraining the current selection then reset to fit new display resolution
00622   if(aspectRatios->currentItem() == displayResolutionIndex )
00623   { selectAspectRatio(); }
00624 }
00625 //==============================================
00626 void EditingInterface::crop()
00627 {
00628   //find selection, if empty bail!
00629   QPoint topLeft, bottomRight;
00630   if (!findSelection(topLeft, bottomRight) )
00631     return;
00632 
00633   //set busy cursor
00634   qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
00635 
00636   //disable user input
00637   layout->getWindow()->getStatus()->grabInput();
00638 
00639   //crop image
00640   applyImageUpdate( cropImage( photo->getImageFilename(), topLeft, bottomRight ),
00641                     true );
00642 
00643   //enable user input
00644   layout->getWindow()->getStatus()->releaseInput();
00645 
00646   //remove busy cursor
00647   qApp->restoreOverrideCursor();
00648 }
00649 //==============================================
00650 void EditingInterface::enhanceContrast()
00651 {
00652   //set busy cursor
00653   qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
00654   qApp->processEvents();
00655 
00656   //disable user input
00657   layout->getWindow()->getStatus()->grabInput();
00658 
00659   //enhance image
00660   applyImageUpdate( enhanceImageContrast( photo->getImageFilename(),
00661                                           layout->getWindow()->getStatus() ),
00662                     false );
00663 
00664   //enable user input
00665   layout->getWindow()->getStatus()->releaseInput();
00666 
00667   //remove busy cursor
00668   qApp->restoreOverrideCursor();
00669   qApp->processEvents();
00670 }
00671 //==============================================
00672 void EditingInterface::colorBalance()
00673 {
00674   //set busy cursor
00675   qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
00676   qApp->processEvents();
00677 
00678   //disable user input
00679   layout->getWindow()->getStatus()->grabInput();
00680 
00681   //improve color balance
00682   applyImageUpdate( improveColorBalance( photo->getImageFilename(),
00683                                          layout->getWindow()->getStatus() ),
00684                     false );
00685 
00686   //enable user input
00687   layout->getWindow()->getStatus()->releaseInput();
00688 
00689   //remove busy cursor
00690   qApp->restoreOverrideCursor();
00691   qApp->processEvents();
00692 }
00693 //==============================================
00694 void EditingInterface::removeRedeye()
00695 {
00696   //find selection, if empty bail!
00697   QPoint topLeft, bottomRight;
00698   if (!findSelection(topLeft, bottomRight) )
00699     return;
00700 
00701   //set busy cursor
00702   qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
00703   qApp->processEvents();
00704   
00705   //disable user input
00706   layout->getWindow()->getStatus()->grabInput();
00707 
00708   //remove redeye image
00709   applyImageUpdate( removeRedeyeRegions( photo->getImageFilename(), 
00710                                          topLeft, bottomRight,
00711                                          layout->getWindow()->getStatus() ),
00712                     true );
00713 
00714   //enable user input
00715   layout->getWindow()->getStatus()->releaseInput();
00716 
00717   //remove busy cursor
00718   qApp->restoreOverrideCursor();
00719   qApp->processEvents();
00720 }
00721 //==============================================
00722 void EditingInterface::tuneLevels()
00723 {
00724   //load photo in histogram editor
00725   //if changes took place update image
00726   HistogramEditor editor( photo->getImageFilename(), this);
00727   if( editor.exec() ) 
00728   { 
00729     //set busy cursor
00730     qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
00731     qApp->processEvents();
00732 
00733     //disable user input
00734     layout->getWindow()->getStatus()->grabInput();
00735 
00736     //update image    
00737     applyImageUpdate( editor.getModifiedImage(), false ); 
00738 
00739     //enable user input
00740     layout->getWindow()->getStatus()->releaseInput();
00741 
00742     //remove busy cursor
00743     qApp->restoreOverrideCursor();
00744     qApp->processEvents();
00745   }
00746 }
00747 //==============================================
00748 void EditingInterface::adjustGrain()
00749 {
00750   //load photo in grain editor
00751   //if changes took place update image
00752   GrainEditor editor( photo->getImageFilename(), this);
00753   if( editor.exec() ) 
00754   { 
00755     //set busy cursor
00756     qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
00757     qApp->processEvents();
00758     
00759     //disable user input
00760     layout->getWindow()->getStatus()->grabInput();
00761 
00762     //update image    
00763     applyImageUpdate( editor.getModifiedImage(), false ); 
00764     
00765     //enable user input
00766     layout->getWindow()->getStatus()->releaseInput();
00767 
00768     //remove busy cursor
00769     qApp->restoreOverrideCursor();
00770     qApp->processEvents();
00771   }
00772 }
00773 //==============================================
00774 void EditingInterface::selectEffect()
00775 {  
00776   //apply effect on preview image
00777   QImage* editedImage = applyEffect( effectPreviewImageFilename );
00778   
00779   //bail if generated preview image failed
00780   if( editedImage == NULL ) return;
00781   
00782   //refresh displayed preview image
00783   effectPreview->setPixmap( QPixmap(*editedImage) );
00784   delete editedImage;
00785   editedImage = NULL;  
00786 }
00787 //==============================================
00788 void EditingInterface::applyEffect()
00789 {  
00790   //--------------------------------
00791   //Get any manipulation options if needed
00792   ManipulationOptions* options = NULL;
00793   if( effectsList->currentItem() == MOSAIC_EFFECT )   
00794   {
00795     MosaicOptionsDialog optionsDialog(this);
00796     //user accepted so get selected options
00797     if( optionsDialog.exec() ) 
00798     { 
00799       //constructing the tiles list can unfortunately be quite slow so show a preparing tiles message
00800       //and busy icon while getting the options chosen
00801       layout->getWindow()->getStatus()->showProgressBar( QString(tr("Preparing Tiles")), 100 );
00802       qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
00803       qApp->processEvents();       
00804       options = optionsDialog.getOptions(); 
00805       qApp->restoreOverrideCursor();
00806     }
00807     //user hit cancel so bail
00808     else 
00809     { return; }
00810   }
00811   else
00812   { options = new ManipulationOptions( layout->getWindow()->getStatus() ); }
00813   //--------------------------------
00814   //Disable user input
00815   layout->getWindow()->getStatus()->grabInput();
00816   applyEffectButton->setEnabled(false);
00817   qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
00818   qApp->processEvents();
00819   //--------------------------------
00820   //Apply effect
00821   QImage* editedImage = applyEffect( photo->getImageFilename(), options );
00822   applyImageUpdate( editedImage, false );
00823   delete options; options = NULL;
00824   //--------------------------------
00825   //Remove status bar if present and reenable user input
00826   layout->getWindow()->getStatus()->setStatus( "" );
00827   layout->getWindow()->getStatus()->releaseInput();
00828   applyEffectButton->setEnabled(true);
00829   qApp->restoreOverrideCursor();
00830   qApp->processEvents();
00831   //--------------------------------
00832 } 
00833 //==============================================
00834 QImage* EditingInterface::applyEffect(QString filename, ManipulationOptions* options)
00835 {
00836   //apply effect
00837   QImage* effectedImage = NULL;
00838   switch( effectsList->currentItem() )
00839   {
00840     case BW_EFFECT:          effectedImage = blackWhiteEffect(  filename, options ); break;
00841     case SEPIA_EFFECT:       effectedImage = sepiaEffect(       filename, options ); break;
00842     case INVERT_EFFECT:      effectedImage = invertEffect(      filename, options ); break;
00843     case EMBOSS_EFFECT:      effectedImage = embossEffect(      filename, options ); break;
00844     case PAINTING_EFFECT:    effectedImage = oilPaintingEffect( filename, options ); break;
00845     case POINTILLISM_EFFECT: effectedImage = pointillismEffect( filename, options ); break;
00846     case MOSAIC_EFFECT:      effectedImage = mosaicEffect(      filename, (MosaicOptions*) options ); break;
00847   }
00848 
00849   //return effected image
00850   return effectedImage;
00851 }
00852 //==============================================
00853 void EditingInterface::applyImageUpdate(QImage* editedImage, bool resetSelection)
00854 {  
00855   //skip apply step if pointer is null. this usually means
00856   //no modifications were made (for example: no red eyes were detected)
00857   if(editedImage == NULL) 
00858   { 
00859     //sometimes the user instructs the program to modify an image in a way
00860     //where no real changes are actually necessary. case in point, red eye reduction
00861     //on a region where there is no red stuff at all! in order to be consistant, if
00862     //the user is expecting the selection to be reset then always reset it! this
00863     //normally occurs below when resetting the photo but we'll do it here 
00864     //since resetting the photo will not take place
00865     if(resetSelection) 
00866     { 
00867       selectionInterface->selectNone(); 
00868     }
00869     
00870     return; 
00871   }
00872   
00873   //construct edited image path
00874   QString editedImagePath = ((Window*)qApp->mainWidget())->getTitle()->getAlbum()->getTmpDir() + "/editedImage.jpg";
00875 
00876   //save edited image to temporary location
00877   //TODO: EXIF information is lost at this point, Qt does not support
00878   //storing exif information, but perhaps a 2nd pass can be made on the file
00879   //where exif info is added using libjpeg functions?
00880   editedImage->save( editedImagePath, "JPEG", 95 );
00881   delete editedImage;
00882   editedImage = NULL;
00883     
00884   //apply changes to photo
00885   photo->setImage( editedImagePath );
00886   
00887   //Reload photo view
00888   selectionInterface->setPhoto( editedImagePath, resetSelection );  
00889 
00890   //If we're resetting the selection (due to cropping), reset the 
00891   //selection rotated bit as well
00892   if( resetSelection ) { selectionRotated = false; }
00893   
00894   //update image dimension variables
00895   getImageSize( photo->getImageFilename(), imageWidth, imageHeight );  
00896 
00897   //get display size photo dimensions
00898   selectionInterface->getDisplaySize( displayWidth, displayHeight );
00899 
00900   //update effect preview
00901   scaleImage( photo->getImageFilename(), effectPreviewImageFilename, EFFECT_PREVIEW_WIDTH, EFFECT_PREVIEW_HEIGHT );
00902   selectEffect();
00903   
00904   //emit modified signal
00905   emit photoModified();
00906 }
00907 //==============================================
00908 void EditingInterface::returnAction()
00909 {
00910   //exit edit mode
00911   layout->organize();
00912 }
00913 //==============================================
00914 bool EditingInterface::findSelection(QPoint& topLeft, QPoint& bottomRight)
00915 {
00916   //get raw selection in display coordinates
00917   selectionInterface->getSelection(topLeft, bottomRight);
00918 
00919   //if range is empty then retrun false
00920   if(topLeft.x() >= bottomRight.x() ||
00921      topLeft.y() >= bottomRight.y())
00922     return false;
00923   
00924   //return success
00925   return true;
00926 }
00927 //==============================================
00928 void EditingInterface::handleSelectionChanged()
00929 {
00930   //crop button is enabled only when a portion of the image is selected
00931   QPoint topLeft, bottomRight;
00932   bool selectionPresent = findSelection(topLeft,bottomRight);     
00933 
00934   cropButton->setEnabled( selectionPresent );
00935   redEyeReductionButton->setEnabled( selectionPresent );  
00936 }
00937 //==============================================
00938 void EditingInterface::handleAspectRatioChanged()
00939 {
00940   //change aspect ratio combo box to custom
00941   aspectRatios->setCurrentItem(0);  
00942 }
00943 //==============================================
00944 void EditingInterface::selectAll(QPoint& topLeft, QPoint& bottomRight)
00945 {
00946   topLeft.setX(0); 
00947   topLeft.setY(0);
00948   bottomRight.setX(imageWidth - 1); 
00949   bottomRight.setY(imageHeight - 1);     
00950 }
00951 //==============================================
00952 void EditingInterface::keyPressEvent( QKeyEvent *e )
00953 {
00954   //next handle additional keys
00955   switch( e->key() )
00956   {
00957     //apply changes and exit
00958     case Qt::Key_Escape:
00959       returnAction();
00960       break;
00961     case Qt::Key_Prior:
00962       showPrevPhoto();
00963       break;
00964     case Qt::Key_Next:
00965       showNextPhoto();
00966       break;
00967     case Qt::Key_Home:
00968       showFirstPhoto();
00969       break;
00970     case Qt::Key_End:
00971       showLastPhoto();
00972       break;
00973     case Qt::Key_R:
00974       if(e->state() & Qt::ControlButton)
00975         rotateRight();
00976       break;
00977     case Qt::Key_L:
00978       if(e->state() & Qt::ControlButton)
00979         rotateLeft();
00980       break;
00981     case Qt::Key_F:
00982       if(e->state() & Qt::ControlButton)
00983       {
00984         if( e->state() & Qt::AltButton )
00985           flipVertical();
00986         else
00987           flipHorizontal();
00988       }
00989       break;
00990     default:
00991       e->ignore();
00992   }
00993 }
00994 //==============================================
00995 bool EditingInterface::currentPhotoRevertable()
00996 {
00997   if(photo == NULL) 
00998     return false;
00999   else
01000     return photo->revertPossible();
01001 }
01002 //==============================================
01003 void EditingInterface::revertCurrentPhoto()
01004 {
01005   //if current photo not revertable immediately bail
01006   if( ! currentPhotoRevertable() ) return;
01007   
01008   //set busy cursor
01009   qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
01010   
01011   //disable user input
01012   layout->getWindow()->getStatus()->grabInput();
01013 
01014   //get current and reverted image sizes and compare to see if size has changed.
01015   //if so reset selected region
01016   int origWidth, origHeight;
01017   getImageSize( photo->originalImageFilename(), origWidth, origHeight );  
01018   bool resetSelection = (origWidth != imageWidth) || (origHeight != imageHeight);
01019   
01021   photo->revertPhoto();
01022 
01023   //Reload photo view
01024   selectionInterface->setPhoto( photo->getImageFilename(), resetSelection );  
01025   
01026   //update image dimension variables
01027   getImageSize( photo->getImageFilename(), imageWidth, imageHeight );  
01028   
01029   //get display size photo dimensions
01030   selectionInterface->getDisplaySize( displayWidth, displayHeight );
01031   
01032   //update effect preview
01033   scaleImage( photo->getImageFilename(), effectPreviewImageFilename, EFFECT_PREVIEW_WIDTH, EFFECT_PREVIEW_HEIGHT );
01034   selectEffect();  
01035   
01036   //emit modified signal
01037   emit photoModified();
01038 
01039   //enable user input
01040   layout->getWindow()->getStatus()->releaseInput();
01041 
01042   //remove busy cursor
01043   qApp->restoreOverrideCursor();
01044 }
01045 //==============================================
01046 void EditingInterface::setFocus()
01047 {
01048   //always pass off focus even to selection interface so it can get key strokes
01049   selectionInterface->setFocus();
01050 }
01051 //==============================================
01052 void EditingInterface::rotateSelection()
01053 {
01054   //invert rotate bool
01055   selectionRotated = !selectionRotated;
01056   
01057   //rotate custom selection in place, scale/shift if necessary to keep on image
01058   if(aspectRatios->currentItem() == 0)
01059   {
01060     //get cur selection
01061     QPoint curTopLeft, curBottomRight;
01062     selectionInterface->getSelection(curTopLeft, curBottomRight); 
01063 
01064     //find center
01065     QPoint selectionCenter = QPoint( ( curTopLeft.x() + curBottomRight.x() ) / 2,
01066                                      ( curTopLeft.y() + curBottomRight.y() ) / 2 );    
01067 
01068     //scale rotated width/height to fit image
01069     int newWidth = curBottomRight.y() - curTopLeft.y() + 1;
01070     int newHeight =curBottomRight.x() - curTopLeft.x() + 1;
01071     calcScaledImageDimensions( newWidth, newHeight,
01072                                imageWidth, imageHeight,
01073                                newWidth, newHeight );
01074 
01075     //center new selection over old selection
01076     QPoint topLeft = QPoint( selectionCenter.x() - newWidth/2,
01077                              selectionCenter.y() - newHeight/2 );
01078     QPoint bottomRight = QPoint( topLeft.x() + newWidth - 1,
01079                                  topLeft.y() + newHeight - 1 );
01080 
01081     //shift selection area to not go outside image boundary
01082     if(topLeft.x() < 0)
01083     {
01084       bottomRight.setX( bottomRight.x() - topLeft.x() );
01085       topLeft.setX( 0 );
01086     }
01087 
01088     if(topLeft.y() < 0)
01089     {
01090       bottomRight.setY( bottomRight.y() - topLeft.y() );
01091       topLeft.setY( 0 );
01092     }
01093     
01094     if(bottomRight.x() >= imageWidth )
01095     {
01096       topLeft.setX( topLeft.x() - ( bottomRight.x() - imageWidth + 1 ) );
01097       bottomRight.setX( imageWidth - 1 );
01098     }
01099 
01100     if(bottomRight.y() >= imageHeight )
01101     {
01102       topLeft.setY( topLeft.y() - ( bottomRight.y() - imageHeight + 1 ) );
01103       bottomRight.setY( imageHeight - 1 );
01104     }
01105     
01106     //select new region
01107     selectionInterface->setSelection(topLeft, bottomRight);    
01108   }
01109   //else call selectAspectRatio passing true that we're
01110   //using the rotated version of the current aspect ratio
01111   else
01112   { 
01113     selectAspectRatio(); 
01114   }
01115 }
01116 //==============================================
01117 void EditingInterface::selectAspectRatio()
01118 {
01119   //if user selected "custom" don't modify current selection
01120   if( aspectRatios->currentItem() == 0 ) return;
01121   
01122   //get default aspect ratio
01123   QSize aspectRatio = aspectRatioValues[ aspectRatios->currentItem() ];  
01124 
01125   //automatically rotate default if current photo is taller than wide
01126   if( imageHeight > imageWidth )
01127   { aspectRatio = QSize( aspectRatio.height(), aspectRatio.width() ); }
01128   
01129   //exchange aspect ratio dimensions if we're in rotated selection mode
01130   if( selectionRotated )
01131   { aspectRatio = QSize( aspectRatio.height(), aspectRatio.width() ); }
01132     
01133   //determine selected width and height;
01134   int selectedWidth = 0; 
01135   int selectedHeight = 0;
01136   
01137   //display resolution, match exactly or scale down
01138   if(aspectRatios->currentItem() == displayResolutionIndex)
01139   {    
01140     //select region less than or equal to display resolution while maintaining aspect ratio
01141     selectedWidth = aspectRatio.width();
01142     selectedHeight = aspectRatio.height();
01143     calcScaledImageDimensions( selectedWidth, selectedHeight,
01144                                imageWidth, imageHeight,
01145                                selectedWidth, selectedHeight );
01146   }
01147   //else use aspect ratio directly as a ratio
01148   else
01149   {  
01150     //select region using same aspect ratio
01151     selectedWidth = imageWidth;
01152     selectedHeight = (int) (((double) (imageWidth * aspectRatio.height()) ) / aspectRatio.width() );
01153     calcScaledImageDimensions( selectedWidth, selectedHeight,
01154                                imageWidth, imageHeight,
01155                                selectedWidth, selectedHeight );
01156     
01157   }
01158   
01159   //get current selection boundary
01160   QPoint curTopLeft, curBottomRight;
01161   selectionInterface->getSelection( curTopLeft, curBottomRight );
01162   
01163   //get current selection center
01164   QPoint curCenter;
01165   curCenter.setX( (curTopLeft.x() + curBottomRight.x()) / 2 );
01166   curCenter.setY( (curTopLeft.y() + curBottomRight.y()) / 2 );
01167 
01168   //if center is off image (no previous selection) then
01169   //fix center to center of image
01170   if( curCenter.x() < 0 || curCenter.y() < 0 )
01171   {
01172     curCenter.setX( imageWidth/2 );
01173     curCenter.setY( imageHeight/2 );
01174   }
01175   
01176   //attempt to center new selection overold selection, only
01177   //offset if necessary
01178   QPoint newTopLeft, newBottomRight;
01179 
01180   newTopLeft.setX( curCenter.x() - selectedWidth/2 );
01181   newTopLeft.setY( curCenter.y() - selectedHeight/2 );
01182 
01183   //push right/down if necessary
01184   if( newTopLeft.x() < 0 ) newTopLeft.setX( 0 );
01185   if( newTopLeft.y() < 0 ) newTopLeft.setY( 0 );
01186   
01187   //push left/up if necessary
01188   newBottomRight.setX( newTopLeft.x() + selectedWidth - 1 );
01189   if( newBottomRight.x() >= imageWidth )
01190   {
01191     newBottomRight.setX( imageWidth-1 );
01192     newTopLeft.setX( newBottomRight.x() - selectedWidth + 1 );
01193   }
01194   
01195   newBottomRight.setY( newTopLeft.y() + selectedHeight - 1 );
01196   if( newBottomRight.y() >= imageHeight )
01197   {
01198     newBottomRight.setY( imageHeight-1 );
01199     newTopLeft.setY( newBottomRight.y() - selectedHeight + 1 );
01200   }
01201 
01202   //select region
01203   selectionInterface->setSelection(newTopLeft, newBottomRight,
01204                                    maxDimensions[aspectRatios->currentItem()] );    
01205 } 
01206 //==============================================
01207 void EditingInterface::startCorrectTilt()
01208 {
01209   //instruct user to select a horizontal or vertical line in the image by
01210   //beginning draw line mode in the selection interface
01211   correctTiltButton->setEnabled( false );
01212   selectionInterface->enterDrawLineMode();
01213 }
01214 //==============================================
01215 void EditingInterface::finishCorrectTilt( QPoint p1, QPoint p2 )
01216 {
01217   //if either point is invalid ignore action
01218   if( p1.x() == -1 || p2.x() == -1 )
01219   {
01220     //reenable tilt button
01221     correctTiltButton->setEnabled( true );
01222     return;
01223   }
01224   
01225   //set busy cursor
01226   qApp->setOverrideCursor( QCursor(Qt::WaitCursor));
01227   
01228   //disable user input
01229   layout->getWindow()->getStatus()->grabInput();
01230   
01231   //rotate image by determining correct angle from two points
01232   QImage* rotatedImage = correctImageTilt( photo->getImageFilename(), p1, p2,
01233                                            layout->getWindow()->getStatus() );
01234   applyImageUpdate( rotatedImage, true );
01235   
01236   //reenable tilt button
01237   correctTiltButton->setEnabled( true );
01238 
01239   //enable user input
01240   layout->getWindow()->getStatus()->releaseInput();
01241 
01242   //remove busy cursor
01243   qApp->restoreOverrideCursor();
01244 }
01245 //==============================================
01246 
01247 

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