AlbumShaper
1.0a3
|
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