1 /*******************************************************************************
2 **
3 ** Photivo
4 **
5 ** Copyright (C) 2008,2009 Jos De Laender <jos.de_laender@telenet.be>
6 ** Copyright (C) 2009-2012 Michael Munzert <mail@mm-log.com>
7 ** Copyright (C) 2010-2012 Bernd Schoeler <brjohn@brother-john.net>
8 ** Copyright (C) 2013 Alexander Tzyganenko <tz@fast-report.com>
9 **
10 ** This file is part of Photivo.
11 **
12 ** Photivo is free software: you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License version 3
14 ** as published by the Free Software Foundation.
15 **
16 ** Photivo is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ** GNU General Public License for more details.
20 **
21 ** You should have received a copy of the GNU General Public License
22 ** along with Photivo.  If not, see <http://www.gnu.org/licenses/>.
23 **
24 *******************************************************************************/
25 #include "ptDefines.h"
26 #include "ptInfo.h"
27 #include "ptCalloc.h"
28 #include "ptConfirmRequest.h"
29 #include "ptConstants.h"
30 #include "ptMessageBox.h"
31 #include "ptDcRaw.h"
32 #include "ptProcessor.h"
33 #include "ptMainWindow.h"
34 #include "ptViewWindow.h"
35 #include "ptHistogramWindow.h"
36 #include "ptGuiOptions.h"
37 #include "ptSettings.h"
38 #include "ptError.h"
39 #include "ptRGBTemperature.h"
40 #include "ptWhiteBalances.h"
41 #include "ptCurve.h"
42 #include "ptTheme.h"
43 #include "ptWiener.h"
44 #include "ptParseCli.h"
45 #include "ptImageHelper.h"
46 #include "filters/imagespot/ptTuningSpot.h"
47 #include "qtsingleapplication/qtsingleapplication.h"
48 #include "filemgmt/ptFileMgrWindow.h"
49 #include "batch/ptBatchWindow.h"
50 #include "filters/ptFilterDM.h"
51 #include "filters/ptFilterBase.h"
52 #include "ptToolBox.h"
53 #include "filters/ptFilterUids.h"
54 
55 #ifdef Q_OS_WIN
56   #include "ptEcWin7.h"
57   #include "ptWinApi.h"
58 #endif
59 
60 #include <wand/magick_wand.h>
61 
62 #define QT_CLEAN_NAMESPACE
63 
64 #include <QFileInfo>
65 #include <QtGui>
66 #include <QtCore>
67 #include <QFileDialog>
68 #include <QColorDialog>
69 #include <QInputDialog>
70 #include <QTextCodec>
71 #include <QDesktopWidget>
72 #ifdef Q_OS_MAC
73   #include <QFileOpenEvent>
74 #endif
75 
76 #include <string>
77 #include <csignal>
78 #include <exception>
79 
80 using namespace std;
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 //
84 // This is the file where everything is started.
85 // It starts not only the gui but it is *also* the starting point
86 // for guiless jobmode. The design is such that the pipe runs
87 // independent whether or not gui thingies are attached to it.
88 //
89 ////////////////////////////////////////////////////////////////////////////////
90 
91 ptDcRaw*     TheDcRaw       = NULL;
92 ptProcessor* TheProcessor   = NULL;
93 
94 QStringList FileExtsRaw;
95 QStringList FileExtsBitmap;
96 QString     UserDirectory;
97 QString     ShareDirectory;
98 // Sidecar related
99 Exiv2::IptcData IptcData;
100 Exiv2::XmpData  XmpData;
101 
102 cmsHPROFILE PreviewColorProfile = NULL;
103 cmsCIExyY       D65;
104 cmsCIExyY       D50;
105 // precalculated color transform
106 cmsHTRANSFORM ToPreviewTransform = NULL;
107 void ReadSidecar(const QString& Sidecar);
108 void SetRatingFromXmp();
109 void SetTagsFromXmp();
110 
111 //
112 // The 'tee' towards the display.
113 // Visualization :
114 //
115 // Raw->Image_AfterDcRaw->Image_AfterLensfun->Image_AfterRGB->Image_AfterLab->
116 // Image_AfterGREYC->Image_AfterEyeCandy
117 // -------------------------------------------------------------------------
118 //                                       |
119 //                                Somewhere a tee to the preview
120 //                                       |
121 //                                  PreviewImage
122 //
123 // The pipe changed, Lab and Greyc became LabCC and LabSN
124 
125 
126 ptImage*  PreviewImage     = NULL;
127 ptImage*  HistogramImage   = NULL;
128 
129 // The main windows of the application.
130 ptMainWindow*      MainWindow      = NULL;
131 ptViewWindow*      ViewWindow      = NULL;
132 ptHistogramWindow* HistogramWindow = NULL;
133 ptFileMgrWindow*   FileMgrWindow   = NULL;
134 ptBatchWindow*     BatchWindow     = NULL;
135 
136 // Error dialog for segfaults
137 ptMessageBox* SegfaultErrorBox;
138 
139 // Theming
140 ptTheme* Theme = NULL;
141 
142 QTranslator appTranslator;
143 
144 // Gui options and settings.
145 ptGuiOptions  *GuiOptions = NULL;
146 ptSettings    *Settings = NULL;
147 
148 // Lensfun database.
149 //ptLensfun*  LensfunData = NULL;    // TODO BJ: implement lensfun DB
150 
151 // Run mode
152 short NextPhase;
153 short NextSubPhase;
154 short ImageSaved;
155 short ImageCleanUp;
156 
157 // uint16_t (0,0xffff) to float (0.0, 1.0)
158 float    ToFloatTable[0x10000];
159 float    ToFloatABNeutral[0x10000];
160 uint16_t ToInvertTable[0x10000];
161 uint16_t ToSRGBTable[0x10000];
162 
163 // Filter patterns for the filechooser.
164 QString ChannelMixerFilePattern;
165 QString CurveFilePattern;
166 QString JobFilePattern;
167 QString SettingsFilePattern;
168 QString ProfilePattern;
169 QString RawPattern;
170 QString BitmapPattern;
171 QString SaveBitmapPattern;
172 
InitStrings()173 void InitStrings() {
174   ChannelMixerFilePattern =
175     QCoreApplication::translate("Global Strings","Photivo channelmixer file (*.ptm);;All files (*.*)");
176   CurveFilePattern =
177     QCoreApplication::translate("Global Strings","Photivo curve file (*.ptc);;All files (*.*)");
178   JobFilePattern =
179     QCoreApplication::translate("Global Strings","Photivo job file (*.ptj);;All files (*.*)");
180   SettingsFilePattern =
181     QCoreApplication::translate("Global Strings","Photivo settings file (*.pts);;All files (*.*)");
182   ProfilePattern =
183     QCoreApplication::translate("Global Strings","ICC colour profiles (*.icc *.icm);;All files (*.*)");
184 
185   // QFileDialog has no case insensitive option ...
186   RawPattern =
187     QCoreApplication::translate("Global Strings","Raw files ("
188                                                  "*.arw *.ARW *.Arw "
189                                                  "*.bay *.BAY *.Bay "
190                                                  "*.bmq *.BMQ *.Bmq "
191                                                  "*.cr2 *.CR2 *.Cr2 "
192                                                  "*.crw *.CRW *.Crw "
193                                                  "*.cs1 *.CS1 *.Cs1 "
194                                                  "*.dc2 *.DC2 *.Dc2 "
195                                                  "*.dcr *.DCR *.Dcr "
196                                                  "*.dng *.DNG *.Dng "
197                                                  "*.erf *.ERF *.Erf "
198                                                  "*.fff *.FFF *.Fff "
199                                                  "*.hdr *.HDR *.Hdr "
200                                                  "*.ia  *.IA *.Ia "
201                                                  "*.k25 *.K25 "
202                                                  "*.kc2 *.KC2 *.Kc2 "
203                                                  "*.kdc *.KDC *.Kdc "
204                                                  "*.mdc *.MDC *.Mdc "
205                                                  "*.mef *.MEF *.Mef "
206                                                  "*.mos *.MOS *.Mos "
207                                                  "*.mrw *.MRW *.Mrw "
208                                                  "*.nef *.NEF *.Nef "
209                                                  "*.nrw *.NRW *.Nrw "
210                                                  "*.orf *.ORF *.Orf "
211                                                  "*.pef *.PEF *.Pef "
212                                                  "*.pxn *.PXN *.Pxn "
213                                                  "*.qtk *.QTK *.Qtk "
214                                                  "*.raf *.RAF *.Raf "
215                                                  "*.raw *.RAW *.Raw "
216                                                  "*.rdc *.RDC *.Rdc "
217                                                  "*.rw2 *.RW2 *.Rw2 "
218                                                  "*.sr2 *.SR2 *.Sr2 "
219                                                  "*.srf *.SRF *.Srf "
220                                                  "*.srw *.SRW *.Srw "
221                                                  "*.sti *.STI *.Sti "
222                                                  "*.tif *.TIF *.Tif "
223                                                  "*.x3f *.X3F *.X3f)"
224                                                  ";;Bitmaps ("
225                                                  "*.jpeg *.JPEG *.Jpeg "
226                                                  "*.jpg *.JPG *.Jpg "
227                                                  "*.tiff *.TIFF *.Tiff "
228                                                  "*.tif *.TIF *.Tif "
229                                                  "*.bmp *.BMP *.Bmp "
230                                                  "*.png *.PNG *.Png "
231                                                  "*.ppm *.PPm *.Ppm)"
232                                                  ";;All files (*.*)");
233 
234   BitmapPattern =
235     QCoreApplication::translate("Global Strings","Bitmaps ("
236                                                  "*.jpeg *.JPEG *.Jpeg "
237                                                  "*.jpg *.JPG *.Jpg "
238                                                  "*.tiff *.TIFF *.Tiff "
239                                                  "*.tif *.TIF *.Tif "
240                                                  "*.bmp *.BMP *.Bmp "
241                                                  "*.png *.PNG *.Png "
242                                                  "*.ppm *.PPm *.Ppm "
243                                                  ";;All files (*.*)");
244 
245   SaveBitmapPattern =
246     QCoreApplication::translate("Global Strings","Jpeg (*.jpg);;"
247                                                  "Tiff (*.tiff);;"
248                                                  "Png (*.png);;"
249                                                  "All files (*.*)");
250 }
251 
252 ////////////////////////////////////////////////////////////////////////////////
253 //
254 // Some function prototypes.
255 //
256 ////////////////////////////////////////////////////////////////////////////////
257 
258 ptImageType CheckImageType(QString filename,
259                            uint16_t* width, uint16_t* height,
260                            ptDcRaw* dcRaw = NULL);
261 void   RunJob(const QString FileName);
262 short  ReadJobFile(const QString FileName);
263 void   WriteOut();
264 void   UpdatePreviewImage(const ptImage* ForcedImage   = NULL,
265                           const short    OnlyHistogram = 0);
266 void   UpdateCropToolUI();
267 void   PreCalcTransforms();
268 void   CB_ZoomFitButton();
269 void   CB_MenuFileOpen(const short HaveFile);
270 void   CB_MenuFileExit(const short);
271 void   ExtFileOpen(const QString file);
272 void   CB_WritePipeButton();
273 void   CB_OpenPresetFileButton();
274 void   CB_OpenSettingsFileButton();
275 void   CB_CropOrientationButton();
276 //short  WriteSettingsFile(const QString FileName, const short IsJobFile = 0);
277 void   SetBackgroundColor(int SetIt);
278 void   CB_StyleChoice(const QVariant Choice);
279 void   CB_SliderWidthInput(const QVariant Value);
280 void Export(const short mode);
281 void Update(short Phase,
282             short SubPhase      = -1,
283             short WithIdentify  = 1,
284             short ProcessorMode = ptProcessorMode_Preview);
285 int CalculatePipeSize(const bool NewImage = false);
286 void CB_OpenSettingsFile(QString SettingsFileName);
287 void SaveButtonToolTip(const short mode);
288 
289 int    photivoMain(int Argc, char *Argv[]);
290 void   CleanupResources();
291 void copyFolder(QString sourceFolder, QString destFolder);
292 void CB_PixelReader(const QPointF Point, const ptPixelReading PixelReading);
293 bool GBusy = false;
294 
295 // undo-redo & clipboard support
296 QByteArray ptSettingsToQByteArray();
297 void ptQByteArrayToSettings(const QByteArray &arr);
298 void ptAddUndo();
299 void ptMakeUndo();
300 void ptMakeRedo();
301 void ptClearUndoRedo();
302 void ptMakeFullUndo();
303 void ptResetSettingsToDefault();
304 void ptCopySettingsToClipboard();
305 void ptPasteSettingsFromClipboard();
306 
307 //==============================================================================
308 
CreateAllFilters()309 void CreateAllFilters() {
310   //                   Filter ID                unique name                         caption postfix
311   // Local Edit tab
312   GFilterDM->NewFilter("SpotTuning",            Fuid::SpotTuning_Local);
313   // RGB tab
314   GFilterDM->NewFilter("ChannelMixer",          Fuid::ChannelMixer_RGB);
315   GFilterDM->NewFilter("Highlights",            Fuid::Highlights_RGB);
316   GFilterDM->NewFilter("ColorIntensity",        Fuid::ColorIntensity_RGB);
317   GFilterDM->NewFilter("Brightness",            Fuid::Brightness_RGB);
318   GFilterDM->NewFilter("ExposureCorrection",    Fuid::Exposure_RGB);
319   GFilterDM->NewFilter("ReinhardBrighten",      Fuid::ReinhardBrighten_RGB);
320   GFilterDM->NewFilter("GammaTool",             Fuid::GammaTool_RGB);
321   GFilterDM->NewFilter("Normalization",         Fuid::Normalization_RGB);
322   GFilterDM->NewFilter("ColorEnhancement",      Fuid::ColorEnhancement_RGB);
323   GFilterDM->NewFilter("LMHRecoveryRgb",        Fuid::LMHRecovery_RGB);
324   GFilterDM->NewFilter("TextureContrastRgb",    Fuid::TextureContrast_RGB);
325   GFilterDM->NewFilter("LocalContrastRgb",      Fuid::LocalContrast1_RGB,           " I");
326   GFilterDM->NewFilter("LocalContrastRgb",      Fuid::LocalContrast2_RGB,           " II");
327   GFilterDM->NewFilter("SigContrastRgb",        Fuid::SigContrastRgb_RGB);
328   GFilterDM->NewFilter("LevelsRgb",             Fuid::Levels_RGB);
329   GFilterDM->NewFilter("RgbCurve",              Fuid::RgbCurve_RGB);
330   // Lab Color/contrast tab
331   GFilterDM->NewFilter("LabTransform",          Fuid::LabTransform_LabCC);
332   GFilterDM->NewFilter("ShadowsHighlights",     Fuid::ShadowsHighlights_LabCC);
333   GFilterDM->NewFilter("LMHRecoveryLab",        Fuid::LMHRecovery_LabCC);
334   GFilterDM->NewFilter("Drc",                   Fuid::Drc_LabCC);
335   GFilterDM->NewFilter("SigContrastLab",        Fuid::SigContrastLab_LabCC);
336   GFilterDM->NewFilter("TextureCurve",          Fuid::TextureCurve_LabCC);
337   GFilterDM->NewFilter("TextureContrastLab",    Fuid::TextureContrast1_LabCC,       " I");
338   GFilterDM->NewFilter("TextureContrastLab",    Fuid::TextureContrast2_LabCC,       " II");
339   GFilterDM->NewFilter("LocalContrastLab",      Fuid::LocalContrast1_LabCC,         " I");
340   GFilterDM->NewFilter("LocalContrastLab",      Fuid::LocalContrast2_LabCC,         " II");
341   GFilterDM->NewFilter("LocalContrastStretch",  Fuid::LocalContrastStretch1_LabCC,  " I");
342   GFilterDM->NewFilter("LocalContrastStretch",  Fuid::LocalContrastStretch2_LabCC,  " II");
343   GFilterDM->NewFilter("Saturation",            Fuid::Saturation_LabCC);
344   GFilterDM->NewFilter("ColorBoost",            Fuid::ColorBoost_LabCC);
345   GFilterDM->NewFilter("LevelsLab",             Fuid::Levels_LabCC);
346   // Lab sharpen/noise tab
347   GFilterDM->NewFilter("ImpulseNR",             Fuid::ImpulseNR_LabSN);
348   GFilterDM->NewFilter("EAWavelets",            Fuid::EAWavelets_LabSN);
349   GFilterDM->NewFilter("GreyCStoration",        Fuid::GreyCStoration_LabSN);
350   GFilterDM->NewFilter("Defringe",              Fuid::Defringe_LabSN);
351   GFilterDM->NewFilter("WaveletDenoise",        Fuid::WaveletDenoise_LabSN);
352   GFilterDM->NewFilter("LumaDenoise",           Fuid::LumaDenoise_LabSN);
353   GFilterDM->NewFilter("LumaDenoiseCurve",      Fuid::LumaDenoiseCurve_LabSN);
354   GFilterDM->NewFilter("LumaDenoiseCurve",      Fuid::LumaDenoiseCurve2_LabSN,      " II");
355   GFilterDM->NewFilter("PyramidDenoise",        Fuid::PyramidDenoise_LabSN);
356   GFilterDM->NewFilter("ColorDenoise",          Fuid::ColorDenoise_LabSN);
357   GFilterDM->NewFilter("GradientSharpen",       Fuid::GradientSharpen_LabSN);
358   GFilterDM->NewFilter("DetailCurve",           Fuid::DetailCurve_LabSN);
359   GFilterDM->NewFilter("Wiener",                Fuid::Wiener_LabSN);
360   GFilterDM->NewFilter("InvDiffSharpen",        Fuid::InvDiffSharpen_LabSN);
361   GFilterDM->NewFilter("UnsharpMask",           Fuid::Usm_LabSN);
362   GFilterDM->NewFilter("HighpassSharpen",       Fuid::HighpassSharpen_LabSN);
363   GFilterDM->NewFilter("FilmGrain",             Fuid::FilmGrain_LabSN);
364   GFilterDM->NewFilter("LabChannelView",        Fuid::ViewLab_LabSN);
365   // Lab Eyecandy tab
366   GFilterDM->NewFilter("Outline",               Fuid::Outline_LabEyeCandy);
367   GFilterDM->NewFilter("LumaByHueCurve",        Fuid::LumaByHueCurve_LabEyeCandy);
368   GFilterDM->NewFilter("SatCurve",              Fuid::SatCurve_LabEyeCandy);
369   GFilterDM->NewFilter("HueCurve",              Fuid::HueCurve_LabEyeCandy);
370   GFilterDM->NewFilter("LCurve",                Fuid::LCurve_LabEyeCandy);
371   GFilterDM->NewFilter("ABCurves",              Fuid::ABCurves_LabEyeCandy);
372   GFilterDM->NewFilter("ColorContrast",         Fuid::ColorContrast_LabEyeCandy);
373   GFilterDM->NewFilter("ToneAdjust",            Fuid::ToneAdjust1_LabEyeCandy,      " I");
374   GFilterDM->NewFilter("ToneAdjust",            Fuid::ToneAdjust2_LabEyeCandy,      " II");
375   GFilterDM->NewFilter("LumaAdjust",            Fuid::LumaAdjust_LabEyeCandy);
376   GFilterDM->NewFilter("SatAdjust",             Fuid::SatAdjust_LabEyeCandy);
377   GFilterDM->NewFilter("Tone",                  Fuid::Tone_LabEyeCandy);
378   GFilterDM->NewFilter("VignetteLab",           Fuid::Vignette_LabEyeCandy);
379   // Eyecandy tab
380   GFilterDM->NewFilter("BlackWhite",            Fuid::BlackWhite_EyeCandy);
381   GFilterDM->NewFilter("CrossProcessing",       Fuid::CrossProcessing_EyeCandy);
382   GFilterDM->NewFilter("SimpleTone",            Fuid::SimpleTone_EyeCandy);
383   GFilterDM->NewFilter("ColorTone",             Fuid::ColorTone1_EyeCandy,          " I");
384   GFilterDM->NewFilter("ColorTone",             Fuid::ColorTone2_EyeCandy,          " II");
385   GFilterDM->NewFilter("SigContrastRgb",        Fuid::SigContrastRgb_EyeCandy);
386   GFilterDM->NewFilter("TextureOverlay",        Fuid::TextureOverlay1_EyeCandy,     " I");
387   GFilterDM->NewFilter("TextureOverlay",        Fuid::TextureOverlay2_EyeCandy,     " II");
388   GFilterDM->NewFilter("GradualOverlay",        Fuid::GradualOverlay1_EyeCandy,     " I");
389   GFilterDM->NewFilter("GradualOverlay",        Fuid::GradualOverlay2_EyeCandy,     " II");
390   GFilterDM->NewFilter("VignetteRgb",           Fuid::Vignette_EyeCandy);
391   GFilterDM->NewFilter("GradualBlur",           Fuid::GradualBlur1_EyeCandy,        " I");
392   GFilterDM->NewFilter("GradualBlur",           Fuid::GradualBlur2_EyeCandy,        " II");
393   GFilterDM->NewFilter("SoftglowOrton",         Fuid::SoftglowOrton_EyeCandy);
394   GFilterDM->NewFilter("ColorIntensity",        Fuid::ColorIntensity_EyeCandy);
395   GFilterDM->NewFilter("RToneCurve",            Fuid::RTone_EyeCandy);
396   GFilterDM->NewFilter("GToneCurve",            Fuid::GTone_EyeCandy);
397   GFilterDM->NewFilter("BToneCurve",            Fuid::BTone_EyeCandy);
398   // Output tab
399   GFilterDM->NewFilter("RgbCurve",              Fuid::RgbCurve_Out);
400   GFilterDM->NewFilter("AfterGammaCurve",       Fuid::AfterGammaCurve_Out);
401   GFilterDM->NewFilter("SigContrastRgb",        Fuid::SigContrastRgb_Out);
402   GFilterDM->NewFilter("Wiener",                Fuid::Wiener_Out);
403 }
404 
405 
406 //==============================================================================
407 
408 
409 ////////////////////////////////////////////////////////////////////////////////
410 //
411 // Progress function in the GUI.
412 // Can later also in job.
413 //
414 ////////////////////////////////////////////////////////////////////////////////
415 
ReportProgress(const QString Message)416 void ReportProgress(const QString Message) {
417   printf("Progress : %s\n",Message.toLocal8Bit().data());
418   if (!MainWindow) return;
419   MainWindow->StatusLabel->setText(Message);
420   MainWindow->StatusLabel->repaint();
421   // Workaround to keep the GUI responsive
422   // during pipe processing...
423   QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
424 }
425 
426 ////////////////////////////////////////////////////////////////////////////////
427 //
428 // Main : instantiating toplevel windows, settings and options ..
429 //
430 ////////////////////////////////////////////////////////////////////////////////
431 
432 short   InStartup  = 1;
433 
434 short   JobMode = 0;
435 QString JobFileName = "";
436 QString ImageFileToOpen = "";
437 QString PtsFileToOpen = "";
438 QString Sidecar = "";
439 #ifdef Q_OS_MAC
440     bool MacGotFileEvent=false;
441 #endif
442 QRect DetailViewRect;
443 
444 
445 #ifndef DLRAW_GIMP_PLUGIN
SegfaultAbort(int)446 void SegfaultAbort(int) {
447   // prevent infinite recursion if SegfaultAbort() causes another segfault
448   std::signal(SIGSEGV, SIG_DFL);
449   std::signal(SIGABRT, SIG_DFL);
450   SegfaultErrorBox->exec();
451 //  std::abort();
452 //  Batch manager needs Photivo to return a value to determine a crash
453   exit(EXIT_FAILURE);
454 }
455 
main(int Argc,char * Argv[])456 int main(int Argc, char *Argv[]) {
457 #ifdef Q_OS_WIN
458   WinApi::AttachToParentConsole();
459 #endif
460 
461   int RV = photivoMain(Argc,Argv);
462   DestroyMagick();
463   DelAndNull(SegfaultErrorBox);
464   CleanupResources(); // Not necessary , for debug.
465 
466 #ifdef Q_OS_WIN
467   // Close output channels to a possibly attached console and detach from it.
468   // Not sure if this is strictly necessary, but it does not hurt either.
469   fclose(stdout);
470   fclose(stderr);
471   FreeConsole();
472 #endif
473 
474   return RV;
475 }
476 #endif
477 
478 
479 //class QtSingleApplication with redefined event to handle QFileOpenEvent
480 #ifdef Q_OS_MAC
481   class MyQApplication : public QtSingleApplication {
482   protected:
483     virtual bool event(QEvent *event);
484   public:
485       bool initialized;
486       void macinit();
487       MyQApplication(const QString &appId, int & argc, char ** arg);
488   };
489 
event(QEvent * event)490   bool MyQApplication::event(QEvent *event)
491   {
492       switch (event->type()) {
493       case QEvent::FileOpen:
494           ImageFileToOpen=static_cast<QFileOpenEvent *>(event)->file();
495           MacGotFileEvent=true;
496           if(initialized){
497               //skip on first Event
498           ExtFileOpen(ImageFileToOpen);
499           }
500           return true;
501       default:
502           MacGotFileEvent=false;
503           break;
504       }
505       return QtSingleApplication::event(event);
506   }
MyQApplication(const QString & appId,int & argc,char ** argv)507   MyQApplication::MyQApplication(const QString &appId,int & argc, char ** argv) : QtSingleApplication(appId,argc, argv){
508   initialized=false;
509   };
macinit()510   void MyQApplication::macinit(){
511       initialized=true;
512   };
513 #endif
514 
515 
516 #ifdef Q_OS_MAC
517 MyQApplication* TheApplication;
518 #else
519 QtSingleApplication* TheApplication;
520 #endif
521 
photivoMain(int Argc,char * Argv[])522 int photivoMain(int Argc, char *Argv[]) {
523   QString VerTemp(TOSTRING(APPVERSION));    //also used for the cli syntax error msg below!
524   printf("Photivo version %s\n", VerTemp.toLocal8Bit().data());
525 
526   InitializeMagick(*Argv);
527 
528   //QApplication TheApplication(Argc,Argv);
529   QStringList environment = QProcess::systemEnvironment();
530   QString user=environment.filter(QRegExp("^USERNAME=|^USER=",Qt::CaseInsensitive)).first();
531   if(!user.isEmpty()){
532       int l=user.indexOf("=",0);
533       user="_"+user.right(user.length()-l-1);
534   }
535   user="photivo"+user;
536 
537 #ifdef Q_OS_MAC
538   TheApplication = new MyQApplication(user, Argc,Argv);
539 #else
540   TheApplication = new QtSingleApplication(user, Argc,Argv);
541 #endif
542   //close on last window closed, seems to be unneeded
543   TheApplication->connect(TheApplication, SIGNAL(lastWindowClosed()), TheApplication, SLOT(quit()));
544 
545   // Error handling for segfaults (to prevent silent crashes)
546   SegfaultErrorBox = new ptMessageBox(QMessageBox::Critical,
547                                       QObject::tr("Photivo crashed"),
548                                       QObject::tr("Photivo crashed. You can get help on our flickr forum at\n"
549                                       "<a href=\"http://www.flickr.com/groups/photivo/discuss/\">http://www.flickr.com/groups/photivo/discuss/</a>"
550                                       "\nWhen you post there make sure to describe your last actions before the crash occurred."),
551                                       QMessageBox::Ok);
552   SegfaultErrorBox->setTextFormat(Qt::RichText);
553   std::signal(SIGSEGV, SegfaultAbort);
554   std::signal(SIGABRT, SegfaultAbort);
555 
556   // Check for wrong GM quantum depth. We need the 16bit GraphicsMagick.
557   ulong QDepth = 0;
558   const ulong MinQD = 16;
559   MagickGetQuantumDepth(&QDepth);
560   if (QDepth < MinQD) {
561     QString WrongQDepthMsg = QObject::tr(
562         "Fatal error: Wrong GraphicsMagick quantum depth!\n"
563         "Found quantum depth %1. Photivo needs at least %2.\n")
564         .arg(QDepth).arg(MinQD);
565     fprintf(stderr,"%s", WrongQDepthMsg.toLocal8Bit().data());
566     ptMessageBox::critical(0, QObject::tr("Photivo: Fatal Error"), WrongQDepthMsg);
567     exit(EXIT_FAILURE);
568   }
569 
570 
571   // Handle cli arguments
572   QString PhotivoCliUsageMsg = "<pre>" + QObject::tr(
573 "Syntax: photivo [inputfile | -i imagefile | -j jobfile |\n"
574 "                 --load-and-delete imagefile]\n"
575 "                [--pts ptsfile] [--sidecar sidecarfile] [-h] [--new-instance]\n"
576 "Options:\n"
577 "inputfile\n"
578 "      Specify the image or settings file to load. Works like -i for image files\n"
579 "      and like --pts for settings files.\n"
580 "-i imagefile\n"
581 "      Specify image file to load.\n"
582 "-j jobfile\n"
583 "      Specify jobfile for batch processing. Job files are created\n in Photivo\n"
584 "      and then executed with this option.\n"
585 "--load-and-delete imagefile\n"
586 "      Specify temporary file used for Gimp-to-Photivo export. Internal option,\n"
587 "      not intended for general use. BEWARE! This option deletes imagefile!\n"
588 "--pts ptsfile\n"
589 "      Specify settings file to load with the image. Must be used together\n"
590 "      with -i.\n"
591 "--sidecar sidecarfile\n"
592 "      Specify sidecar file to load with the image.\n"
593 "--new-instance\n"
594 "      Allow opening another Photivo instance instead of using a currently\n"
595 "      running Photivo. Job files are always opened in a new instance.\n"
596 "--no-fmgr or -p\n"
597 "      Prevent auto-open file manager when Photivo starts.\n"
598 "--help or -h\n"
599 "      Display this usage information.\n\n"
600 "For more documentation visit the wiki: http://photivo.org/photivo/start\n"
601   ) + "</pre>";
602 
603   ptCliCommands cli = { cliNoAction, "", "", "", false, false };
604 
605 #ifdef Q_OS_MAC
606 //Just Skip if engaged by QFileOpenEvent
607   if(!MacGotFileEvent) {
608 #endif
609 
610   cli = ParseCli(Argc, Argv);
611 
612   // Show help message and exit Photivo
613   if (cli.Mode == cliShowHelp) {
614   #ifdef Q_OS_WIN
615     ptMessageBox::critical(0, QObject::tr("Photivo"), PhotivoCliUsageMsg);
616   #else
617     fprintf(stderr,"%s",PhotivoCliUsageMsg.toLocal8Bit().data());
618   #endif
619     exit(EXIT_FAILURE);
620   }
621 
622   ImageCleanUp = cli.Mode == cliLoadAndDelImage;
623   JobMode = cli.Mode == cliProcessJob;
624   PtsFileToOpen = cli.PtsFilename;
625 
626   if (JobMode) {
627     JobFileName = cli.Filename;
628   } else {
629     ImageFileToOpen = cli.Filename;
630   }
631 
632 
633   if (cli.Sidecar != "" ) {
634     Sidecar = cli.Sidecar;
635   }
636 
637   // QtSingleInstance, add CLI-Switch to skip and allow multiple instances
638   // JobMode is always run in a new instance
639   // Sent messages are handled by ptMainWindow::OtherInstanceMessage
640   if (!JobMode) {
641     if (TheApplication->isRunning() && !cli.NewInstance) {
642       if (PtsFileToOpen != "") {
643         TheApplication->sendMessage("::pts::" + PtsFileToOpen);
644       }
645       if (ImageFileToOpen != "") {
646         if (ImageCleanUp > 0) {
647           TheApplication->sendMessage("::tmp::" + ImageFileToOpen);
648         } else {
649           TheApplication->sendMessage("::img::" + ImageFileToOpen);
650         }
651       }
652       if (Sidecar != ""){
653         TheApplication->sendMessage("::sidecar::" + Sidecar);
654       }
655       TheApplication->activateWindow();
656       exit(0);
657     }
658   }
659 
660 
661 #ifdef Q_OS_MAC
662   } // !MacGotFileEvent
663   QDir dir(QApplication::applicationDirPath());
664   QApplication::setLibraryPaths(QStringList(dir.absolutePath()));
665 #endif
666 
667 
668 
669   FileExtsRaw << "*.arw" << "*.ARW" << " *.Arw"
670               << "*.bay" << "*.BAY" << "*.Bay"
671               << "*.bmq" << "*.BMQ" << "*.Bmq"
672               << "*.cr2" << "*.CR2" << "*.Cr2"
673               << "*.crw" << "*.CRW" << "*.Crw"
674               << "*.cs1" << "*.CS1" << "*.Cs1"
675               << "*.dc2" << "*.DC2" << "*.Dc2"
676               << "*.dcr" << "*.DCR" << "*.Dcr"
677               << "*.dng" << "*.DNG" << "*.Dng"
678               << "*.erf" << "*.ERF" << "*.Erf"
679               << "*.fff" << "*.FFF" << "*.Fff"
680               << "*.hdr" << "*.HDR" << "*.Hdr"
681               << "*.ia " << "*.IA" << "*.Ia"
682               << "*.k25" << "*.K25"
683               << "*.kc2" << "*.KC2" << "*.Kc2"
684               << "*.kdc" << "*.KDC" << "*.Kdc"
685               << "*.mdc" << "*.MDC" << "*.Mdc"
686               << "*.mef" << "*.MEF" << "*.Mef"
687               << "*.mos" << "*.MOS" << "*.Mos"
688               << "*.mrw" << "*.MRW" << "*.Mrw"
689               << "*.nef" << "*.NEF" << "*.Nef"
690               << "*.nrw" << "*.NRW" << "*.Nrw"
691               << "*.orf" << "*.ORF" << "*.Orf"
692               << "*.pef" << "*.PEF" << "*.Pef"
693               << "*.pxn" << "*.PXN" << "*.Pxn"
694               << "*.qtk" << "*.QTK" << "*.Qtk"
695               << "*.raf" << "*.RAF" << "*.Raf"
696               << "*.raw" << "*.RAW" << "*.Raw"
697               << "*.rdc" << "*.RDC" << "*.Rdc"
698               << "*.rw2" << "*.RW2" << "*.Rw2"
699               << "*.sr2" << "*.SR2" << "*.Sr2"
700               << "*.srf" << "*.SRF" << "*.Srf"
701               << "*.srw" << "*.SRW" << "*.Srw"
702               << "*.sti" << "*.STI" << "*.Sti"
703               << "*.tif" << "*.TIF" << "*.Tif"
704               << "*.x3f" << "*.X3F" << "*.X3f";
705 
706   FileExtsBitmap << "*.jpeg" << "*.JPEG" << "*.Jpeg"
707                  << "*.jpg"  << "*.JPG"  << "*.Jpg"
708                  << "*.png"  << "*.PNG"  << "*.Png"
709                  << "*.tiff" << "*.TIFF" << "*.Tiff"
710                  << "*.tif"  << "*.TIF"  << "*.Tif"
711                  << "*.bmp"  << "*.BMP"  << "*.Bmp"
712                  << "*.png"  << "*.PNG"  << "*.Png"
713                  << "*.ppm"  << "*.PPm"  << "*.Ppm";
714 
715 
716   // User home folder, where Photivo stores its ini and all Presets, Curves etc
717   // %appdata%\Photivo on Windows, ~/.photivo on Linux or the program folder for the
718   // portable Windows version.
719   short IsPortableProfile = 0;
720   QString AppDataFolder = "";
721   QString Folder = "";
722 #ifdef Q_OS_WIN
723   IsPortableProfile = QFile::exists("use-portable-profile");
724   if (IsPortableProfile != 0) {
725     printf("Photivo running in portable mode.\n");
726     AppDataFolder = QCoreApplication::applicationDirPath();
727     Folder = "";
728   } else {
729     // WinAPI returns path with native separators "\". We need to change this to "/" for Qt.
730     AppDataFolder = WinApi::AppdataFolder();
731     // Keeping the leading "/" separate here is important or mkdir will fail.
732     Folder = "Photivo/";
733   }
734 #else
735   Folder = ".photivo/";
736   AppDataFolder = QDir::homePath();
737 #endif
738 
739   UserDirectory = AppDataFolder + "/" + Folder;
740 
741   if (IsPortableProfile == 0) {
742       QDir home(AppDataFolder);
743       if (!home.exists(Folder))
744           home.mkdir(Folder);
745   }
746 
747   QString SettingsFileName = UserDirectory + "photivo.ini";
748   // this has to be changed when we move to a different tree structure!
749 #ifdef __unix__
750   QString NewShareDirectory(TOSTRING(PREFIX));
751   if (NewShareDirectory.endsWith("/")) NewShareDirectory.chop(1);
752   NewShareDirectory.append("/share/photivo/");
753 #else
754   QString NewShareDirectory = QCoreApplication::applicationDirPath().append("/");
755 #endif
756   ShareDirectory = NewShareDirectory;
757 
758   QFileInfo SettingsFileInfo(SettingsFileName);
759 //  short NeedInitialization = 1;
760   short FirstStart = 1;
761   if (SettingsFileInfo.exists() &&
762           SettingsFileInfo.isFile() &&
763           SettingsFileInfo.isReadable()) {
764       // photivo was initialized
765 //      NeedInitialization = 0;
766       FirstStart = 0;
767       printf("Existing settingsfile '%s'\n",SettingsFileName.toLocal8Bit().data());
768   } else {
769       printf("New settingsfile '%s'\n",SettingsFileName.toLocal8Bit().data());
770   }
771 
772   printf("User directory: '%s'; \n",UserDirectory.toLocal8Bit().data());
773   printf("Share directory: '%s'; \n",NewShareDirectory.toLocal8Bit().data());
774 
775   // We need to load the translation before the ptSettings
776   QSettings* TempSettings = new QSettings(SettingsFileName, QSettings::IniFormat);
777 
778 //  if (TempSettings->value("SettingsVersion",0).toInt() < PhotivoSettingsVersion)
779 //      NeedInitialization = 1;
780 
781   // Initialize the user folder if needed
782   /* TODO: for testing. Enable the other line below once profile versions are final. */
783   if (IsPortableProfile == 0) {
784       //if (NeedInitialization == 1 && IsPortableProfile == 0) {
785       printf("Initializing/Updating user profile...\n");
786       QFile::remove(UserDirectory + "photivo.png");
787       QFile::copy(NewShareDirectory + "photivo.png",
788               UserDirectory + "photivo.png");
789 //      QFile::remove(UserDirectory + "photivoLogo.png");
790 //      QFile::copy(NewShareDirectory + "photivoLogo.png",
791 //              UserDirectory + "photivoLogo.png");
792       QFile::remove(UserDirectory + "photivoPreview.jpg");
793       QFile::copy(NewShareDirectory + "photivoPreview.jpg",
794               UserDirectory + "photivoPreview.jpg");
795       QStringList SourceFolders;
796       SourceFolders << NewShareDirectory + "Translations"
797           << NewShareDirectory + "Curves"
798           << NewShareDirectory + "ChannelMixers"
799           << NewShareDirectory + "Presets"
800           << NewShareDirectory + "Profiles"
801           << NewShareDirectory + "LensfunDatabase"
802           << NewShareDirectory + "UISettings";
803       QStringList DestFolders;
804       DestFolders << UserDirectory + "Translations"
805           << UserDirectory + "Curves"
806           << UserDirectory + "ChannelMixers"
807           << UserDirectory + "Presets"
808           << UserDirectory + "Profiles"
809           << UserDirectory + "LensfunDatabase"
810           << UserDirectory + "UISettings";
811 
812       for (int i = 0; i < SourceFolders.size(); i++) {
813           copyFolder(SourceFolders.at(i), DestFolders.at(i));
814       }
815   }
816 
817 
818   // Load Translation
819   int TranslMode = TempSettings->value("TranslationMode",0).toInt();
820   QDir TranslDir(UserDirectory + "Translations");
821   QStringList UiLanguages = TranslDir.entryList(QStringList("photivo_*.qm"), QDir::Files|QDir::Readable, QDir::Name).replaceInStrings(".qm", "", Qt::CaseInsensitive);
822   UiLanguages.replaceInStrings("photivo_", "", Qt::CaseInsensitive);
823   int LangIdx = -1;
824 
825   if (TranslMode == 1) {
826       LangIdx = UiLanguages.indexOf(TempSettings->value("UiLanguage","").toString());
827       if (LangIdx >= 0) {
828           QTranslator qtTranslator;
829           appTranslator.load("photivo_" + UiLanguages[LangIdx], UserDirectory + "Translations");
830           TheApplication->installTranslator(&appTranslator);
831           qtTranslator.load("qt_" + UiLanguages[LangIdx], UserDirectory + "Translations");
832           TheApplication->installTranslator(&qtTranslator);
833           printf("Enabled translation: \"%s\".\n", UiLanguages[LangIdx].toLocal8Bit().data());
834       }
835   }
836 
837   delete TempSettings;
838 
839   // Persistent settings.
840   // fixed the remember level to 2, since we have settings files now
841   short RememberSettingLevel = 2;
842 
843   // Load the Settings (are also partly used in JobMode)
844   Settings = new ptSettings(RememberSettingLevel, UserDirectory);
845 
846   // Set directories for needed files
847   Settings->SetValue("UserDirectory", UserDirectory);
848   Settings->SetValue("ShareDirectory",NewShareDirectory);
849   Settings->SetValue("MainDirectory",QCoreApplication::applicationDirPath().append("/"));
850   Settings->SetValue("Sidecar", Sidecar);
851 
852   // Set paths once with first start
853   if (FirstStart == 1) {
854       Settings->SetValue("RawsDirectory", UserDirectory);
855       Settings->SetValue("OutputDirectory", UserDirectory);
856       Settings->SetValue("UIDirectory", UserDirectory + "UISettings");
857       Settings->SetValue("PresetDirectory", UserDirectory + "Presets");
858       Settings->SetValue("CurvesDirectory", UserDirectory + "Curves");
859       Settings->SetValue("ChannelMixersDirectory", UserDirectory + "ChannelMixers");
860       Settings->SetValue("TranslationsDirectory", UserDirectory + "Translations");
861       Settings->SetValue("CameraColorProfilesDirectory", UserDirectory + "Profiles/Camera");
862       Settings->SetValue("PreviewColorProfilesDirectory", UserDirectory + "Profiles/Preview");
863       Settings->SetValue("OutputColorProfilesDirectory", UserDirectory + "Profiles/Output");
864       Settings->SetValue("StandardAdobeProfilesDirectory", UserDirectory + "Profiles/Camera/Standard");
865       Settings->SetValue("LensfunDatabaseDirectory", UserDirectory + "LensfunDatabase");
866       Settings->SetValue("PreviewColorProfile", UserDirectory + "Profiles/Preview/sRGB.icc");
867       Settings->SetValue("OutputColorProfile", UserDirectory + "Profiles/Output/sRGB.icc");
868       Settings->SetValue("StartupSettingsFile", UserDirectory + "Presets/MakeFancy.pts");
869   }
870 
871   // Initialize patterns (after translation)
872   InitStrings();
873 
874   // Init filter data module
875   ptFilterDM::CreateInstance();
876   CreateAllFilters();
877 
878   // Load also the LensfunDatabase.
879   printf("Lensfun database: '%s'; \n",Settings->GetString("LensfunDatabaseDirectory").toLocal8Bit().data());
880   //  LensfunData = new ptLensfun;    // TODO BJ: implement lensfun DB
881 
882   // Instantiate the processor. Spot models are not set here because we
883   // do not yet know if we are in GUI or batch mode.
884   TheProcessor = new ptProcessor(ReportProgress);
885 
886   // First check if we are maybe started as a command line with options.
887   // (And thus have to run a batch job)
888 
889   if (JobMode) {
890     RunJob(JobFileName);
891     exit(EXIT_SUCCESS);
892   }
893 
894   // If falling through to here we are in an interactive non-job mode.
895   // Start op the Gui stuff.
896 
897   // Start the theme class
898   Theme = new ptTheme(TheApplication,
899                       (ptTheme::Theme)Settings->GetInt("Style"),
900                       (ptTheme::Highlight)Settings->GetInt("StyleHighLight"));
901   Theme->setCustomCSS(Settings->GetString("CustomCSSFile"));
902 
903   GuiOptions = new ptGuiOptions();
904 
905   // Open and keep open the profile for previewing.
906   PreviewColorProfile = cmsOpenProfileFromFile(
907           Settings->GetString("PreviewColorProfile").toLocal8Bit().data(),
908           "r");
909   if (!PreviewColorProfile) {
910       ptLogError(ptError_FileOpen,
911               Settings->GetString("PreviewColorProfile").toLocal8Bit().data());
912       return ptError_FileOpen;
913   }
914 
915   // When loading a file via cli, set file manager directory to that path.
916   // Chances are good the user want to work with other files from that dir as well
917   if (!JobMode && !ImageCleanUp && (ImageFileToOpen != "")) {
918     Settings->SetValue("LastFileMgrLocation", QFileInfo(ImageFileToOpen).absolutePath());
919   }
920 
921 #ifndef PT_WITHOUT_FILEMGR
922   Settings->SetValue("PreventFileMgrStartup", int(cli.NoOpenFileMgr));
923 #endif
924 
925   // Construct windows
926   MainWindow = new ptMainWindow(QObject::tr("Photivo"));
927   QObject::connect(TheApplication, SIGNAL(messageReceived(const QString &)),
928                    MainWindow, SLOT(OtherInstanceMessage(const QString &)));
929   TheApplication->setActivationWindow(MainWindow);
930 
931   ViewWindow =
932       new ptViewWindow(MainWindow->ViewFrameCentralWidget, MainWindow);
933 
934   ViewWindow->SetPixelReader(CB_PixelReader);
935 
936   HistogramWindow =
937       new ptHistogramWindow(NULL,MainWindow->HistogramFrameCentralWidget);
938 
939 #ifndef PT_WITHOUT_FILEMGR
940   FileMgrWindow = new ptFileMgrWindow(MainWindow->FileManagerPage);
941   MainWindow->FileManagerLayout->addWidget(FileMgrWindow);
942   QObject::connect(FileMgrWindow, SIGNAL(fileMgrWindowClosed()),
943                    MainWindow, SLOT(CloseFileMgrWindow()));
944   QObject::connect(ViewWindow, SIGNAL(openFileMgr()), MainWindow, SLOT(OpenFileMgrWindow()));
945 #endif
946   QObject::connect(ViewWindow, SIGNAL(openBatch()), MainWindow, SLOT(OpenBatchWindow()));
947 
948   BatchWindow = new ptBatchWindow(MainWindow->BatchPage);
949   MainWindow->BatchLayout->addWidget(BatchWindow);
950   QObject::connect(BatchWindow, SIGNAL(BatchWindowClosed()), MainWindow, SLOT(CloseBatchWindow()));
951 
952   // Populate Translations combobox
953   MainWindow->PopulateTranslationsCombobox(UiLanguages, LangIdx);
954 
955   // Theming
956   CB_StyleChoice(Settings->GetInt("Style"));
957 
958   SetBackgroundColor(Settings->GetInt("BackgroundColor"));
959 
960   MainWindow->UpdateToolBoxes();
961 
962 
963   //-------------------------------------
964   // Initialize main window geometry and position
965   // If the screen is not longer present, we move the window to the standard screen
966 
967   int      Screen        = Settings->m_IniSettings->value("MainWindowScreen", -1).toInt();
968   if (Screen >= qApp->desktop()->screenCount()) {
969     Screen = -1;
970   }
971   QRect    DesktopRect   = qApp->desktop()->screenGeometry(Screen);
972   QPoint   UpperLeft     = DesktopRect.topLeft() + QPoint(30, 30);
973   QPoint   MainWindowPos = Settings->m_IniSettings->value("MainWindowPos", UpperLeft).toPoint();
974   QVariant WinSize       = Settings->m_IniSettings->value("MainWindowSize");
975   QSize    MainWindowSize;
976 
977   if (!DesktopRect.contains(MainWindowPos)) {
978     MainWindowPos = UpperLeft;
979   }
980 
981   if(!WinSize.isValid() ||
982      !(WinSize.toSize().width()  < DesktopRect.width()  + 50 &&
983        WinSize.toSize().height() < DesktopRect.height() + 50   )) {
984     // ensure a reasonable size if we don’t get one from Settings
985     MainWindowSize = QSize(qMin(1200, (int)(DesktopRect.width()  * 0.8)),
986                            qMin( 900, (int)(DesktopRect.height() * 0.8)) );
987   } else {
988     MainWindowSize = WinSize.toSize();
989   }
990 
991   MainWindow->resize(MainWindowSize);
992   MainWindow->move(  MainWindowPos);
993 
994   // MainSplitter is the one between tool pane and image pane.
995   // ControlSplitter is the one between histogram and tools tabwidget.
996   QVariant splitterState = Settings->m_IniSettings->value("MainSplitter");
997   if (splitterState.isValid()) {
998     MainWindow->MainSplitter->restoreState(splitterState.toByteArray());
999   } else {
1000     // 10000 width for image pane to ensure the 300 for tool pane
1001     MainWindow->MainSplitter->setSizes(QList<int>() << 300 << 10000);
1002   }
1003 
1004   splitterState = Settings->m_IniSettings->value("ControlSplitter");
1005   if (splitterState.isValid()) {
1006     MainWindow->ControlSplitter->restoreState(splitterState.toByteArray());
1007   } else {
1008     MainWindow->ControlSplitter->setSizes(QList<int>() << 100 << 10000);
1009   }
1010 
1011   if (Settings->m_IniSettings->value("IsMaximized",0).toBool()) {
1012     MainWindow->showMaximized();
1013   } else {
1014     MainWindow->show();
1015   }
1016   //-------------------------------------
1017 
1018 
1019   // Update the preview image will result in displaying the splash.
1020   Update(ptProcessorPhase_Preview);
1021 
1022   // Open and keep open the profile for previewing.
1023   PreviewColorProfile = cmsOpenProfileFromFile(
1024           Settings->GetString("PreviewColorProfile").toLocal8Bit().data(),
1025           "r");
1026   if (!PreviewColorProfile) {
1027       ptLogError(ptError_FileOpen,
1028               Settings->GetString("PreviewColorProfile").toLocal8Bit().data());
1029       assert(PreviewColorProfile);
1030   }
1031 
1032   try {
1033     // Start event loops.
1034     return TheApplication->exec();
1035   } catch (const exception& E) {
1036     GInfo->Raise(E.what(), AT);
1037   } catch (...) {
1038     GInfo->Raise("Unknown error.", AT);
1039   }
1040   return 1;
1041 }
1042 
1043   ////////////////////////////////////////////////////////////////////////////////
1044   //
1045   // This is only needed for the gimp integration.
1046   // Calling over and over photivoMain would otherwise leak like hell
1047   // (or any comparable place).
1048   //
1049   ////////////////////////////////////////////////////////////////////////////////
1050 
CleanupResources()1051   void CleanupResources() {
1052       //printf("(%s,%d) qApp:%p\n",__FILE__,__LINE__,qApp);
1053       // Not : is done at CB for the exit.
1054       // delete Settings; // Don't, is done at CB_MenuFileExit
1055       // Also : do not delete items which are handled by MainWindow, such as
1056       // ViewWindow or HistogramWindow or CurveWindows
1057       //  delete LensfunData;    // TODO BJ: implement lensfun DB
1058       delete TheProcessor;
1059       delete GuiOptions;
1060       delete MainWindow;  // Cleans up HistogramWindow and ViewWindow also !
1061       ViewWindow = NULL;  // needs to be NULL to properly construct MainWindow
1062       delete PreviewImage;
1063       delete TheDcRaw;
1064 }
ExtFileOpen(const QString file)1065 void   ExtFileOpen(const QString file){
1066     ImageFileToOpen = file;
1067     CB_MenuFileOpen(1);
1068 }
1069 
1070 ////////////////////////////////////////////////////////////////////////////////
1071 
ptRemoveFile(const QString FileName)1072 void ptRemoveFile( const QString FileName) {
1073   if (QMessageBox::Yes == ptMessageBox::question(
1074                  MainWindow,
1075                  QObject::tr("Clean up input file"),
1076                  "As requested, Photivo will delete the input file " + FileName + ". Proceed?",
1077                  QMessageBox::No|QMessageBox::Yes)) {
1078     QFile::remove(FileName);
1079   }
1080 }
1081 
1082 ////////////////////////////////////////////////////////////////////////////////
1083 //
1084 // Hack : called at t=0 after the event loop started.
1085 //
1086 ////////////////////////////////////////////////////////////////////////////////
1087 
CB_Event0()1088 void CB_Event0() {
1089   // Init Curves : supposed to be in event loop indeed.
1090   // (f.i. for progress reporting)
1091   QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1092   if (Settings->GetInt("JobMode") == 0)
1093     SaveButtonToolTip(Settings->GetInt("SaveButtonMode"));
1094 
1095   // Fill some look up tables
1096 #pragma omp parallel for
1097   for (uint32_t i=0; i<0x10000; i++) {
1098     // uint16_t (0,0xffff) to float (0.0, 1.0)
1099     ToFloatTable[i]     = (float)i*ptInvWP;
1100     ToFloatABNeutral[i] = (float)i-ptWPHLab;
1101     ToInvertTable[i]    = ptWP - i;
1102     // linear RGB to sRGB table
1103     if (ToFloatTable[i] <= 0.0031308)
1104       ToSRGBTable[i] = CLIP((int32_t)(12.92*i));
1105     else
1106       ToSRGBTable[i] = CLIP((int32_t)((1.055*pow(ToFloatTable[i],1.0/2.4)-0.055)*ptWPf));
1107   }
1108 
1109   // Init run mode
1110   NextPhase = ptProcessorPhase_Raw;
1111   NextSubPhase = ptProcessorPhase_Load;
1112   ImageSaved = 0;
1113 
1114   PreCalcTransforms();
1115 
1116   if (Settings->GetInt("JobMode") == 0) { // not job mode!
1117     MainWindow->Settings_2_Form();
1118 
1119     // Load user settings
1120     if (Settings->GetInt("StartupSettings")) {
1121       if (ImageCleanUp == 0) {
1122         CB_OpenSettingsFile(Settings->GetString("StartupSettingsFile"));
1123       } else { // we got an image from gimp -> neutral display
1124         CB_OpenSettingsFile(Settings->GetString("PresetDirectory") + "/Neutral_absolute.pts");
1125       }
1126       // clean up
1127       QStringList Temp;
1128       Temp << "CropX" << "CropY" << "CropW" << "CropH";
1129       Temp << "RotateW" << "RotateH";
1130       for (int i = 0; i < Temp.size(); i++) Settings->SetValue(Temp.at(i),0);
1131     }
1132 
1133     if (PtsFileToOpen != "") {
1134       CB_OpenSettingsFile(PtsFileToOpen);
1135     }
1136 
1137     if (Sidecar != "") {
1138       ReadSidecar(Sidecar);
1139     }
1140 
1141     if (ImageFileToOpen != "") {
1142       CB_MenuFileOpen(1);
1143     }
1144     MainWindow->UpdateSettings();
1145     ViewWindow->setFocus();
1146     HistogramWindow->Init();
1147   }
1148 
1149   if (Settings->GetStringList("FavouriteTools").isEmpty()) {
1150     Settings->SetValue(
1151       "FavouriteTools",
1152       QStringList({
1153         "TabWhiteBalance",
1154         "TabRotation",
1155         "TabCrop",
1156         Fuid::ReinhardBrighten_RGB,
1157         Fuid::TextureContrast2_LabCC,
1158         Fuid::DetailCurve_LabSN,
1159         Fuid::Vignette_LabEyeCandy,
1160         Fuid::SigContrastRgb_Out
1161       })
1162     );
1163   }
1164 
1165 #ifndef PT_WITHOUT_FILEMGR
1166   if (Settings->GetInt("FileMgrIsOpen")) {
1167     FileMgrWindow->displayThumbnails();
1168     FileMgrWindow->setFocus(Qt::OtherFocusReason);
1169   }
1170 #endif
1171 
1172 //prepare for further QFileOpenEvent(s)
1173 #ifdef Q_OS_MAC
1174   TheApplication->macinit();
1175 #endif
1176 
1177   InStartup = 0;
1178 }
1179 
1180 ////////////////////////////////////////////////////////////////////////////////
1181 //
1182 // Precalculation of color transforms
1183 //
1184 ////////////////////////////////////////////////////////////////////////////////
1185 
PreCalcTransforms()1186 void PreCalcTransforms() {
1187   cmsToneCurve* Gamma = cmsBuildGamma(NULL, 1.0);
1188   cmsToneCurve* Gamma3[3];
1189   Gamma3[0] = Gamma3[1] = Gamma3[2] = Gamma;
1190 
1191   cmsHPROFILE InProfile = 0;
1192 
1193   cmsCIExyY DFromReference;
1194 
1195   switch (Settings->GetInt("WorkColor")) {
1196     case ptSpace_sRGB_D65 :
1197     case ptSpace_AdobeRGB_D65 :
1198       DFromReference = D65;
1199       break;
1200     case ptSpace_WideGamutRGB_D50 :
1201     case ptSpace_ProPhotoRGB_D50 :
1202       DFromReference = D50;
1203       break;
1204     default:
1205       assert(0);
1206   }
1207 
1208   ptImage::setCurrentRGB(Settings->GetInt("WorkColor"));
1209 
1210   InProfile = cmsCreateRGBProfile(&DFromReference,
1211                                   (cmsCIExyYTRIPLE*)&RGBPrimaries[Settings->GetInt("WorkColor")],
1212                                   Gamma3);
1213 
1214   if (!InProfile) {
1215     ptLogError(ptError_Profile,"Could not open InProfile profile.");
1216     return;
1217   }
1218 
1219   cmsFreeToneCurve(Gamma);
1220 
1221   if (Settings->GetInt("CMQuality") == ptCMQuality_HighResPreCalc) {
1222     ToPreviewTransform =
1223       cmsCreateTransform(InProfile,
1224                          TYPE_RGB_16,
1225                          PreviewColorProfile,
1226                          TYPE_RGB_16,
1227                          Settings->GetInt("PreviewColorProfileIntent"),
1228                          cmsFLAGS_HIGHRESPRECALC | cmsFLAGS_BLACKPOINTCOMPENSATION);
1229   } else { // fast sRGB preview also uses the not optimized profile for output
1230     ToPreviewTransform =
1231       cmsCreateTransform(InProfile,
1232                          TYPE_RGB_16,
1233                          PreviewColorProfile,
1234                          TYPE_RGB_16,
1235                          Settings->GetInt("PreviewColorProfileIntent"),
1236                          cmsFLAGS_NOOPTIMIZE | cmsFLAGS_BLACKPOINTCOMPENSATION);
1237   }
1238 
1239   cmsCloseProfile(InProfile);
1240 }
1241 
1242 ////////////////////////////////////////////////////////////////////////////////
1243 //
1244 // Copy folder
1245 //
1246 ////////////////////////////////////////////////////////////////////////////////
1247 
copyFolder(QString sourceFolder,QString destFolder)1248 void copyFolder(QString sourceFolder, QString destFolder)
1249 {
1250   QDir sourceDir(sourceFolder);
1251   if(!sourceDir.exists())
1252     return;
1253   QDir destDir(destFolder);
1254   if(!destDir.exists())
1255   {
1256     destDir.mkdir(destFolder);
1257   }
1258   QStringList files = sourceDir.entryList(QDir::Files);
1259   for(int i = 0; i< files.count(); i++)
1260   {
1261     QString srcName = sourceFolder + "/" + files[i];
1262     QString destName = destFolder + "/" + files[i];
1263     QFile::remove(destName);
1264     QFile::copy(srcName, destName);
1265   }
1266   files.clear();
1267   files = sourceDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
1268   for(int i = 0; i< files.count(); i++)
1269   {
1270     QString srcName = sourceFolder + "/" + files[i];
1271     QString destName = destFolder + "/" + files[i];
1272     copyFolder(srcName, destName);
1273   }
1274 }
1275 
1276 ////////////////////////////////////////////////////////////////////////////////
1277 //
1278 // Update
1279 //
1280 ////////////////////////////////////////////////////////////////////////////////
1281 
Update(short Phase,short SubPhase,short WithIdentify,short ProcessorMode)1282 void Update(short Phase,
1283             short SubPhase      /* = -1 */,
1284             short WithIdentify  /* = 1 */,
1285             short ProcessorMode /* = ptProcessorMode_Preview */)
1286 {
1287 #ifdef Q_OS_WIN
1288   ptEcWin7* Win7Taskbar = NULL;
1289   if (!JobMode) {
1290     Win7Taskbar = ptEcWin7::GetInstance();
1291     Win7Taskbar->setProgressState(ptEcWin7::Indeterminate);
1292   }
1293 #endif
1294 
1295   if (Settings->GetInt("BlockUpdate") == 1) return; // hard block
1296   if (Settings->GetInt("PipeIsRunning") == 1) {
1297     // record that we got here with the new settings
1298     // and make sure the pipe is run after the current
1299     // pass automatically -> timer
1300     return;
1301   } else Settings->SetValue("PipeIsRunning",1);
1302 
1303   if (Phase < ptProcessorPhase_Preview) {
1304     // main processing
1305     if (Phase < NextPhase) NextPhase = Phase;
1306     if (SubPhase > 0 && SubPhase < NextSubPhase) NextSubPhase = SubPhase;
1307     if (Settings->GetInt("RunMode") == 1) {
1308       // we're in manual mode!
1309       MainWindow->UpdateSettings();
1310     } else {
1311       try {
1312         // run processor!
1313         ImageSaved = 0;
1314         MainWindow->UpdateSettings();
1315         if(Settings->GetInt("HaveImage")==1) {
1316           if (NextPhase < ptProcessorPhase_Output)
1317             TheProcessor->Run(NextPhase, NextSubPhase, WithIdentify, ProcessorMode);
1318           UpdatePreviewImage();
1319         }
1320         NextPhase = ptProcessorPhase_Output;
1321         NextSubPhase = ptProcessorPhase_Highlights;
1322       } catch (std::bad_alloc) {
1323         // make sure we image gets processed again
1324         NextPhase = ptProcessorPhase_Raw;
1325         NextSubPhase = ptProcessorPhase_Load;
1326         ViewWindow->ShowStatus(ptStatus_Done);
1327         ReportProgress(QObject::tr("Ready"));
1328         if (Settings->GetInt("PipeSize") == 0) {
1329           ptMessageBox::critical(NULL, "Memory error", "Processing aborted, memory error.\nReverting to 1:2 pipe. Reprocess with F5.");
1330 
1331           Settings->SetValue("PipeSize",1);
1332         } else {
1333           ptMessageBox::critical(NULL, "Memory error", "Processing aborted, memory error.");
1334         }
1335       }
1336     }
1337   } else if (Phase == ptProcessorPhase_OnlyHistogram) {
1338     // only histogram update, don't care about manual mode
1339     UpdatePreviewImage(NULL,1);
1340   } else if (Phase == ptProcessorPhase_Preview) {
1341     // only preview update, don't care about manual mode
1342     UpdatePreviewImage(NULL,0);
1343   } else if (Phase == ptProcessorPhase_WriteOut) {
1344     // write output
1345     WriteOut();
1346   } else if (Phase == ptProcessorPhase_ToGimp) {
1347     // export
1348     Export(ptExportMode_GimpPipe);
1349   } else {
1350     // should not happen!
1351     assert(0);
1352   }
1353   Settings->SetValue("PipeIsRunning",0);
1354 
1355 #ifdef Q_OS_WIN
1356   if (!JobMode) {
1357     Win7Taskbar->setProgressState(ptEcWin7::NoProgress);
1358   }
1359 #endif
1360 }
1361 
1362 ////////////////////////////////////////////////////////////////////////////////
1363 //
1364 // Update
1365 // Overloaded function, expects toolname and will call Update
1366 //
1367 ////////////////////////////////////////////////////////////////////////////////
1368 
GetProcessorPhase(const QString GuiName)1369 int GetProcessorPhase(const QString GuiName) {
1370   int Phase = 0;
1371   QString Tab = MainWindow->ProcessingTabBook->widget(
1372                   MainWindow->m_GroupBox->value(GuiName)->parentTabIdx() )->objectName();
1373   if      (Tab == "LocalTab")       Phase = ptProcessorPhase_LocalEdit;
1374   else if (Tab == "GeometryTab")    Phase = ptProcessorPhase_Geometry;
1375   else if (Tab == "RGBTab")         Phase = ptProcessorPhase_RGB;
1376   else if (Tab == "LabCCTab")       Phase = ptProcessorPhase_LabCC;
1377   else if (Tab == "LabSNTab")       Phase = ptProcessorPhase_LabSN;
1378   else if (Tab == "LabEyeCandyTab") Phase = ptProcessorPhase_LabEyeCandy;
1379   else if (Tab == "EyeCandyTab")    Phase = ptProcessorPhase_EyeCandy;
1380   else if (Tab == "OutTab")         Phase = ptProcessorPhase_Output;
1381   else                              Phase = ptProcessorPhase_Raw;
1382   return Phase;
1383 }
1384 
1385 //==============================================================================
1386 
Update(const QString GuiName)1387 void Update(const QString GuiName) {
1388   int Phase = GetProcessorPhase(GuiName);
1389   // It is assumed that no tool before white balance will use this.
1390   if (Phase < 2) {
1391     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
1392   } else {
1393     Update(Phase);
1394   }
1395 }
1396 
1397 
1398 ////////////////////////////////////////////////////////////////////////////////
1399 //
1400 // Block tools
1401 //
1402 ////////////////////////////////////////////////////////////////////////////////
1403 
BlockTools(const ptBlockToolsMode ANewState,QStringList AExcludeIds=QStringList ())1404 void BlockTools(const ptBlockToolsMode ANewState, QStringList AExcludeIds = QStringList()) {
1405   // Set the object name of the widget that is excluded from blocking.
1406   switch (ANewState) {
1407     case btmBlockForCrop:
1408       AExcludeIds << "TabCrop";
1409       break;
1410     case btmBlockForSpotRepair:
1411       AExcludeIds << "TabSpotRepair";
1412       break;
1413     default:
1414       // nothing to do
1415       break;
1416   }
1417 
1418   bool EnabledStatus = ANewState == btmUnblock;
1419 
1420   // Handle all necessary widgets outside the processing tabbook
1421   MainWindow->HistogramFrameCentralWidget->setEnabled(EnabledStatus);
1422   MainWindow->SearchWidget->setEnabled(EnabledStatus);
1423   MainWindow->PipeControlWidget->setEnabled(EnabledStatus);
1424   MainWindow->StatusWidget->setEnabled(EnabledStatus);
1425 
1426   if (MainWindow->m_MovedTools->size() > 0) {
1427     /* Process moved tools list when UI is not in tab mode (e.g. showing favourites)
1428       We just cycle through the list of currently visible tools and en/disable them.
1429     */
1430     for (QWidget *hToolBox: *MainWindow->m_MovedTools) {
1431       if (!AExcludeIds.contains(hToolBox->objectName())) {
1432         if (hToolBox->objectName().contains("-"))  //new-style
1433           hToolBox->setEnabled(EnabledStatus);
1434         else                                       // old-style
1435           ((ptGroupBox*)hToolBox)->SetEnabled(EnabledStatus);
1436       }
1437     }
1438 
1439   } else {
1440     /* Process processing tabbook
1441       To avoid cycling through all ptGroupBox objects on every tab every time we use the following
1442       approach: We assume that the tabbook is switched to the appropriate tab when BlockTools() is
1443       called, i.e. the tab containing the filter that should not be blocked (if there is such a one).
1444       We en/disable all tabs except the current one completely. Now we only need to cycle through the
1445       remaining ptGroupBoxes on the current tab.
1446     */
1447     int CurrentTab = MainWindow->ProcessingTabBook->currentIndex();
1448 
1449     for (int i = 0; i < MainWindow->ProcessingTabBook->count(); i++) {
1450       if (i != CurrentTab)
1451         MainWindow->ProcessingTabBook->setTabEnabled(i, EnabledStatus);
1452     }
1453 
1454     QList<ptToolBox*> NewToolList =
1455         MainWindow->ProcessingTabBook->widget(CurrentTab)->findChildren<ptToolBox*>();
1456     foreach (ptToolBox* Tool, NewToolList) {
1457       if (!AExcludeIds.contains(Tool->objectName()))
1458         Tool->setEnabled(EnabledStatus);
1459     }
1460     QList<ptGroupBox*> ToolList =
1461         MainWindow->ProcessingTabBook->widget(CurrentTab)->findChildren<ptGroupBox*>();
1462     foreach (ptGroupBox* Tool, ToolList) {
1463       if (!AExcludeIds.contains(Tool->objectName()))
1464         Tool->SetEnabled(EnabledStatus);
1465     }
1466   }
1467 
1468   Settings->SetValue("BlockTools", ANewState);
1469 }
1470 
1471 ////////////////////////////////////////////////////////////////////////////////
1472 //
1473 // Histogram
1474 //
1475 ////////////////////////////////////////////////////////////////////////////////
1476 void HistogramCropDone(const ptStatus ExitStatus, QRect SelectionRect);
1477 
HistogramGetCrop()1478 void HistogramGetCrop() {
1479   // Get the crop for the histogram
1480   if (Settings->GetInt("HistogramCrop")) {
1481     // Allow to be selected in the view window. And deactivate main.
1482     BlockTools(btmBlockAll);
1483     ViewWindow->ShowStatus(QObject::tr("Selection"));
1484     ViewWindow->StartSimpleRect(HistogramCropDone);
1485     ViewWindow->setFocus();
1486   } else {
1487     ReportProgress(QObject::tr("Updating histogram"));
1488     Update(ptProcessorPhase_Preview);
1489     ReportProgress(QObject::tr("Ready"));
1490   }
1491 }
1492 
HistogramCropDone(const ptStatus ExitStatus,QRect SelectionRect)1493 void HistogramCropDone(const ptStatus ExitStatus, QRect SelectionRect) {
1494   // Selection is done at this point. Disallow it further and activate main.
1495   BlockTools(btmUnblock);
1496   if (ExitStatus == stFailure) {
1497     Settings->SetValue("HistogramCropX",0);
1498     Settings->SetValue("HistogramCropY",0);
1499     Settings->SetValue("HistogramCropW",0);
1500     Settings->SetValue("HistogramCropH",0);
1501     Settings->SetValue("HistogramCrop",0);
1502     return;
1503   }
1504 
1505   short XScale = 1<<Settings->GetInt("PipeSize");
1506   short YScale = 1<<Settings->GetInt("PipeSize");
1507 
1508   Settings->SetValue("HistogramCropX", SelectionRect.left() * XScale);
1509   Settings->SetValue("HistogramCropY", SelectionRect.top() * YScale);
1510   Settings->SetValue("HistogramCropW", SelectionRect.width() * XScale);
1511   Settings->SetValue("HistogramCropH", SelectionRect.height() * YScale);
1512 
1513   // Check if the chosen area is large enough
1514   if (Settings->GetInt("HistogramCropW") < 50 || Settings->GetInt("HistogramCropH") < 50) {
1515     ptMessageBox::information(0,
1516       QObject::tr("Selection too small"),
1517       QObject::tr("Selection rectangle needs to be at least 50x50 pixels in size.\nNo crop, try again."));
1518     Settings->SetValue("HistogramCropX",0);
1519     Settings->SetValue("HistogramCropY",0);
1520     Settings->SetValue("HistogramCropW",0);
1521     Settings->SetValue("HistogramCropH",0);
1522     Settings->SetValue("HistogramCrop",0);
1523   }
1524 
1525   ReportProgress(QObject::tr("Updating histogram"));
1526   Update(ptProcessorPhase_Preview);
1527   ReportProgress(QObject::tr("Ready"));
1528 }
1529 
1530 
1531 ////////////////////////////////////////////////////////////////////////////////
1532 //
1533 // Status report in Viewwindow
1534 //
1535 ////////////////////////////////////////////////////////////////////////////////
1536 
ViewWindowShowStatus(short State)1537 void ViewWindowShowStatus(short State) {
1538   if (ViewWindow) {
1539     ViewWindow->ShowStatus(State);
1540   }
1541 }
1542 
1543 ////////////////////////////////////////////////////////////////////////////////
1544 //
1545 // Operations done right before gamma and profile for whatever reason
1546 // Finalrun to allow filters only on the final run
1547 // Resize to forbid resizing (-> histogram only on crop)
1548 //
1549 ////////////////////////////////////////////////////////////////////////////////
1550 
BeforeGamma(ptImage * Image,const short FinalRun=0,const short Resize=1)1551 void BeforeGamma(ptImage* Image, const short FinalRun = 0, const short Resize = 1) {
1552 
1553   if (Settings->GetInt("WebResizeBeforeGamma")==1 && Resize) {
1554     if (FinalRun == 1) Settings->SetValue("FullOutput",1);
1555     if (Settings->ToolIsActive("TabWebResize")) {
1556       ReportProgress(QObject::tr("WebResizing"));
1557       Image->ptGMResize(Settings->GetInt("WebResizeScale"),
1558                         0,
1559                         Settings->GetInt("WebResizeFilter"),
1560                         Settings->GetInt("WebResizeDimension"));
1561     }
1562     if (FinalRun == 1) Settings->SetValue("FullOutput",0);
1563   }
1564 
1565   // TODO put these curves together as devicelink into lcms
1566 
1567   // BaseCurve.
1568   auto hFilter = GFilterDM->GetFilterFromName(Fuid::RgbCurve_Out);
1569   if (hFilter->isActive()) {
1570     ReportProgress(QObject::tr("Applying base curve"));
1571     hFilter->runFilter(Image);
1572   }
1573 
1574   //GammaCompensation
1575   if (Settings->ToolIsActive("TabGammaCompensation")) {
1576     ReportProgress(QObject::tr("Applying gamma compensation"));
1577     ptCurve* CompensationCurve = new ptCurve();
1578     CompensationCurve->setFromFunc(ptCurve::DeltaGammaTool,Settings->GetDouble("OutputGamma"),
1579               Settings->GetDouble("OutputLinearity"));
1580     Image->ApplyCurve(CompensationCurve,7);
1581     delete CompensationCurve;
1582   }
1583 }
1584 
1585 ////////////////////////////////////////////////////////////////////////////////
1586 //
1587 // Operations done after gamma and profile for whatever reason
1588 // Finalrun to allow filters only on the final run
1589 // Resize to forbid resizing (-> histogram only on crop)
1590 //
1591 ////////////////////////////////////////////////////////////////////////////////
1592 
AfterAll(ptImage * Image,const short FinalRun=0,const short Resize=1)1593 void AfterAll(ptImage* Image, const short FinalRun = 0, const short Resize = 1) {
1594   // Sigmoidal contrast
1595   auto hFilter = GFilterDM->GetFilterFromName(Fuid::SigContrastRgb_Out);
1596   if (hFilter->isActive()) {
1597     ReportProgress(QObject::tr("Applying RGB Contrast"));
1598     hFilter->runFilter(Image);
1599   }
1600 
1601   // After gamma curve
1602   hFilter = GFilterDM->GetFilterFromName(Fuid::AfterGammaCurve_Out);
1603   if (hFilter->isActive()) {
1604     ReportProgress(QObject::tr("Applying after gamma curve"));
1605     hFilter->runFilter(Image);
1606   }
1607 
1608   // WebResize for quality reasons done after output profile
1609   if (Settings->GetInt("WebResizeBeforeGamma")==0 && Resize) {
1610     if (FinalRun == 1) Settings->SetValue("FullOutput",1);
1611     if (Settings->ToolIsActive("TabWebResize")) {
1612       ReportProgress(QObject::tr("WebResizing"));
1613       Image->ptGMResize(Settings->GetInt("WebResizeScale"),
1614                         0,
1615                         Settings->GetInt("WebResizeFilter"),
1616                         Settings->GetInt("WebResizeDimension"));
1617     }
1618     if (FinalRun == 1) Settings->SetValue("FullOutput",0);
1619   }
1620 }
1621 
EndSharpen(ptImage * Image,cmsHPROFILE Profile,const int Intent)1622 void EndSharpen(ptImage* Image, cmsHPROFILE Profile, const int Intent) {
1623   ReportProgress(QObject::tr("Wiener Filter"));
1624   int InColorSpace = Image->m_ColorSpace;
1625   cmsHPROFILE InternalProfile = 0;
1626   if (Profile == NULL || InColorSpace != ptSpace_Profiled) {
1627     // linear case
1628     cmsToneCurve* Gamma = cmsBuildGamma(NULL, 1.0);
1629     cmsToneCurve* Gamma3[3];
1630     Gamma3[0] = Gamma3[1] = Gamma3[2] = Gamma;
1631 
1632     cmsCIExyY       DFromReference;
1633 
1634     switch (Image->m_ColorSpace) {
1635       case ptSpace_sRGB_D65 :
1636       case ptSpace_AdobeRGB_D65 :
1637         DFromReference = D65;
1638         break;
1639       case ptSpace_WideGamutRGB_D50 :
1640       case ptSpace_ProPhotoRGB_D50 :
1641         DFromReference = D50;
1642         break;
1643       default:
1644         assert(0);
1645     }
1646 
1647     InternalProfile = cmsCreateRGBProfile(&DFromReference,
1648                                     (cmsCIExyYTRIPLE*)&RGBPrimaries[Image->m_ColorSpace],
1649                                     Gamma3);
1650 
1651     if (!InternalProfile) {
1652       ptLogError(ptError_Profile,"Could not open InternalProfile profile.");
1653       return;
1654     }
1655 
1656     cmsFreeToneCurve(Gamma);
1657   } else {
1658     // profiled case
1659     InternalProfile = Profile;
1660   }
1661 
1662   cmsHPROFILE LabProfile = 0;
1663   LabProfile = cmsCreateLab4Profile(NULL);
1664   // to Lab
1665   cmsHTRANSFORM Transform;
1666   Transform = cmsCreateTransform(InternalProfile,
1667                                  TYPE_RGB_16,
1668                                  LabProfile,
1669                                  TYPE_Lab_16,
1670                                  Intent,
1671                                  cmsFLAGS_NOOPTIMIZE | cmsFLAGS_BLACKPOINTCOMPENSATION);
1672 
1673   int32_t Size = Image->m_Width*Image->m_Height;
1674   int32_t Step = 100000;
1675 #pragma omp parallel for schedule(static)
1676   for (int32_t i = 0; i < Size; i+=Step) {
1677     int32_t Length = (i+Step)<Size ? Step : Size - i;
1678     uint16_t* Tile = &(Image->m_Image[i][0]);
1679     cmsDoTransform(Transform,Tile,Tile,Length);
1680   }
1681   Image->m_ColorSpace = ptSpace_Lab;
1682   // Wiener Filter
1683   GFilterDM->GetFilterFromName(Fuid::Wiener_Out)->runFilter(Image);
1684 
1685   // to RGB
1686   Transform = cmsCreateTransform(LabProfile,
1687                                  TYPE_Lab_16,
1688                                  InternalProfile,
1689                                  TYPE_RGB_16,
1690                                  Intent,
1691                                  cmsFLAGS_NOOPTIMIZE | cmsFLAGS_BLACKPOINTCOMPENSATION);
1692 
1693 #pragma omp parallel for schedule(static)
1694   for (int32_t i = 0; i < Size; i+=Step) {
1695     int32_t Length = (i+Step)<Size ? Step : Size - i;
1696     uint16_t* Tile = &(Image->m_Image[i][0]);
1697     cmsDoTransform(Transform,Tile,Tile,Length);
1698   }
1699 
1700   cmsDeleteTransform(Transform);
1701   cmsCloseProfile(LabProfile);
1702   if (Profile == NULL || InColorSpace != ptSpace_Profiled)
1703     cmsCloseProfile(InternalProfile);
1704   Image->m_ColorSpace = InColorSpace;
1705 }
1706 
1707 ////////////////////////////////////////////////////////////////////////////////
1708 //
1709 // Determine and update the preview image.
1710 //
1711 // ForcedImage claims that this image should be previewed.
1712 // (somehow of a hack : it is used for the Crop function where
1713 // we want the user to present fast a  new image to be cropped without
1714 // having to calculate through the whole pipe).
1715 //
1716 // OnlyHistogram : hack to sync up the histogram when it was inactive.
1717 //
1718 ////////////////////////////////////////////////////////////////////////////////
1719 
UpdatePreviewImage(const ptImage * ForcedImage,const short OnlyHistogram)1720 void UpdatePreviewImage(const ptImage* ForcedImage   /* = NULL  */,
1721                         const short    OnlyHistogram /* = false */) {
1722 
1723   if (!PreviewImage) PreviewImage = new (ptImage);
1724 
1725   // If we don't have yet a m_Image_AfterGeometry we are in
1726   // startup condition and show the start screen
1727   if (!TheProcessor->m_Image_AfterGeometry) {
1728     MainWindow->ViewFrameStackedWidget->setCurrentWidget(MainWindow->ViewStartPage);
1729     return;
1730   }
1731 
1732   MainWindow->ViewFrameStackedWidget->setCurrentWidget(MainWindow->ViewFrameCentralWidget);
1733 
1734   // Fast display of an image, e.g. for cropping
1735   // -> no histogram
1736   // -> only exposure for better display
1737   // -> transfer to preview color space
1738   if (ForcedImage) {
1739     PreviewImage->Set(ForcedImage);
1740     if (Settings->GetDouble("CropExposure") != 0.0) {
1741       PreviewImage->Expose(pow(2,Settings->GetDouble("CropExposure")), TExposureClipMode::Ratio);
1742     }
1743     BeforeGamma(PreviewImage,0,0);
1744 
1745     // Convert from working space to screen space.
1746     // Using lcms and a standard sRGB or custom profile.
1747     ptImage* ReturnValue = PreviewImage->lcmsRGBToPreviewRGB(Settings->GetInt("CMQuality") == ptCMQuality_FastSRGB);
1748     if (!ReturnValue) {
1749       ptLogError(ptError_lcms,"lcmsRGBToPreviewRGB");
1750       assert(ReturnValue);
1751     }
1752     AfterAll(PreviewImage,0,0);
1753 
1754     ViewWindow->UpdateImage(PreviewImage);
1755     ReportProgress(QObject::tr("Ready"));
1756     return;
1757   }
1758 
1759   ViewWindow->ShowStatus(ptStatus_Updating);
1760   ReportProgress(QObject::tr("Updating preview image"));
1761 
1762   if (!HistogramImage) HistogramImage = new (ptImage);
1763 
1764   short ActiveTab = MainWindow->GetCurrentTab();
1765 
1766   Settings->SetValue("ShowExposureIndicatorSensor",0);
1767 
1768   // Determine first what is the current image.
1769   if (ForcedImage) {
1770     PreviewImage->Set(ForcedImage);
1771   } else if (Settings->GetInt("PreviewMode") == ptPreviewMode_End) {
1772     PreviewImage->Set(TheProcessor->m_Image_AfterEyeCandy);
1773   } else {
1774     if (!Settings->useRAWHandling()) ActiveTab = MAX(ptLocalTab, ActiveTab);
1775     switch (ActiveTab) {
1776       case ptCameraTab:
1777         Settings->SetValue("ShowExposureIndicatorSensor",1);
1778         if (Settings->GetInt("ExposureIndicatorSensor")) {
1779           PreviewImage->Set(TheDcRaw,
1780                              Settings->GetInt("WorkColor"));
1781         } else {
1782           PreviewImage->Set(TheProcessor->m_Image_AfterDcRaw);
1783         }
1784         break;
1785       case ptLocalTab:
1786         PreviewImage->Set(TheProcessor->m_Image_AfterLocalEdit);
1787         break;
1788       case ptGeometryTab:
1789         PreviewImage->Set(TheProcessor->m_Image_AfterGeometry);
1790         break;
1791       case ptRGBTab:
1792         PreviewImage->Set(TheProcessor->m_Image_AfterRGB);
1793         break;
1794       case ptLabCCTab:
1795         PreviewImage->Set(TheProcessor->m_Image_AfterLabCC);
1796         break;
1797       case ptLabSNTab:
1798         PreviewImage->Set(TheProcessor->m_Image_AfterLabSN);
1799         break;
1800       case ptLabEyeCandyTab:
1801         PreviewImage->Set(TheProcessor->m_Image_AfterLabEyeCandy);
1802         break;
1803       case ptEyeCandyTab:
1804       case ptOutTab:
1805         PreviewImage->Set(TheProcessor->m_Image_AfterEyeCandy);
1806         break;
1807       default:
1808         // Should not happen.
1809         assert(0);
1810     }
1811   }
1812 
1813   if (Settings->GetInt("HistogramMode")==ptHistogramMode_Linear) {
1814     HistogramImage->Set(PreviewImage);
1815     // If we are in a Tab preview mode and in the lab mode
1816     // we do the conversion to Lab in case it would not have been
1817     // done yet (due to suppressed for speed in absense of USM or L Curve).
1818     // This way the histogram is an L Histogram at this point.
1819     if ( (Settings->GetInt("PreviewMode") == ptPreviewMode_Tab) &&
1820          (ActiveTab == ptLabCCTab || ActiveTab == ptLabSNTab || ActiveTab == ptLabEyeCandyTab) &&
1821          (HistogramImage->m_ColorSpace != ptSpace_Lab) ) {
1822       HistogramImage->RGBToLab();
1823     }
1824   } else if (Settings->GetInt("HistogramMode")==ptHistogramMode_Output &&
1825              !(Settings->GetInt("HistogramCrop") && !Settings->GetInt("WebResize"))) {
1826     HistogramImage->Set(PreviewImage);
1827 
1828 
1829   } else if (Settings->GetInt("HistogramCrop")) {
1830     HistogramImage->Set(PreviewImage);
1831   }
1832 
1833   if (PreviewImage->m_ColorSpace == ptSpace_Lab)
1834     PreviewImage->LabToRGB(Settings->GetInt("WorkColor"));
1835 
1836   uint16_t Width = 0;
1837   uint16_t Height = 0;
1838   uint16_t TempCropX = 0;
1839   uint16_t TempCropY = 0;
1840   uint16_t TempCropW = 0;
1841   uint16_t TempCropH = 0;
1842 
1843   if (Settings->GetInt("HistogramMode")==ptHistogramMode_Linear) {
1844     ReportProgress(QObject::tr("Updating histogram"));
1845 
1846     if (Settings->GetInt("HistogramCrop")) {
1847       float TmpScaled = TheProcessor->m_ScaleFactor;
1848       Width = HistogramImage->m_Width;
1849       Height = HistogramImage->m_Height;
1850       TempCropX = Settings->GetInt("HistogramCropX")*TmpScaled;
1851       TempCropY = Settings->GetInt("HistogramCropY")*TmpScaled;
1852       TempCropW = Settings->GetInt("HistogramCropW")*TmpScaled;
1853       TempCropH = Settings->GetInt("HistogramCropH")*TmpScaled;
1854       if ((((TempCropX) + (TempCropW)) > Width) ||
1855           (((TempCropY) + (TempCropH)) >  Height)) {
1856         ptMessageBox::information(MainWindow,
1857                QObject::tr("Histogram selection outside the image"),
1858                QObject::tr("Histogram selection rectangle too large.\nNo crop, try again."));
1859         Settings->SetValue("HistogramCropX",0);
1860         Settings->SetValue("HistogramCropY",0);
1861         Settings->SetValue("HistogramCropW",0);
1862         Settings->SetValue("HistogramCropH",0);
1863         Settings->SetValue("HistogramCrop",0);
1864       } else {
1865         HistogramImage->Crop(TempCropX, TempCropY, TempCropW, TempCropH);
1866       }
1867     }
1868 
1869     // In case of histogram update only, we're done.
1870     if (OnlyHistogram) {
1871       HistogramWindow->UpdateView(HistogramImage);
1872       ViewWindow->ShowStatus(ptStatus_Done);
1873       return;
1874     }
1875   }
1876 
1877   uint8_t ExposureChannelMask = 0;
1878   uint16_t OverExposureLevel[3];
1879   uint16_t UnderExposureLevel[3];
1880   if (Settings->GetInt("ExposureIndicator")) {
1881     ReportProgress(QObject::tr("Indicating exposure"));
1882 
1883     if (Settings->GetInt("ExposureIndicatorR")) ExposureChannelMask |= 1;
1884     if (Settings->GetInt("ExposureIndicatorG")) ExposureChannelMask |= 2;
1885     if (Settings->GetInt("ExposureIndicatorB")) ExposureChannelMask |= 4;
1886 
1887     if (ActiveTab == ptCameraTab && Settings->GetInt("ExposureIndicatorSensor")){
1888       OverExposureLevel[0] = CLIP((int32_t)
1889         ((TheDcRaw->m_WhiteLevel_AfterPhase1-TheDcRaw->m_BlackLevel_AfterPhase1)
1890         *TheDcRaw->m_Multipliers[0]));
1891       OverExposureLevel[1] = CLIP((int32_t)
1892         ((TheDcRaw->m_WhiteLevel_AfterPhase1-TheDcRaw->m_BlackLevel_AfterPhase1)
1893         *TheDcRaw->m_Multipliers[1]));
1894       OverExposureLevel[2] = CLIP((int32_t)
1895         ((TheDcRaw->m_WhiteLevel_AfterPhase1-TheDcRaw->m_BlackLevel_AfterPhase1)
1896         *TheDcRaw->m_Multipliers[2]));
1897       UnderExposureLevel[0] = 0x0000;
1898       UnderExposureLevel[1] = 0x0000;
1899       UnderExposureLevel[2] = 0x0000;
1900     } else {
1901       OverExposureLevel[0] = 0xfff0;
1902       OverExposureLevel[1] = 0xfff0;
1903       OverExposureLevel[2] = 0xfff0;
1904       UnderExposureLevel[0] = 0x000f;
1905       UnderExposureLevel[1] = 0x000f;
1906       UnderExposureLevel[2] = 0x000f;
1907     }
1908   }
1909 
1910   if (!ForcedImage) {
1911     BeforeGamma(PreviewImage);
1912   }
1913 
1914   if (Settings->GetInt("HistogramMode")==ptHistogramMode_Output) {
1915 
1916     ReportProgress(QObject::tr("Updating histogram"));
1917     if (Settings->GetInt("HistogramCrop") && !Settings->GetInt("WebResize")) {
1918       HistogramImage->Set(PreviewImage);
1919     } else {
1920       BeforeGamma(HistogramImage,0,0);
1921     }
1922 
1923     ReportProgress(QObject::tr("Converting to output space"));
1924 
1925     cmsHPROFILE OutputColorProfile = NULL;
1926     OutputColorProfile = cmsOpenProfileFromFile(
1927                          Settings->GetString("OutputColorProfile").toLocal8Bit().data(), "r");
1928     if (!OutputColorProfile) {
1929       ptLogError(ptError_FileOpen,
1930         Settings->GetString("OutputColorProfile").toLocal8Bit().data());
1931       assert(OutputColorProfile);
1932     }
1933 
1934     // Convert from working space to screen space.
1935     // Using lcms and a standard sRGB or custom profile.
1936 
1937     ptImage* ReturnValue = HistogramImage->lcmsRGBToRGB(
1938       OutputColorProfile,
1939       Settings->GetInt("OutputColorProfileIntent"),
1940       Settings->GetInt("CMQuality"));
1941     if (!ReturnValue) {
1942       ptLogError(ptError_lcms,"lcmsRGBToRGB(OutputColorProfile)");
1943       assert(ReturnValue);
1944     }
1945 
1946     if (Settings->GetInt("HistogramCrop") && !Settings->GetInt("WebResize")) {
1947       AfterAll(HistogramImage);
1948       if (GFilterDM->GetFilterFromName(Fuid::Wiener_Out)->isActive() &&
1949           Settings->GetInt("PreviewMode") == ptPreviewMode_End)
1950       {
1951         EndSharpen(HistogramImage, OutputColorProfile, Settings->GetInt("OutputColorProfileIntent"));
1952       }
1953     } else {
1954       AfterAll(HistogramImage,0,0);
1955       if (GFilterDM->GetFilterFromName(Fuid::Wiener_Out)->isActive() &&
1956           Settings->GetInt("PreviewMode") == ptPreviewMode_End)
1957       {
1958         EndSharpen(HistogramImage, OutputColorProfile, Settings->GetInt("OutputColorProfileIntent"));
1959       }
1960     }
1961 
1962     // Close the output profile.
1963     cmsCloseProfile(OutputColorProfile);
1964 
1965     if (Settings->GetInt("HistogramCrop")) {
1966       float TmpScaled = TheProcessor->m_ScaleFactor;
1967       Width = HistogramImage->m_Width;
1968       Height = HistogramImage->m_Height;
1969       TempCropX = Settings->GetInt("HistogramCropX")*TmpScaled;
1970       TempCropY = Settings->GetInt("HistogramCropY")*TmpScaled;
1971       TempCropW = Settings->GetInt("HistogramCropW")*TmpScaled;
1972       TempCropH = Settings->GetInt("HistogramCropH")*TmpScaled;
1973       if ((((TempCropX) + (TempCropW)) >  Width) ||
1974           (((TempCropY) + (TempCropH)) >  Height)) {
1975         ptMessageBox::information(MainWindow,
1976           QObject::tr("Histogram selection outside the image"),
1977           QObject::tr("Histogram selection rectangle too large.\nNo crop, try again."));
1978         Settings->SetValue("HistogramCropX",0);
1979         Settings->SetValue("HistogramCropY",0);
1980         Settings->SetValue("HistogramCropW",0);
1981         Settings->SetValue("HistogramCropH",0);
1982         Settings->SetValue("HistogramCrop",0);
1983       } else {
1984         HistogramImage->Crop(TempCropX, TempCropY, TempCropW, TempCropH);
1985       }
1986     }
1987     if (OnlyHistogram) {
1988       HistogramWindow->UpdateView(HistogramImage);
1989       ViewWindow->ShowStatus(ptStatus_Done);
1990       return;
1991     }
1992   }
1993 
1994   ReportProgress(QObject::tr("Converting to screen space"));
1995 
1996   // Convert from working space to screen space.
1997   // Using lcms and a standard sRGB or custom profile.
1998   PreviewImage->lcmsRGBToPreviewRGB(Settings->GetInt("CMQuality") == ptCMQuality_FastSRGB);
1999 
2000   if (!ForcedImage) {
2001     AfterAll(PreviewImage);
2002     if (GFilterDM->GetFilterFromName(Fuid::Wiener_Out)->isActive() &&
2003         Settings->GetInt("PreviewMode") == ptPreviewMode_End)
2004     {
2005       EndSharpen(PreviewImage, PreviewColorProfile, Settings->GetInt("PreviewColorProfileIntent"));
2006     }
2007   }
2008 
2009   if (Settings->GetInt("HistogramMode")==ptHistogramMode_Preview) {
2010     if (!Settings->GetInt("HistogramCrop") ||
2011         (Settings->GetInt("HistogramCrop") && !Settings->GetInt("WebResize"))) {
2012       HistogramImage->Set(PreviewImage);
2013     } else if (Settings->GetInt("HistogramCrop")) {
2014       BeforeGamma(HistogramImage,0,0);
2015 
2016       ptImage* ReturnValue = HistogramImage->lcmsRGBToPreviewRGB(Settings->GetInt("CMQuality") == ptCMQuality_FastSRGB);
2017       if (!ReturnValue) {
2018         ptLogError(ptError_lcms,"lcmsRGBToPreviewRGB");
2019         assert(ReturnValue);
2020       }
2021 
2022       AfterAll(HistogramImage,0,0);
2023       if (GFilterDM->GetFilterFromName(Fuid::Wiener_Out)->isActive() &&
2024           Settings->GetInt("PreviewMode") == ptPreviewMode_End)
2025       {
2026         EndSharpen(HistogramImage, PreviewColorProfile, Settings->GetInt("PreviewColorProfileIntent"));
2027       }
2028     }
2029 
2030     if (Settings->GetInt("HistogramCrop")) {
2031       float TmpScaled = TheProcessor->m_ScaleFactor;
2032       Width = HistogramImage->m_Width;
2033       Height = HistogramImage->m_Height;
2034       TempCropX = Settings->GetInt("HistogramCropX")*TmpScaled;
2035       TempCropY = Settings->GetInt("HistogramCropY")*TmpScaled;
2036       TempCropW = Settings->GetInt("HistogramCropW")*TmpScaled;
2037       TempCropH = Settings->GetInt("HistogramCropH")*TmpScaled;
2038       if ((((TempCropX) + (TempCropW)) >  Width) ||
2039           (((TempCropY) + (TempCropH)) >  Height)) {
2040         ptMessageBox::information(MainWindow,
2041           QObject::tr("Histogram selection outside the image"),
2042           QObject::tr("Histogram selection rectangle too large.\nNo crop, try again."));
2043         Settings->SetValue("HistogramCropX",0);
2044         Settings->SetValue("HistogramCropY",0);
2045         Settings->SetValue("HistogramCropW",0);
2046         Settings->SetValue("HistogramCropH",0);
2047         Settings->SetValue("HistogramCrop",0);
2048       } else {
2049         HistogramImage->Crop(TempCropX, TempCropY, TempCropW, TempCropH);
2050       }
2051     }
2052   }
2053 
2054   if (!OnlyHistogram) {
2055     if (Settings->GetInt("HistogramMode")==ptHistogramMode_Output) {
2056       if (Settings->GetInt("ExposureIndicator"))
2057         PreviewImage->IndicateExposure(HistogramImage,
2058                                       Settings->GetInt("ExposureIndicatorOver"),
2059                                       Settings->GetInt("ExposureIndicatorUnder"),
2060                                       ExposureChannelMask,
2061                                       OverExposureLevel,
2062                                       UnderExposureLevel);
2063     } else {
2064       if (Settings->GetInt("ExposureIndicator"))
2065         PreviewImage->IndicateExposure(Settings->GetInt("ExposureIndicatorOver"),
2066                                       Settings->GetInt("ExposureIndicatorUnder"),
2067                                       ExposureChannelMask,
2068                                       OverExposureLevel,
2069                                       UnderExposureLevel);
2070     }
2071 
2072     // Get a special preview
2073     if (Settings->GetInt("SpecialPreview"))
2074       PreviewImage->SpecialPreview(Settings->GetInt("SpecialPreview"),
2075                                    Settings->GetInt("PreviewColorProfileIntent"));
2076 
2077     // Update the ViewWindow and show if needed.
2078     ViewWindow->UpdateImage(PreviewImage);
2079   }
2080 
2081   HistogramWindow->UpdateView(HistogramImage);
2082   ViewWindow->ShowStatus(ptStatus_Done);
2083 
2084   ReportProgress(QObject::tr("Ready"));
2085 
2086   if (!OnlyHistogram) {
2087     if (Settings->GetInt("WriteBackupSettings")) {
2088       GFilterDM->WritePresetFile(Settings->GetString("UserDirectory")+"backup.pts");
2089     }
2090   }
2091 } // UpdatePreviewImage
2092 
2093 
2094 ////////////////////////////////////////////////////////////////////////////////
2095 //
2096 // RunJob (the non-interactive 'batch' run).
2097 //
2098 ////////////////////////////////////////////////////////////////////////////////
2099 
RunJob(const QString JobFileName)2100 void RunJob(const QString JobFileName) {
2101   Settings->SetValue("JobMode",1);
2102   // Init
2103   CB_Event0();
2104 
2105   // Read the gui settings from a file.
2106   short NextPhase = 1;
2107   short ReturnValue = GFilterDM->ReadPresetFile(JobFileName, NextPhase);
2108   // TODO: BJ Implement spot processing
2109   if (ReturnValue) {
2110     printf("\nNo valid job file!\n\n");
2111     return;
2112   }
2113 
2114   QStringList InputFileNameList = Settings->GetStringList("InputFileNameList");
2115   assert(InputFileNameList.size());
2116 
2117   do {
2118     try {
2119       // Test if we can handle the file
2120       ptDcRaw* TestDcRaw = new(ptDcRaw);
2121       Settings->ToDcRaw(TestDcRaw);
2122       uint16_t InputWidth = 0;
2123       uint16_t InputHeight = 0;
2124       ptImageType InputType = CheckImageType(InputFileNameList[0],
2125                                              &InputWidth, &InputHeight,
2126                                              TestDcRaw);
2127 
2128       if (InputType <= itUndetermined) {
2129         // not a supported image type or error reading the file
2130         QString ErrorMessage = QObject::tr("Cannot decode")
2131                              + " '"
2132                              + InputFileNameList[0]
2133                              + "'" ;
2134         printf("%s\n",ErrorMessage.toLocal8Bit().data());
2135         delete TestDcRaw;
2136 
2137 
2138       } else {
2139         // process the image
2140         if (InputType == itRaw) {
2141           Settings->SetValue("IsRAW",1);
2142         } else {
2143           Settings->SetValue("IsRAW",0);
2144         }
2145 
2146         if (!Settings->useRAWHandling()) {
2147           Settings->SetValue("ExposureNormalization", 0.0);
2148         }
2149 
2150         QFileInfo PathInfo(InputFileNameList[0]);
2151         if (!Settings->GetString("OutputDirectory").isEmpty()) {
2152           Settings->SetValue("OutputFileName",
2153             Settings->GetString("OutputDirectory") + "/" + PathInfo.completeBaseName());
2154         } else {
2155           Settings->SetValue("OutputFileName",
2156             PathInfo.dir().path() + "/" + PathInfo.completeBaseName());
2157         }
2158         if (!Settings->GetString("OutputFileNameSuffix").isEmpty()) {
2159           Settings->SetValue("OutputFileName",
2160                              Settings->GetString("OutputFileName") +
2161                              Settings->GetString("OutputFileNameSuffix"));
2162         }
2163         else {
2164           if (!Settings->GetInt("IsRAW")) {
2165             Settings->SetValue("OutputFileName",
2166                                Settings->GetString("OutputFileName") + "-new");
2167           }
2168         }
2169 
2170         // Here we have the OutputFileName, but extension still to add.
2171         switch(Settings->GetInt("SaveFormat")) {
2172           case ptSaveFormat_JPEG :
2173             Settings->SetValue("OutputFileName",
2174                                Settings->GetString("OutputFileName") + ".jpg");
2175             break;
2176           case ptSaveFormat_PNG :
2177           case ptSaveFormat_PNG16 :
2178             Settings->SetValue("OutputFileName",
2179                                Settings->GetString("OutputFileName") + ".png");
2180             break;
2181           case ptSaveFormat_TIFF8 :
2182           case ptSaveFormat_TIFF16 :
2183             Settings->SetValue("OutputFileName",
2184                                Settings->GetString("OutputFileName") + ".tif");
2185             break;
2186           default :
2187             Settings->SetValue("OutputFileName",
2188                                Settings->GetString("OutputFileName") + ".ppm");
2189             break;
2190         }
2191 
2192         // Processing the job.
2193         delete TheDcRaw;
2194         delete TheProcessor;
2195         TheProcessor = new ptProcessor(ReportProgress);
2196         TheDcRaw = TestDcRaw;
2197         Settings->SetValue("ImageW",InputWidth);
2198         Settings->SetValue("ImageH",InputHeight);
2199 
2200         TheProcessor->m_DcRaw = TheDcRaw;
2201 
2202         Settings->SetValue("RunMode",0);
2203         Settings->SetValue("FullOutput",1);
2204         TheProcessor->Run(ptProcessorPhase_Raw,ptProcessorPhase_Load,0,1);
2205         Settings->SetValue("FullOutput",0);
2206         // And write result.
2207         Update(ptProcessorPhase_WriteOut);
2208       }
2209     } catch (std::bad_alloc) {
2210       QString ErrorMessage = QObject::tr("Memory error, no conversion for file:")
2211                            + " '"
2212                            + InputFileNameList[0]
2213                            + "'" ;
2214       printf("%s\n",ErrorMessage.toLocal8Bit().data());
2215     }
2216 
2217     // Loop over the inputfiles by shifting the next one to index 0
2218     if (InputFileNameList.size()) {
2219       InputFileNameList.removeAt(0);
2220     }
2221 
2222     // Write the changed InputFileNameList back to the settings.
2223     Settings->SetValue("InputFileNameList",InputFileNameList);
2224 
2225   } while (InputFileNameList.size());
2226 } // RunJob
2227 
2228 //==============================================================================
2229 // Prepares the tags list and sets TagsList and DigikamTagsList
PrepareTags(const QString TagsInput)2230 void PrepareTags(const QString TagsInput) {
2231 
2232   QString WorkString = TagsInput;
2233   WorkString.replace("\n",",");
2234   while (WorkString.contains("  "))
2235     WorkString.replace("  "," ");
2236   if (WorkString.startsWith(" ")) WorkString.remove(0,1);
2237   if (WorkString.endsWith(" ")) WorkString.remove(WorkString.size()-1,1);
2238   while (WorkString.contains("//"))
2239     WorkString.replace("//","/");
2240   while (WorkString.contains("/ /"))
2241     WorkString.replace("/ /","/");
2242   if (WorkString.endsWith("/")) WorkString.remove(WorkString.size()-1,1);
2243   WorkString.replace(" ,",",");
2244   WorkString.replace("/,",",");
2245   WorkString.replace(" ,",","); // We need this again!
2246   WorkString.replace(" /","/");
2247   WorkString.replace("/ ","/");
2248   WorkString.replace(",/",",");
2249   WorkString.replace(", ",",");
2250   if (WorkString.startsWith("/")) WorkString.remove(0,1);
2251 
2252   QStringList DigikamTags = WorkString.split(",", QString::SkipEmptyParts);
2253 
2254   QStringList Tags;
2255   QString TempString;
2256   for (int i = 0; i < DigikamTags.size(); i++) {
2257     TempString = DigikamTags.at(i);
2258     TempString.remove(0,TempString.lastIndexOf("/")+1);
2259     if (TempString.startsWith(" ")) TempString.remove(0,1);
2260     Tags << TempString;
2261   }
2262 
2263   Settings->SetValue("DigikamTagsList", DigikamTags);
2264   Settings->SetValue("TagsList", Tags);
2265 }
2266 
2267 //==============================================================================
2268 
2269 /*! Write out in one of the output formats (after applying output profile). */
WriteOut()2270 void WriteOut() {
2271   ptImage* OutImage = NULL;
2272 
2273   if (Settings->GetInt("JobMode") == 1) {
2274     OutImage = TheProcessor->m_Image_AfterEyeCandy; // Job mode -> no cache
2275   } else {
2276     if (!OutImage) OutImage = new(ptImage);
2277     OutImage->Set(TheProcessor->m_Image_AfterEyeCandy);
2278   }
2279 
2280   BeforeGamma(OutImage, 1);
2281 
2282   cmsHPROFILE OutputColorProfile = NULL;
2283 
2284   ReportProgress(QObject::tr("Converting to output space"));
2285 
2286   // Prepare and open an output profile.
2287   OutputColorProfile = cmsOpenProfileFromFile(
2288     Settings->GetString("OutputColorProfile").toLocal8Bit().data(),
2289     "r");
2290   if (!OutputColorProfile) {
2291     ptLogError(ptError_FileOpen,
2292    Settings->GetString("OutputColorProfile").toLocal8Bit().data());
2293     assert(OutputColorProfile);
2294   }
2295 
2296   // Color space conversion
2297   ptImage* ReturnValue = OutImage->lcmsRGBToRGB(
2298     OutputColorProfile,
2299     Settings->GetInt("OutputColorProfileIntent"),
2300     Settings->GetInt("CMQuality"));
2301   if (!ReturnValue) {
2302     ptLogError(ptError_lcms,"lcmsRGBToRGB(OutputColorProfile)");
2303     assert(ReturnValue);
2304   }
2305 
2306   AfterAll(OutImage, 1);
2307   if (GFilterDM->GetFilterFromName(Fuid::Wiener_Out)->isActive())
2308     EndSharpen(OutImage, OutputColorProfile, Settings->GetInt("OutputColorProfileIntent"));
2309   // Close the output profile.
2310   cmsCloseProfile(OutputColorProfile);
2311 
2312   ReportProgress(QObject::tr("Writing output"));
2313 
2314   bool FileWritten =  OutImage->ptGMCWriteImage(
2315     Settings->GetString("OutputFileName").toLocal8Bit().data(),
2316     Settings->GetInt("SaveFormat"),
2317     Settings->GetInt("SaveQuality"),
2318     Settings->GetInt("SaveSampling"),
2319     Settings->GetInt("SaveResolution"),
2320     Settings->GetString("OutputColorProfile").toLocal8Bit().data(),
2321     Settings->GetInt("OutputColorProfileIntent"));
2322 
2323   if (!FileWritten) {
2324     ptMessageBox::warning(MainWindow, QObject::tr("GraphicsMagick Error"), QObject::tr("No output file written."));
2325   } else {
2326     ReportProgress(QObject::tr("Writing output (exif)"));
2327 
2328     if (Settings->GetInt("IncludeExif")) {
2329       if (!ptImageHelper::WriteExif(Settings->GetString("OutputFileName"),
2330                                     TheProcessor->m_ExifBuffer,
2331                                     IptcData,
2332                                     XmpData))
2333         ptMessageBox::warning(MainWindow, QObject::tr("Exif Error"), QObject::tr("No exif data written."));
2334     }
2335   }
2336 
2337   if (Settings->GetInt("JobMode") == 0) delete OutImage;
2338 
2339   if (JobMode == 0) {
2340     // This variable carries only JobMode, the "JobMode" settings
2341     // is also used for full image output.
2342     ReportProgress(QObject::tr("Writing output (settings)"));
2343 
2344     QFileInfo PathInfo(Settings->GetString("OutputFileName"));
2345     QString SettingsFileName = PathInfo.dir().path() + "/" + PathInfo.completeBaseName() + ".pts";
2346 
2347     GFilterDM->WritePresetFile(SettingsFileName);
2348   }
2349 
2350   if (FileWritten) {
2351     QFileInfo hInfo = QFileInfo(Settings->GetString("OutputFileName"));
2352     ReportProgress(
2353       QString(QObject::tr("Written %L1 bytes (%L2 MByte)"))
2354           .arg(hInfo.size())
2355           .arg((float)hInfo.size()/1024/1024, 0, 'f', 2)
2356     );
2357   } else {
2358     ReportProgress(QObject::tr("Ready"));
2359   }
2360 }
2361 
2362 //==============================================================================
2363 
WritePipe(QString OutputName="")2364 void WritePipe(QString OutputName = "") {
2365 
2366   if (Settings->GetInt("HaveImage")==0) return;
2367 
2368   QStringList InputFileNameList = Settings->GetStringList("InputFileNameList");
2369   QFileInfo PathInfo(InputFileNameList[0]);
2370   QString SuggestedFileName = PathInfo.dir().path() + "/" + PathInfo.completeBaseName();
2371   if (!Settings->GetString("OutputFileNameSuffix").isEmpty())
2372     SuggestedFileName += Settings->GetString("OutputFileNameSuffix");
2373   else
2374     if (!Settings->GetInt("IsRAW")) SuggestedFileName += "-new";
2375   QString Pattern;
2376 
2377   switch(Settings->GetInt("SaveFormat")) {
2378     case ptSaveFormat_JPEG :
2379       SuggestedFileName += ".jpg";
2380       Pattern = QObject::tr("Jpg images (*.jpg *.jpeg);;All files (*.*)");
2381       break;
2382     case ptSaveFormat_PNG :
2383     case ptSaveFormat_PNG16 :
2384       SuggestedFileName += ".png";
2385       Pattern = QObject::tr("PNG images(*.png);;All files (*.*)");
2386       break;
2387     case ptSaveFormat_TIFF8 :
2388     case ptSaveFormat_TIFF16 :
2389       SuggestedFileName += ".tif";
2390       Pattern = QObject::tr("Tiff images (*.tif *.tiff);;All files (*.*)");
2391       break;
2392     default :
2393       SuggestedFileName += ".ppm";
2394       Pattern = QObject::tr("Ppm images (*.ppm);;All files (*.*)");
2395       break;
2396   }
2397 
2398   QString FileName = OutputName;
2399   if (FileName == "")
2400     FileName = QFileDialog::getSaveFileName(NULL,
2401                                             QObject::tr("Save File"),
2402                                             SuggestedFileName,
2403                                             Pattern);
2404 
2405   if (0 == FileName.size()) return; // Operation cancelled.
2406 
2407   Settings->SetValue("OutputFileName",FileName);
2408 
2409   // Write out (maybe after applying gamma).
2410   Update(ptProcessorPhase_WriteOut);
2411   ImageSaved = 1;
2412 }
2413 
2414 ////////////////////////////////////////////////////////////////////////////////
2415 //
2416 // Utility : Update GuiSettings->m_?Multiplier according
2417 // to the ColorTemperature/GreenIntensity in the GuiSettings.
2418 //
2419 ////////////////////////////////////////////////////////////////////////////////
2420 
CalculateMultipliersFromTemperature()2421 void CalculateMultipliersFromTemperature() {
2422 
2423   // m_D65Multipliers are supposed to be D65
2424   // (setting Pre to the ratio of the D65 delivers
2425   // rgbWB = (x,x,x) and 6500 temperature).
2426 
2427   double RefRGB[3];
2428   TemperatureToRGB(Settings->GetInt("ColorTemperature"),RefRGB);
2429   RefRGB[1] /= Settings->GetDouble("GreenIntensity");
2430   if (TheDcRaw->m_RawColorPhotivo) {
2431    Settings->SetValue("RMultiplier",
2432                       VALUE(TheDcRaw->m_D65Multipliers[0])/RefRGB[0]);
2433    Settings->SetValue("GMultiplier",
2434                       VALUE(TheDcRaw->m_D65Multipliers[1])/RefRGB[1]);
2435    Settings->SetValue("BMultiplier",
2436                       VALUE(TheDcRaw->m_D65Multipliers[2])/RefRGB[2]);
2437   } else {
2438     // If not raw color, calculate RefRGB in sRGB back to the camera RGB
2439     for (short c=0; c<TheDcRaw->m_Colors; c++) {
2440       double InverseMultiplier = 0;
2441       for (short cc=0; cc<3; cc++) {
2442         InverseMultiplier += 1/VALUE(TheDcRaw->m_D65Multipliers[c])
2443                               * TheDcRaw->m_MatrixSRGBToCamRGB[c][cc]
2444                               * RefRGB[cc];
2445       }
2446       switch (c) {
2447         case 0 :
2448           Settings->SetValue("RMultiplier",1/InverseMultiplier);
2449           break;
2450         case 1 :
2451           Settings->SetValue("GMultiplier",1/InverseMultiplier);
2452           break;
2453         case 2 :
2454           Settings->SetValue("BMultiplier",1/InverseMultiplier);
2455           break;
2456         default :
2457           assert(0);
2458       }
2459     }
2460   }
2461 }
2462 
2463 ////////////////////////////////////////////////////////////////////////////////
2464 //
2465 // Utility function : Normalize the Multipliers to largest 1.0
2466 // If Max is set, normalize to lowest 1.0
2467 //
2468 ////////////////////////////////////////////////////////////////////////////////
2469 
NormalizeMultipliers(const short Max=0)2470 void NormalizeMultipliers(const short Max = 0) {
2471   if (Max == 0) {
2472     double Maximum = Settings->GetDouble("RMultiplier");
2473     if (Settings->GetDouble("GMultiplier") > Maximum)
2474       Maximum = Settings->GetDouble("GMultiplier");
2475     if (Settings->GetDouble("BMultiplier") > Maximum)
2476       Maximum = Settings->GetDouble("BMultiplier");
2477     assert (Maximum > 0.0);
2478     Settings->SetValue("RMultiplier",Settings->GetDouble("RMultiplier")/Maximum);
2479     Settings->SetValue("GMultiplier",Settings->GetDouble("GMultiplier")/Maximum);
2480     Settings->SetValue("BMultiplier",Settings->GetDouble("BMultiplier")/Maximum);
2481   } else {
2482     double Minimum = Settings->GetDouble("RMultiplier");
2483     if (Settings->GetDouble("GMultiplier") < Minimum)
2484       Minimum = Settings->GetDouble("GMultiplier");
2485     if (Settings->GetDouble("BMultiplier") < Minimum)
2486       Minimum = Settings->GetDouble("BMultiplier");
2487     assert (Minimum > 0.0);
2488     Settings->SetValue("RMultiplier",Settings->GetDouble("RMultiplier")/Minimum);
2489     Settings->SetValue("GMultiplier",Settings->GetDouble("GMultiplier")/Minimum);
2490     Settings->SetValue("BMultiplier",Settings->GetDouble("BMultiplier")/Minimum);
2491   }
2492 }
2493 
2494 //==============================================================================
2495 // Handles the display of the pixel values
CB_PixelReader(const QPointF Point,const ptPixelReading PixelReading)2496 void CB_PixelReader(const QPointF Point, const ptPixelReading PixelReading) {
2497   // No display while pipe is running
2498   if (Settings->GetInt("PipeIsRunning") || Settings->GetInt("HaveImage")==0) {
2499     HistogramWindow->PixelInfoHide();
2500     return;
2501   }
2502 
2503   RGBValue RGB;
2504 
2505   // reset the display
2506   if (PixelReading == prNone) {
2507     HistogramWindow->PixelInfoHide();
2508     return;
2509   } else if (PixelReading == prLinear) {
2510     // we use the AfterEyeCandy image as source
2511     RGB = TheProcessor->m_Image_AfterEyeCandy->GetRGB(Point.x(), Point.y());
2512   } else {
2513     // we use the PreviewImage as source
2514     RGB = PreviewImage->GetRGB(Point.x(), Point.y());
2515   }
2516 
2517   // We normalize the values to 0..100
2518   HistogramWindow->PixelInfo(QString::number(RGB.R/655.35, 'f', 2),
2519                              QString::number(RGB.G/655.35, 'f', 2),
2520                              QString::number(RGB.B/655.35, 'f', 2));
2521 }
2522 
2523 ////////////////////////////////////////////////////////////////////////////////
2524 //
2525 // For convenience...
2526 //
2527 ////////////////////////////////////////////////////////////////////////////////
2528 
UpdateSettings()2529 void UpdateSettings() {
2530   MainWindow->UpdateSettings();
2531 }
2532 
2533 ////////////////////////////////////////////////////////////////////////////////
2534 //
2535 // Callback pertaining to the Tabs structure (switching page)
2536 //
2537 ////////////////////////////////////////////////////////////////////////////////
2538 
CB_Tabs(const short)2539 void CB_Tabs(const short) {
2540   // If we are previewing according to Tab, we now have to update.
2541   if (Settings->GetInt("PreviewMode") == ptPreviewMode_Tab) {
2542     Update(ptProcessorPhase_Preview);
2543   }
2544 }
2545 
2546 
2547 ////////////////////////////////////////////////////////////////////////////////
2548 //
2549 // Callbacks pertaining to the Menu structure.
2550 // (inclusive 'X' pressing).
2551 //
2552 ////////////////////////////////////////////////////////////////////////////////
2553 
CB_MenuFileOpen(const short HaveFile)2554 void CB_MenuFileOpen(const short HaveFile) {
2555   QStringList OldInputFileNameList = Settings->GetStringList("InputFileNameList");
2556   QString InputFileName = "";
2557   if (HaveFile) {
2558     InputFileName = ImageFileToOpen;
2559   }
2560 
2561   // Ask user confirmation
2562   if (Settings->GetInt("HaveImage") == 1) {
2563     if (!ptConfirmRequest::saveImage(InputFileName)) {
2564       return;
2565     }
2566   }
2567 
2568   // open file dialog
2569   if (!HaveFile) {
2570     InputFileName =
2571       QFileDialog::getOpenFileName(NULL,
2572                                    QObject::tr("Open Raw"),
2573                                    Settings->GetString("RawsDirectory"),
2574                                    RawPattern);
2575   }
2576 
2577   // no new image file: abort
2578   if (InputFileName == "") {
2579     return;
2580   } else {
2581     if (!QFile::exists(InputFileName)) {
2582       ptMessageBox::warning(NULL,
2583           QObject::tr("File not found"),
2584           QObject::tr("Input file does not exist.") + "\n\n" + InputFileName);
2585       return;
2586     }
2587   }
2588 
2589   QFileInfo PathInfo(InputFileName);
2590   Settings->SetValue("RawsDirectory",PathInfo.absolutePath());
2591   QStringList InputFileNameList;
2592   InputFileNameList << PathInfo.absoluteFilePath();
2593 
2594   Settings->SetValue("InputFileNameList",InputFileNameList);
2595 
2596   // Feedback to the user
2597   ReportProgress(QObject::tr("Reading file"));
2598 
2599   // Test if we can handle the file
2600   ptDcRaw* TestDcRaw = new(ptDcRaw);
2601   Settings->ToDcRaw(TestDcRaw);
2602   uint16_t InputWidth = 0;
2603   uint16_t InputHeight = 0;
2604   ptImageType InputType = CheckImageType(InputFileNameList[0],
2605                                          &InputWidth, &InputHeight,
2606                                          TestDcRaw);
2607 
2608   if (InputType <= itUndetermined) {
2609     // not a supported image type or error reading the file
2610     QString ErrorMessage = QObject::tr("Cannot decode")
2611                          + " '"
2612                          + InputFileNameList[0]
2613                          + "'" ;
2614     ptMessageBox::warning(MainWindow, "Decode error", ErrorMessage);
2615     Settings->SetValue("InputFileNameList", OldInputFileNameList);
2616     delete TestDcRaw;
2617     return;
2618   }
2619 
2620   // Image type is supported: process the image
2621   if (InputType == itRaw) {
2622     Settings->SetValue("IsRAW", 1);
2623   } else {
2624     Settings->SetValue("IsRAW", 0);
2625   }
2626 
2627   Settings->SetEnabled("UseThumbnail", Settings->GetInt("IsRAW") == 1);
2628 
2629   if (!Settings->useRAWHandling()) {
2630     Settings->SetValue("ExposureNormalization", 0.0);
2631   }
2632 
2633   if (Settings->GetInt("HaveImage") == 1) {
2634     // Catch 1:1 pipe size when opening
2635     if (Settings->GetInt("PipeSize") == 0)
2636       Settings->SetValue("PipeSize", 1);
2637   }
2638 
2639   // TODO mike: need to delete the processor here?
2640   delete TheDcRaw;
2641   delete TheProcessor;
2642   // Load user settings
2643   if (Settings->GetInt("StartupSettings") == 1 &&
2644       Settings->GetInt("StartupSettingsReset") == 1 &&
2645       Settings->GetInt("HaveImage") == 1) {
2646     Settings->SetValue("HaveImage", 0);
2647     CB_OpenSettingsFile(Settings->GetString("StartupSettingsFile"));
2648     // clean up
2649     QStringList Temp;
2650     Temp << "CropX" << "CropY" << "CropW" << "CropH";
2651     Temp << "RotateW" << "RotateH";
2652     for (int i = 0; i < Temp.size(); i++) Settings->SetValue(Temp.at(i), 0);
2653   }
2654 
2655   if (Settings->GetString("Sidecar") != "") {
2656     ReadSidecar(Settings->GetString("Sidecar"));
2657   }
2658 
2659   // load settings file automatically
2660   QString SettingsFileName = PathInfo.dir().path() + "/" + PathInfo.completeBaseName() + ".pts";
2661   if (QFile::exists(SettingsFileName)) {
2662     Settings->SetValue("HaveImage", 0);
2663     CB_OpenSettingsFile(SettingsFileName);
2664   }
2665 
2666   // clean up possible detail view cache
2667   if (Settings->GetInt("DetailViewActive") == 1) {
2668     Settings->SetValue("DetailViewActive", 0);
2669     Settings->SetValue("DetailViewCropX",  0);
2670     Settings->SetValue("DetailViewCropY",  0);
2671     Settings->SetValue("DetailViewCropW",  0);
2672     Settings->SetValue("DetailViewCropH",  0);
2673     Settings->ToDcRaw(TestDcRaw);
2674   }
2675 
2676   TheDcRaw = TestDcRaw;
2677   Settings->SetValue("ImageW", InputWidth);
2678   Settings->SetValue("ImageH", InputHeight);
2679 
2680   if (Settings->GetInt("StartupSwitchAR")) {
2681     // portrait image
2682     if ((!Settings->useRAWHandling() &&
2683          Settings->GetInt("ImageW") < Settings->GetInt("ImageH")) ||
2684         TheDcRaw->m_Flip & 4) {
2685       if (Settings->GetInt("AspectRatioW") > Settings->GetInt("AspectRatioH"))
2686         CB_CropOrientationButton();
2687     } else { // landscape
2688       if (Settings->GetInt("AspectRatioW") < Settings->GetInt("AspectRatioH"))
2689         CB_CropOrientationButton();
2690     }
2691   }
2692   SetRatingFromXmp();
2693   if (Settings->GetInt("LoadTags"))
2694     SetTagsFromXmp();
2695 
2696   // reflect RAW or bitmap in GUI
2697   MainWindow->UpdateToolBoxes();
2698 
2699   TheProcessor = new ptProcessor(ReportProgress);
2700   TheProcessor->m_DcRaw = TheDcRaw;
2701 
2702   Settings->SetValue("HaveImage", 1);
2703   short OldRunMode = Settings->GetInt("RunMode");
2704   Settings->SetValue("RunMode", 0);
2705 
2706   if (Settings->GetInt("AutomaticPipeSize") && Settings->ToolIsActive("TabResize")) {
2707     CalculatePipeSize(true);
2708   }
2709 
2710   Update(ptProcessorPhase_Raw, ptProcessorPhase_Load, 0);
2711 
2712   MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
2713   Settings->SetValue("PerspectiveFocalLength", Settings->GetDouble("FocalLengthIn35mmFilm"));
2714   Settings->SetValue("DefishFocalLength",      Settings->GetDouble("FocalLengthIn35mmFilm"));
2715   Settings->SetValue("LfunFocal",              Settings->GetDouble("FocalLengthIn35mmFilm"));
2716   double TmpAprt = Settings->GetDouble("ApertureFromExif");
2717   Settings->SetValue("LfunAperture",           (TmpAprt == 0.0) ? 8.0 : TmpAprt);
2718   MainWindow->UpdateFilenameInfo(Settings->GetStringList("InputFileNameList"));
2719 
2720   QFileInfo finfo = QFileInfo((Settings->GetStringList("InputFileNameList"))[0]);
2721   MainWindow->setWindowTitle(
2722       QString("%1 - %2 - Photivo").arg(finfo.fileName())
2723                                   .arg(QDir::toNativeSeparators(finfo.absolutePath())) );
2724 
2725   Settings->SetValue("RunMode",OldRunMode);
2726 
2727   ptClearUndoRedo();
2728 }
2729 
2730 //==============================================================================
2731 
CB_MenuFileSaveOutput(QString OutputName="")2732 void CB_MenuFileSaveOutput(QString OutputName = "") {
2733   try {
2734     if (Settings->GetInt("HaveImage")==0) return;
2735 
2736     QStringList InputFileNameList = Settings->GetStringList("InputFileNameList");
2737     QFileInfo PathInfo(InputFileNameList[0]);
2738     QString SuggestedFileName = PathInfo.dir().path() + "/" + PathInfo.completeBaseName();
2739     if (!Settings->GetString("OutputFileNameSuffix").isEmpty())
2740       SuggestedFileName += Settings->GetString("OutputFileNameSuffix");
2741     else
2742       if (!Settings->GetInt("IsRAW")) SuggestedFileName += "-new";
2743     QString Pattern;
2744 
2745     switch(Settings->GetInt("SaveFormat")) {
2746       case ptSaveFormat_JPEG :
2747         SuggestedFileName += ".jpg";
2748         Pattern = QObject::tr("Jpg images (*.jpg *.jpeg);;All files (*.*)");
2749         break;
2750       case ptSaveFormat_PNG :
2751       case ptSaveFormat_PNG16 :
2752         SuggestedFileName += ".png";
2753         Pattern = QObject::tr("PNG images(*.png);;All files (*.*)");
2754         break;
2755       case ptSaveFormat_TIFF8 :
2756       case ptSaveFormat_TIFF16 :
2757         SuggestedFileName += ".tif";
2758         Pattern = QObject::tr("Tiff images (*.tif *.tiff);;All files (*.*)");
2759         break;
2760       default :
2761         SuggestedFileName += ".ppm";
2762         Pattern = QObject::tr("Ppm images (*.ppm);;All files (*.*)");
2763         break;
2764     }
2765 
2766     QString FileName = OutputName;
2767     if (FileName == "")
2768       FileName = QFileDialog::getSaveFileName(NULL,
2769                                               QObject::tr("Save File"),
2770                                               SuggestedFileName,
2771                                               Pattern);
2772 
2773     if (0 == FileName.size()) return; // Operation cancelled.
2774 
2775     Settings->SetValue("OutputFileName",FileName);
2776 
2777     short OldRunMode = Settings->GetInt("RunMode");
2778     Settings->SetValue("RunMode",0);
2779 
2780     // Processing the job.
2781     delete TheDcRaw;
2782     delete TheProcessor;
2783   TheDcRaw = new(ptDcRaw);
2784     TheProcessor = new ptProcessor(ReportProgress);
2785     Settings->SetValue("JobMode",1); // Disable caching to save memory
2786     TheProcessor->m_DcRaw = TheDcRaw;
2787     Settings->ToDcRaw(TheDcRaw);
2788     // Run the graphical pipe in full format mode to recreate the image.
2789     Settings->SetValue("FullOutput",1);
2790     TheProcessor->Run(ptProcessorPhase_Raw,ptProcessorPhase_Load,1,1);
2791     Settings->SetValue("FullOutput",0);
2792 
2793     // Write out (maybe after applying gamma).
2794     Update(ptProcessorPhase_WriteOut);
2795 
2796     delete TheDcRaw;
2797     delete TheProcessor;
2798   TheDcRaw = new(ptDcRaw);
2799     TheProcessor = new ptProcessor(ReportProgress);
2800     Settings->SetValue("JobMode",0);
2801     TheProcessor->m_DcRaw = TheDcRaw;
2802     Settings->ToDcRaw(TheDcRaw);
2803     Update(ptProcessorPhase_Raw,ptProcessorPhase_Load,0);
2804     MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
2805     Settings->SetValue("RunMode",OldRunMode);
2806     ImageSaved = 1;
2807   } catch (std::bad_alloc) {
2808     ptMessageBox::critical(NULL, "Memory error", "No file written, memory error.");
2809   }
2810 } // CB_MenuFileSaveOutput
2811 
2812 //==============================================================================
2813 
CB_MenuFileExit(const short)2814 void CB_MenuFileExit(const short) {
2815   if (Settings->GetInt("HaveImage")==1 && ImageSaved == 0) {
2816     if (!ptConfirmRequest::saveImage()) {
2817       return;
2818     }
2819   }
2820 
2821   // Save current filter config
2822   if (Settings->GetString("StartupSettingsFile").endsWith("Presets/Latest.pts"))
2823     GFilterDM->WritePresetFile(Settings->GetString("UserDirectory") + "/Presets/Latest.pts");
2824 
2825   // clean up the input file if we got just a temp file
2826   if (Settings->GetInt("HaveImage")==1 && ImageCleanUp == 1) {
2827     QString OldInputFileName = Settings->GetStringList("InputFileNameList")[0];
2828     ptRemoveFile(OldInputFileName);
2829     ImageCleanUp--;
2830   }
2831 
2832   // Delete backup settingsfile
2833   if (Settings->GetInt("WriteBackupSettings") == 1)
2834     QFile::remove(Settings->GetString("UserDirectory")+"/backup.pts");
2835 
2836   MainWindow->Form_2_Settings();
2837 
2838   printf("Saving settings ...\n");
2839 
2840 #ifndef PT_WITHOUT_FILEMGR
2841   // this also writes settings.
2842   delete FileMgrWindow;
2843 #endif
2844 
2845   delete BatchWindow;
2846 
2847   // Store the position of the splitter and main window
2848   Settings->m_IniSettings->
2849     setValue("MainSplitter",MainWindow->MainSplitter->saveState());
2850   Settings->m_IniSettings->
2851     setValue("ControlSplitter",MainWindow->ControlSplitter->saveState());
2852   Settings->m_IniSettings->setValue("MainWindowPos",    MainWindow->pos());
2853   Settings->m_IniSettings->setValue("MainWindowSize",   MainWindow->size());
2854   Settings->m_IniSettings->setValue("IsMaximized",      MainWindow->windowState() == Qt::WindowMaximized);
2855   Settings->m_IniSettings->setValue("MainWindowScreen", qApp->desktop()->screenNumber(MainWindow));
2856 
2857   // Store the version of the settings and files
2858   Settings->m_IniSettings->setValue("SettingsVersion",PhotivoSettingsVersion);
2859 
2860   // Explicitly. The destructor of it cares for persistent settings.
2861   delete Settings;
2862 #ifdef Q_OS_WIN
2863   if (!JobMode)
2864     ptEcWin7::DestroyInstance();
2865 #endif
2866 
2867   ALLOCATED(10000000);
2868   printf("Exiting Photivo.\n");
2869   QCoreApplication::exit(EXIT_SUCCESS);
2870 }
2871 
2872 ////////////////////////////////////////////////////////////////////////////////
2873 //
2874 // Callbacks pertaining to the gimp
2875 //
2876 ////////////////////////////////////////////////////////////////////////////////
2877 
CB_ExportToGimpCheck(const QVariant Check)2878 void CB_ExportToGimpCheck(const QVariant Check) {
2879   Settings->SetValue("ExportToGimp",Check);
2880 }
2881 
GimpExport(const short UsePipe)2882 void GimpExport(const short UsePipe) {
2883   try {
2884     if (Settings->GetInt("HaveImage")==0) return;
2885 
2886     ReportProgress(QObject::tr("Writing tmp image for gimp"));
2887 
2888     short OldRunMode = Settings->GetInt("RunMode");
2889 
2890     ptImage* ImageForGimp = new ptImage;
2891 
2892     if (UsePipe == 1)
2893       ImageForGimp->Set(TheProcessor->m_Image_AfterEyeCandy);
2894     else {
2895       Settings->SetValue("RunMode",0);
2896 
2897       // Processing the job.
2898       delete TheDcRaw;
2899       delete TheProcessor;
2900     TheDcRaw = new(ptDcRaw);
2901       TheProcessor = new ptProcessor(ReportProgress);
2902       Settings->SetValue("JobMode",1); // Disable caching to save memory
2903 
2904       TheProcessor->m_DcRaw = TheDcRaw;
2905       Settings->ToDcRaw(TheDcRaw);
2906       // Run the graphical pipe in full format mode to recreate the image.
2907       Settings->SetValue("FullOutput",1);
2908       TheProcessor->Run(ptProcessorPhase_Raw,ptProcessorPhase_Load,1,1);
2909       Settings->SetValue("FullOutput",0);
2910 
2911       ImageForGimp = TheProcessor->m_Image_AfterEyeCandy; // no cache
2912     }
2913 
2914     BeforeGamma(ImageForGimp);
2915 
2916     cmsHPROFILE OutputColorProfile = NULL;
2917 
2918     ReportProgress(QObject::tr("Converting to output space"));
2919 
2920     // Prepare and open an output profile.
2921     OutputColorProfile = cmsOpenProfileFromFile(
2922       Settings->GetString("OutputColorProfile").toLocal8Bit().data(),
2923       "r");
2924     if (!OutputColorProfile) {
2925       ptLogError(ptError_FileOpen,
2926      Settings->GetString("OutputColorProfile").toLocal8Bit().data());
2927       assert(OutputColorProfile);
2928     }
2929 
2930     // Color space conversion
2931     ptImage* ReturnValue = ImageForGimp->lcmsRGBToRGB(
2932       OutputColorProfile,
2933       Settings->GetInt("OutputColorProfileIntent"),
2934       Settings->GetInt("CMQuality"));
2935     if (!ReturnValue) {
2936       ptLogError(ptError_lcms,"lcmsRGBToRGB(OutputColorProfile)");
2937       assert(ReturnValue);
2938     }
2939 
2940     AfterAll(ImageForGimp);
2941 
2942     if (GFilterDM->GetFilterFromName(Fuid::Wiener_Out)->isActive())
2943       EndSharpen(ImageForGimp, OutputColorProfile, Settings->GetInt("OutputColorProfileIntent"));
2944     // Close the output profile.
2945     cmsCloseProfile(OutputColorProfile);
2946 
2947     QTemporaryFile ImageFile;
2948     ImageFile.setFileTemplate(QDir::tempPath()+"/XXXXXX.ppm");
2949     bool result = ImageFile.open();
2950     assert (result);
2951     QString ImageFileName = ImageFile.fileName();
2952     ImageFile.setAutoRemove(false);
2953     ImageFile.close();
2954     printf("(%s,%d) '%s'\n",
2955            __FILE__,__LINE__,ImageFileName.toLocal8Bit().data());
2956     ImageForGimp->WriteAsPpm(ImageFileName.toLocal8Bit().data(),16);
2957 
2958     ReportProgress(QObject::tr("Writing tmp exif for gimp"));
2959 
2960     QTemporaryFile ExifFile;
2961     result = ExifFile.open();
2962     assert (result);
2963     QString ExifFileName = ExifFile.fileName();
2964     ExifFile.setAutoRemove(false);
2965     printf("(%s,%d) '%s'\n",
2966            __FILE__,__LINE__,ExifFileName.toLocal8Bit().data());
2967     QDataStream ExifOut(&ExifFile);
2968     ExifOut.writeRawData((char *) TheProcessor->m_ExifBuffer.data(),
2969                          TheProcessor->m_ExifBuffer.size());
2970     ExifFile.close();
2971 
2972     ReportProgress(QObject::tr("Writing tmp icc for gimp"));
2973 
2974     QTemporaryFile ICCFile;
2975     result = ICCFile.open();
2976     assert (result);
2977     QString ICCFileName = ICCFile.fileName();
2978     ICCFile.setAutoRemove(false);
2979     printf("(%s,%d) '%s'\n",
2980            __FILE__,__LINE__,ICCFileName.toLocal8Bit().data());
2981     QDataStream ICCOut(&ICCFile);
2982     FILE* pFile = fopen ( Settings->GetString("OutputColorProfile").toLocal8Bit().data(), "rb" );
2983     if (pFile==NULL) {
2984       ptLogError(ptError_FileOpen,Settings->GetString("OutputColorProfile").toLocal8Bit().data());
2985       exit(EXIT_FAILURE);
2986     }
2987     fseek (pFile , 0 , SEEK_END);
2988     long lSize = ftell (pFile);
2989     rewind (pFile);
2990 
2991     char* pchBuffer = (char*) CALLOC2(lSize,sizeof(uint8_t));
2992     ptMemoryError(pchBuffer,__FILE__,__LINE__);
2993 
2994     size_t RV = fread (pchBuffer, 1, lSize, pFile);
2995     if (RV != (size_t) lSize) {
2996       ptLogError(ptError_FileOpen,Settings->GetString("OutputColorProfile").toLocal8Bit().data());
2997       exit(EXIT_FAILURE);
2998     }
2999     ICCOut.writeRawData(pchBuffer, lSize);
3000 
3001     FCLOSE (pFile);
3002     FREE2 (pchBuffer);
3003     ICCFile.close();
3004 
3005     ReportProgress(QObject::tr("Writing gimp interface file"));
3006 
3007     QTemporaryFile GimpFile;
3008     GimpFile.setFileTemplate(QDir::tempPath()+"/XXXXXX.ptg");
3009     result = GimpFile.open();
3010     assert (result);
3011     QString GimpFileName = GimpFile.fileName();
3012     GimpFile.setAutoRemove(false);
3013     printf("(%s,%d) '%s'\n",
3014            __FILE__,__LINE__,GimpFileName.toLocal8Bit().data());
3015     QTextStream Out(&GimpFile);
3016     Out << ImageFileName << "\n";
3017     Out << ExifFileName << "\n";
3018     Out << ICCFileName << "\n";
3019     GimpFile.close();
3020 
3021     QString GimpExeCommand = Settings->GetString("GimpExecCommand");
3022     QStringList GimpArguments;
3023     GimpArguments << GimpFileName;
3024     QProcess* GimpProcess = new QProcess();
3025     GimpProcess->startDetached(GimpExeCommand,GimpArguments);
3026 
3027     // clean up
3028     if (UsePipe == 1) {
3029       delete ImageForGimp;
3030     } else {
3031       delete TheDcRaw;
3032       delete TheProcessor;
3033     TheDcRaw = new(ptDcRaw);
3034       TheProcessor = new ptProcessor(ReportProgress);
3035       Settings->SetValue("JobMode",0);
3036       TheProcessor->m_DcRaw = TheDcRaw;
3037       Settings->ToDcRaw(TheDcRaw);
3038       Update(ptProcessorPhase_Raw,ptProcessorPhase_Load,0);
3039       MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
3040       Settings->SetValue("RunMode",OldRunMode);
3041     }
3042     ReportProgress(QObject::tr("Ready"));
3043   } catch (std::bad_alloc) {
3044     ptMessageBox::critical(NULL, "Memory error", "No export, memory error.");
3045   }
3046 }
3047 
3048 ////////////////////////////////////////////////////////////////////////////////
3049 //
3050 // Callbacks pertaining to the Zoom function
3051 //
3052 ////////////////////////////////////////////////////////////////////////////////
3053 
CB_ZoomInput(const QVariant Value)3054 void CB_ZoomInput(const QVariant Value) {
3055   ViewWindow->ZoomTo(Value.toFloat() / 100.0);
3056   // TODO SR: updatesettings doesnt seem to be necessary
3057 //    MainWindow->UpdateSettings(); // To reflect maybe new zoom
3058 }
3059 
CB_ZoomFitButton()3060 void CB_ZoomFitButton() {
3061   ViewWindow->ZoomToFit();
3062   //MainWindow->UpdateSettings(); // To reflect maybe new zoom
3063 }
3064 
CB_ZoomFullButton()3065 void CB_ZoomFullButton() {
3066   CB_ZoomInput(100);
3067 }
3068 
CB_ZoomStep(int direction)3069 void CB_ZoomStep(int direction) {
3070   ViewWindow->ZoomStep(direction);
3071 }
3072 
CB_BatchButton()3073 void CB_BatchButton() {
3074   MainWindow->OpenBatchWindow();
3075 }
3076 
CB_FileMgrButton()3077 void CB_FileMgrButton() {
3078 #ifndef PT_WITHOUT_FILEMGR
3079   MainWindow->OpenFileMgrWindow();
3080 #endif
3081 }
3082 
CB_FullScreenButton(const int State)3083 void CB_FullScreenButton(const int State) {
3084   if (State == 1) {
3085     MainWindow->raise();
3086     MainWindow->showFullScreen();
3087     Settings->SetValue("FullscreenActive", 1);
3088   } else {
3089     MainWindow->showNormal();
3090     Settings->SetValue("FullscreenActive", 0);
3091   }
3092   MainWindow->FullScreenButton->setChecked(State);
3093 }
3094 
3095 ////////////////////////////////////////////////////////////////////////////////
3096 //
3097 // Callbacks pertaining to the prev/next image buttons
3098 //
3099 ////////////////////////////////////////////////////////////////////////////////
3100 
ptGetFilesInTheImageFolder()3101 QFileInfoList ptGetFilesInTheImageFolder() {
3102   QStringList InputFileNameList = Settings->GetStringList("InputFileNameList");
3103   QFileInfo PathInfo(InputFileNameList[0]);
3104   QString fileName = PathInfo.fileName();
3105   QDir fileDir = PathInfo.dir();
3106   fileDir.setFilter(QDir::Files);
3107   fileDir.setSorting(QDir::Name);
3108 
3109   QStringList fileExts;
3110   if (Settings->GetInt("FileMgrShowRAWs")) {
3111     fileExts << FileExtsRaw;
3112   }
3113   if (Settings->GetInt("FileMgrShowBitmaps")) {
3114     fileExts << FileExtsBitmap;
3115   }
3116   return fileDir.entryInfoList(fileExts);
3117 }
3118 
ptGetImageFileName()3119 QString ptGetImageFileName() {
3120   QStringList InputFileNameList = Settings->GetStringList("InputFileNameList");
3121   QFileInfo PathInfo(InputFileNameList[0]);
3122   return PathInfo.fileName();
3123 }
3124 
CB_PreviousImageButton()3125 void CB_PreviousImageButton() {
3126   if (Settings->GetInt("HaveImage")==0) return;
3127 
3128   QString fileName = ptGetImageFileName();
3129   QFileInfoList files = ptGetFilesInTheImageFolder();
3130 
3131   for (int i = 1; i < files.count(); i++) {
3132     if (files[i].fileName() == fileName) {
3133       ImageFileToOpen = files[i - 1].absoluteFilePath();
3134       CB_MenuFileOpen(1);
3135       break;
3136     }
3137   }
3138 }
3139 
CB_NextImageButton()3140 void CB_NextImageButton() {
3141   if (Settings->GetInt("HaveImage")==0) return;
3142 
3143   QString fileName = ptGetImageFileName();
3144   QFileInfoList files = ptGetFilesInTheImageFolder();
3145 
3146   for (int i = 0; i < files.count() - 1; i++) {
3147     if (files[i].fileName() == fileName) {
3148       ImageFileToOpen = files[i + 1].absoluteFilePath();
3149       CB_MenuFileOpen(1);
3150       break;
3151     }
3152   }
3153 }
3154 
3155 ////////////////////////////////////////////////////////////////////////////////
3156 //
3157 // Callbacks pertaining to the Generic Tab
3158 //
3159 ////////////////////////////////////////////////////////////////////////////////
3160 
CB_CameraColorChoice(const QVariant Choice)3161 void CB_CameraColorChoice(const QVariant Choice) {
3162   int PreviousChoice = Settings->GetInt("CameraColor");
3163   Settings->SetValue("CameraColor",Choice);
3164   if (Choice.toInt() == ptCameraColor_Profile) {
3165     if (!Settings->GetString("CameraColorProfile").size()) {
3166       ptMessageBox::warning(MainWindow,
3167                            QObject::tr("Please load a profile first"),
3168                            QObject::tr("Please load a profile first"));
3169       Settings->SetValue("CameraColor",PreviousChoice);
3170     }
3171   }
3172 
3173   if (Settings->GetInt("CameraColor") == ptCameraColor_Embedded) {
3174     // TODO
3175     ptMessageBox::warning(MainWindow,
3176                         QObject::tr("Not yet implemented"),
3177                         QObject::tr("Not yet implemented. Reverting to Adobe."));
3178     Settings->SetValue("CameraColor",ptCameraColor_Adobe_Matrix);
3179   }
3180 
3181   Update(ptProcessorPhase_Raw,ptProcessorPhase_Highlights);
3182 }
3183 
CB_CameraColorProfileButton()3184 void CB_CameraColorProfileButton() {
3185   QString ProfileFileName = QFileDialog::getOpenFileName(
3186                  NULL,
3187                  QObject::tr("Open Profile"),
3188                  Settings->GetString("CameraColorProfilesDirectory"),
3189                  ProfilePattern);
3190 
3191   if (0 == ProfileFileName.size() ) {
3192     // Canceled just return
3193     return;
3194   } else {
3195     QFileInfo PathInfo(ProfileFileName);
3196     Settings->SetValue("CameraColorProfilesDirectory",PathInfo.absolutePath());
3197     Settings->SetValue("CameraColorProfile",PathInfo.absoluteFilePath());
3198     Settings->SetValue("CameraColor",ptCameraColor_Profile);
3199   }
3200 
3201   Update(ptProcessorPhase_Raw,ptProcessorPhase_Highlights);
3202 }
3203 
CB_CameraColorProfileIntentChoice(const QVariant Choice)3204 void CB_CameraColorProfileIntentChoice(const QVariant Choice) {
3205   Settings->SetValue("CameraColorProfileIntent",Choice);
3206   Update(ptProcessorPhase_Raw,ptProcessorPhase_Highlights);
3207 }
3208 
CB_CameraColorGammaChoice(const QVariant Choice)3209 void CB_CameraColorGammaChoice(const QVariant Choice) {
3210   Settings->SetValue("CameraColorGamma",Choice);
3211   Update(ptProcessorPhase_Raw,ptProcessorPhase_Highlights);
3212 }
3213 
CB_WorkColorChoice(const QVariant Choice)3214 void CB_WorkColorChoice(const QVariant Choice) {
3215   Settings->SetValue("WorkColor",Choice);
3216   PreCalcTransforms();
3217   Update(ptProcessorPhase_Raw,ptProcessorPhase_Highlights);
3218 }
3219 
CB_CMQualityChoice(const QVariant Choice)3220 void CB_CMQualityChoice(const QVariant Choice) {
3221   Settings->SetValue("CMQuality",Choice);
3222   MainWindow->UpdateSettings();
3223   PreCalcTransforms();
3224   Update(ptProcessorPhase_Preview);
3225 }
3226 
CB_PreviewColorProfileButton()3227 void CB_PreviewColorProfileButton() {
3228   QString ProfileFileName = QFileDialog::getOpenFileName(
3229                  NULL,
3230                  QObject::tr("Open Profile"),
3231                  Settings->GetString("PreviewColorProfilesDirectory"),
3232                  ProfilePattern);
3233 
3234   if (0 == ProfileFileName.size() ) {
3235     // Canceled just return
3236     return;
3237   } else {
3238     QFileInfo PathInfo(ProfileFileName);
3239     Settings->SetValue("PreviewColorProfilesDirectory",PathInfo.absolutePath());
3240     Settings->SetValue("PreviewColorProfile",PathInfo.absoluteFilePath());
3241   }
3242 
3243   // Reflect in gui.
3244   MainWindow->UpdateSettings();
3245 
3246   // Close old profile and open new one.
3247   cmsCloseProfile(PreviewColorProfile);
3248   PreviewColorProfile = cmsOpenProfileFromFile(
3249           Settings->GetString("PreviewColorProfile").toLocal8Bit().data(),
3250           "r");
3251   if (!PreviewColorProfile) {
3252     ptLogError(ptError_FileOpen,
3253          Settings->GetString("PreviewColorProfile").toLocal8Bit().data());
3254     assert(PreviewColorProfile);
3255   }
3256   PreCalcTransforms();
3257   // And update the preview.
3258   Update(ptProcessorPhase_Preview);
3259 }
3260 
CB_PreviewColorProfileIntentChoice(const QVariant Choice)3261 void CB_PreviewColorProfileIntentChoice(const QVariant Choice) {
3262   Settings->SetValue("PreviewColorProfileIntent",Choice);
3263   PreCalcTransforms();
3264   Update(ptProcessorPhase_Preview);
3265 }
3266 
CB_OutputColorProfileButton()3267 void CB_OutputColorProfileButton() {
3268   QString ProfileFileName = QFileDialog::getOpenFileName(
3269                  NULL,
3270                  QObject::tr("Open Profile"),
3271                  Settings->GetString("OutputColorProfilesDirectory"),
3272                  ProfilePattern);
3273 
3274   if (0 == ProfileFileName.size() ) {
3275     // Canceled just return
3276     return;
3277   } else {
3278     QFileInfo PathInfo(ProfileFileName);
3279     Settings->SetValue("OutputColorProfilesDirectory",PathInfo.absolutePath());
3280     Settings->SetValue("OutputColorProfile",PathInfo.absoluteFilePath());
3281   }
3282 
3283   // Reflect in gui.
3284   if (Settings->GetInt("HistogramMode")==ptHistogramMode_Output) {
3285     if (Settings->GetInt("ExposureIndicator")==1) {
3286       Update(ptProcessorPhase_Preview);
3287     } else {
3288       Update(ptProcessorPhase_OnlyHistogram);
3289     }
3290   }
3291   MainWindow->UpdateSettings();
3292 }
3293 
CB_OutputColorProfileResetButton()3294 void CB_OutputColorProfileResetButton() {
3295   Settings->SetValue("OutputColorProfile",
3296                      (Settings->GetString("UserDirectory") + "Profiles/Output/sRGB.icc").toLocal8Bit().data());
3297   if (Settings->GetInt("HistogramMode")==ptHistogramMode_Output) {
3298     if (Settings->GetInt("ExposureIndicator")==1) {
3299       Update(ptProcessorPhase_Preview);
3300     } else {
3301       Update(ptProcessorPhase_OnlyHistogram);
3302     }
3303   }
3304   MainWindow->UpdateSettings();
3305 }
3306 
CB_OutputColorProfileIntentChoice(const QVariant Choice)3307 void CB_OutputColorProfileIntentChoice(const QVariant Choice) {
3308   Settings->SetValue("OutputColorProfileIntent",Choice);
3309   if (Settings->GetInt("HistogramMode")==ptHistogramMode_Output) {
3310     if (Settings->GetInt("ExposureIndicator")==1) {
3311       Update(ptProcessorPhase_Preview);
3312     } else {
3313       Update(ptProcessorPhase_OnlyHistogram);
3314     }
3315   }
3316   MainWindow->UpdateSettings();
3317 }
3318 
CB_StyleChoice(const QVariant Choice)3319 void CB_StyleChoice(const QVariant Choice) {
3320   Settings->SetValue("Style", Choice);
3321   ptTheme::Theme newTheme = (ptTheme::Theme)Choice.toInt();
3322 
3323   if (newTheme == ptTheme::thNone) {
3324     Settings->SetValue("CustomCSSFile","");
3325     Theme->setCustomCSS("");
3326   }
3327 
3328   Theme->SwitchTo(newTheme, (ptTheme::Highlight)Settings->GetInt("StyleHighLight"));
3329 
3330 #ifdef Q_OS_MAC
3331 //dirty hack to make theming work
3332   MainWindow->MainSplitter->setStyleSheet("");
3333 #endif
3334 
3335   MainWindow->MainTabBook->setStyle(Theme->style());
3336   MainWindow->ProcessingTabBook->setStyle(Theme->style());
3337   MainWindow->BottomContainer->setStyle(Theme->style());
3338   MainWindow->PipeControlWidget->setStyle(Theme->style());
3339   MainWindow->MainSplitter->setStyle(Theme->style());
3340   MainWindow->ControlSplitter->setStyle(Theme->style());
3341   MainWindow->ViewSplitter->setStyle(Theme->style());
3342   MainWindow->ViewStartPage->setStyle(Theme->style());
3343 
3344   TheApplication->setPalette(Theme->palette());
3345 
3346   MainWindow->MainTabBook->setStyleSheet(Theme->stylesheet());
3347   MainWindow->BottomContainer->setStyleSheet(Theme->stylesheet());
3348   MainWindow->PipeControlWidget->setStyleSheet(Theme->stylesheet());
3349   MainWindow->StatusWidget->setStyleSheet(Theme->stylesheet());
3350   MainWindow->SearchWidget->setStyleSheet(Theme->stylesheet());
3351   MainWindow->ViewStartPageFrame->setStyleSheet(Theme->stylesheet());
3352 #ifdef Q_OS_MAC
3353 //dirty hack to make theming work
3354   if(Theme->MacStyleFlag){
3355   MainWindow->MainSplitter->setStyleSheet("background-color:"+Theme->MacBackGround+";");
3356   }
3357 #endif
3358   MainWindow->UpdateToolBoxes();
3359   SetBackgroundColor(Settings->GetInt("BackgroundColor"));
3360   CB_SliderWidthInput(Settings->GetInt("SliderWidth"));
3361 #ifndef PT_WITHOUT_FILEMGR
3362   FileMgrWindow->updateTheme();
3363 #endif
3364   BatchWindow->UpdateTheme();
3365 }
3366 
CB_StyleHighLightChoice(const QVariant Choice)3367 void CB_StyleHighLightChoice(const QVariant Choice) {
3368   Settings->SetValue("StyleHighLight",Choice);
3369   CB_StyleChoice(Settings->GetInt("Style"));
3370 }
3371 
CB_LoadStyleButton()3372 void CB_LoadStyleButton() {
3373   QString FileName;
3374 
3375   FileName = QFileDialog::getOpenFileName(NULL,
3376     QObject::tr("Open Image"),
3377     Settings->GetString("UserDirectory"),
3378     QObject::tr("CSS files (*.css *.qss);;All files(*.*)")
3379   );
3380 
3381   if (FileName.size() == 0) {
3382     return;
3383   } else {
3384     Settings->SetValue("CustomCSSFile", FileName);
3385     Theme->setCustomCSS(FileName);
3386     CB_StyleChoice(Settings->GetInt("Style"));
3387   }
3388 }
3389 
3390 
CB_SaveConfirmationCheck(const QVariant Check)3391 void CB_SaveConfirmationCheck(const QVariant Check) {
3392   Settings->SetValue("SaveConfirmation",Check);
3393   MainWindow->AutosaveSettingsWidget->setDisabled(Settings->GetInt("SaveConfirmation"));
3394 }
3395 
CB_AutosaveSettingsCheck(const QVariant Check)3396 void CB_AutosaveSettingsCheck(const QVariant Check) {
3397   Settings->SetValue("AutosaveSettings",Check);
3398 }
3399 
CB_ResetSettingsConfirmationCheck(const QVariant Check)3400 void CB_ResetSettingsConfirmationCheck(const QVariant Check) {
3401   Settings->SetValue("ResetSettingsConfirmation",Check);
3402 }
3403 
CB_FullPipeConfirmationCheck(const QVariant Check)3404 void CB_FullPipeConfirmationCheck(const QVariant Check) {
3405   Settings->SetValue("FullPipeConfirmation",Check);
3406 }
3407 
3408 
CB_WriteBackupSettingsCheck(const QVariant Check)3409 void CB_WriteBackupSettingsCheck(const QVariant Check) {
3410   Settings->SetValue("WriteBackupSettings",Check);
3411 }
3412 
CB_MemoryTestInput(const QVariant Value)3413 void CB_MemoryTestInput(const QVariant Value) {
3414   Settings->SetValue("MemoryTest",0);
3415   if (Value.toInt()>0)
3416     if (ptMessageBox::question(MainWindow,
3417         QObject::tr("Are you sure?"),
3418         QObject::tr("If you don't stop me, I will waste %1 MB of memory.").arg(Value.toInt()),
3419         QMessageBox::Ok,QMessageBox::Cancel)==QMessageBox::Ok){
3420       // allocate orphaned memory for testing
3421       char (*Test) = (char (*)) CALLOC2(Value.toInt()*1024*1024,1);
3422       memset(Test, '\0', Value.toInt()*1024*1024);
3423       ptMessageBox::critical(0,"Feedback","Memory wasted ;-)");
3424     }
3425 }
3426 
SetDetailViewRect(const ptStatus,QRect rect)3427 void SetDetailViewRect(const ptStatus, QRect rect) {
3428   DetailViewRect = rect;
3429 }
CB_PipeSizeChoice(const QVariant Choice)3430 void CB_PipeSizeChoice(const QVariant Choice) {
3431 
3432   short PreviousPipeSize = Settings->GetInt("PipeSize");
3433 
3434   if (Choice == ptPipeSize_Full &&
3435       Settings->GetInt("FullPipeConfirmation")==1 &&
3436       (Settings->GetInt("ImageH") > 2000 ||
3437        Settings->GetInt("ImageW") > 2000)) {
3438     ptMessageBox msgBox;
3439     msgBox.setWindowTitle(QObject::tr("Really switch to 1:1 pipe?"));
3440     msgBox.setText(QObject::tr("Switching to 1:1 pipe will increase memory usage and processing time greatly.\nAre you sure?"));
3441 
3442     QPushButton *DetailButton = msgBox.addButton(QObject::tr("Detail view"), QMessageBox::ActionRole);
3443     QPushButton *CancelButton = msgBox.addButton(QMessageBox::Cancel);
3444     msgBox.addButton(QMessageBox::Ok);
3445 
3446     msgBox.exec();
3447 
3448     if (msgBox.clickedButton() == CancelButton ||
3449         (msgBox.clickedButton() == DetailButton &&
3450          Settings->GetInt("HaveImage")==0)) {
3451       Settings->SetValue("PipeSize", PreviousPipeSize);
3452       return;
3453     } else if (msgBox.clickedButton() == DetailButton &&
3454                Settings->GetInt("HaveImage") == 1) {
3455       short OldZoomMode = 0;
3456       if (Settings->GetInt("DetailViewActive") == 0) {
3457         Settings->SetValue("DetailViewScale", PreviousPipeSize);
3458         if (TheProcessor->m_Image_DetailPreview == NULL)
3459           TheProcessor->m_Image_DetailPreview = new ptImage();
3460         // save a full image if we have several detail views without full view
3461         if (!Settings->useRAWHandling()) {
3462           TheProcessor->m_Image_DetailPreview->SetScaled(TheProcessor->m_Image_AfterDcRaw,
3463                                                          Settings->GetInt("Scaled"));
3464         } else {
3465           TheProcessor->m_Image_DetailPreview->Set(TheProcessor->m_Image_AfterDcRaw);
3466         }
3467       }
3468       // display the cache image and start crop mode
3469 
3470       // First : make sure we have Image_AfterDcRaw in the view window.
3471       // Anything else might have undergone geometric transformations that are
3472       // impossible to calculate reverse to a spot in dcraw.
3473       OldZoomMode = Settings->GetInt("ZoomMode");
3474       ViewWindow->ZoomToFit();
3475       UpdatePreviewImage(TheProcessor->m_Image_DetailPreview);
3476 
3477       // Allow to be selected in the view window. And deactivate main.
3478       BlockTools(btmBlockAll);
3479       ViewWindow->ShowStatus(QObject::tr("Detail view"));
3480       ViewWindow->StartSimpleRect(SetDetailViewRect);
3481       while (ViewWindow->interaction() == iaSelectRect) {
3482         QApplication::processEvents();
3483       }
3484 
3485       // Selection is done at this point. Disallow it further and activate main.
3486       BlockTools(btmUnblock);
3487 
3488       if (DetailViewRect.width() >>4 <<4 > 19 &&
3489           DetailViewRect.height() >>4 <<4 > 19) {
3490         Settings->SetValue("DetailViewActive",1);
3491         short CachedPipeSize = Settings->GetInt("DetailViewScale");
3492         Settings->SetValue("DetailViewCropX", ((DetailViewRect.left() >>4) <<4) << CachedPipeSize);
3493         Settings->SetValue("DetailViewCropY", ((DetailViewRect.top() >>4) <<4) << CachedPipeSize);
3494         Settings->SetValue("DetailViewCropW", ((DetailViewRect.width() >>4) <<4) << CachedPipeSize);
3495         Settings->SetValue("DetailViewCropH", ((DetailViewRect.height() >>4) <<4) << CachedPipeSize);
3496         Settings->ToDcRaw(TheDcRaw);
3497       } else {
3498         ptMessageBox::information(NULL,"No crop","Too small. Please try again!");
3499         //ViewWindow->Zoom(OldZoom,0);    // TODOSR: re-enable
3500         Settings->SetValue("ZoomMode",OldZoomMode);
3501         Update(ptProcessorPhase_Preview);
3502         if (Settings->GetInt("DetailViewActive")==0) {
3503           delete TheProcessor->m_Image_DetailPreview;
3504           TheProcessor->m_Image_DetailPreview = NULL;
3505         }
3506         Settings->SetValue("PipeSize",PreviousPipeSize);
3507         return;
3508       }
3509 
3510       //ViewWindow->Zoom(OldZoom,0);    // TODOSR: re-enable
3511       Settings->SetValue("ZoomMode",OldZoomMode);
3512 
3513     } else { // 1:1 full mode
3514       // clean up possible detail view cache
3515       if (TheProcessor->m_Image_DetailPreview != NULL) {
3516         delete TheProcessor->m_Image_DetailPreview;
3517         TheProcessor->m_Image_DetailPreview = NULL;
3518         Settings->SetValue("DetailViewActive",0);
3519         Settings->SetValue("DetailViewCropX", 0);
3520         Settings->SetValue("DetailViewCropY", 0);
3521         Settings->SetValue("DetailViewCropW", 0);
3522         Settings->SetValue("DetailViewCropH", 0);
3523         Settings->ToDcRaw(TheDcRaw);
3524       }
3525     }
3526   } else {
3527     // clean up possible detail view cache
3528     if (TheProcessor->m_Image_DetailPreview != NULL) {
3529       delete TheProcessor->m_Image_DetailPreview;
3530       TheProcessor->m_Image_DetailPreview = NULL;
3531       Settings->SetValue("DetailViewActive",0);
3532       Settings->SetValue("DetailViewCropX", 0);
3533       Settings->SetValue("DetailViewCropY", 0);
3534       Settings->SetValue("DetailViewCropW", 0);
3535       Settings->SetValue("DetailViewCropH", 0);
3536       Settings->ToDcRaw(TheDcRaw);
3537     }
3538   }
3539 
3540   MainWindow->UpdateToolBoxes();
3541 
3542   Settings->SetValue("PipeSize",Choice);
3543   short PipeSize = Settings->GetInt("PipeSize");
3544   short Expansion = PreviousPipeSize-PipeSize;
3545 
3546   if (Settings->GetInt("DetailViewActive")==0) {
3547     // Following adaptation is needed for the case spot WB is in place.
3548     if (Expansion > 0) {
3549       Settings->SetValue("VisualSelectionX",
3550                          Settings->GetInt("VisualSelectionX")<<Expansion);
3551       Settings->SetValue("VisualSelectionY",
3552                          Settings->GetInt("VisualSelectionY")<<Expansion);
3553       Settings->SetValue("VisualSelectionWidth",
3554                          Settings->GetInt("VisualSelectionWidth")<<Expansion);
3555       Settings->SetValue("VisualSelectionHeight",
3556                          Settings->GetInt("VisualSelectionHeight")<<Expansion);
3557     } else {
3558       Expansion = -Expansion;
3559       Settings->SetValue("VisualSelectionX",
3560                          Settings->GetInt("VisualSelectionX")>>Expansion);
3561       Settings->SetValue("VisualSelectionY",
3562                          Settings->GetInt("VisualSelectionY")>>Expansion);
3563       Settings->SetValue("VisualSelectionWidth",
3564                          Settings->GetInt("VisualSelectionWidth")>>Expansion);
3565       Settings->SetValue("VisualSelectionHeight",
3566                          Settings->GetInt("VisualSelectionHeight")>>Expansion);
3567     }
3568   }
3569 
3570   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
3571   MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
3572 
3573   ALLOCATED(10000000);
3574 }
3575 
3576 
CB_RunModeCheck(const QVariant Check)3577 void CB_RunModeCheck(const QVariant Check) {
3578   Settings->SetValue("RunMode",Check);
3579   MainWindow->UpdateSettings();
3580   if (Settings->GetInt("RunMode")==0) {
3581     Update(ptProcessorPhase_Output);
3582   }
3583 }
3584 
CB_PreviewModeButton(const QVariant State)3585 void CB_PreviewModeButton(const QVariant State) {
3586   Settings->SetValue("PreviewTabMode",State);
3587   if (Settings->GetInt("PreviewTabMode")) {
3588     Settings->SetValue("PreviewMode",ptPreviewMode_Tab);
3589     MainWindow->PreviewModeButton->setChecked(1);
3590   } else {
3591     Settings->SetValue("PreviewMode",ptPreviewMode_End);
3592     MainWindow->PreviewModeButton->setChecked(0);
3593   }
3594   Update(ptProcessorPhase_Preview);
3595 }
3596 
CB_RunButton()3597 void CB_RunButton() {
3598   short OldRunMode = Settings->GetInt("RunMode");
3599   Settings->SetValue("RunMode",0);
3600   Update(ptProcessorPhase_Output);
3601   Settings->SetValue("RunMode",OldRunMode);
3602   MainWindow->UpdateSettings();
3603 }
3604 
ResetButtonHandler(const short mode)3605 void ResetButtonHandler(const short mode) {
3606   int DoOpen = 1;
3607   if (mode == ptResetMode_Full) { // full reset
3608     if ( Settings->GetInt("ResetSettingsConfirmation")==1 ) {
3609       ptMessageBox msgBox;
3610       msgBox.setIcon(QMessageBox::Question);
3611       msgBox.setWindowTitle(QObject::tr("Reset?"));
3612       msgBox.setText(QObject::tr("Reset to neutral values?\n"));
3613       msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
3614       msgBox.setDefaultButton(QMessageBox::Ok);
3615       if ( msgBox.exec()==QMessageBox::Cancel ) {
3616         DoOpen = 0;
3617       }
3618     }
3619     if ( DoOpen==1 ) {
3620       CB_OpenSettingsFile(Settings->GetString("PresetDirectory") + "/Neutral_absolute.pts");
3621     }
3622   } else if (mode == ptResetMode_User) { // reset to startup settings
3623     if ( Settings->GetInt("ResetSettingsConfirmation")==1 ) {
3624       ptMessageBox msgBox;
3625       msgBox.setIcon(QMessageBox::Question);
3626       msgBox.setWindowTitle(QObject::tr("Reset?"));
3627       msgBox.setText(QObject::tr("Reset to start up settings?\n"));
3628       msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
3629       msgBox.setDefaultButton(QMessageBox::Ok);
3630       if ( msgBox.exec()==QMessageBox::Cancel ) {
3631         DoOpen = 0;
3632       }
3633     }
3634     if ( DoOpen==1 ) {
3635       CB_OpenSettingsFile(Settings->GetString("StartupSettingsFile"));
3636     }
3637   } else if (mode == ptResetMode_OpenPreset) { // open preset file
3638     CB_OpenPresetFileButton();
3639   } else { // open settings file
3640     CB_OpenSettingsFileButton();
3641   }
3642 }
3643 
CB_ResetButton()3644 void CB_ResetButton() {
3645   ResetButtonHandler(Settings->GetInt("ResetButtonMode"));
3646 }
3647 
CB_SpecialPreviewChoice(const QVariant Choice)3648 void CB_SpecialPreviewChoice(const QVariant Choice) {
3649   Settings->SetValue("SpecialPreview",Choice);
3650   Update(ptProcessorPhase_Preview);
3651 }
3652 
CB_GimpExecCommandButton()3653 void CB_GimpExecCommandButton() {
3654 
3655   QString GimpExecCommandString = QFileDialog::getOpenFileName(NULL,
3656     QObject::tr("Get Gimp command"),
3657     Settings->GetString("UserDirectory"),
3658     "All files (*.*)");
3659 
3660   if (0 == GimpExecCommandString.size() ) {
3661     // Canceled just return
3662     return;
3663   } else {
3664     QFileInfo PathInfo(GimpExecCommandString);
3665     Settings->SetValue("GimpExecCommand",PathInfo.absoluteFilePath());
3666   }
3667 
3668   // Reflect in gui.
3669   MainWindow->UpdateSettings();
3670 }
3671 
CB_RememberSettingLevelChoice(const QVariant Choice)3672 void CB_RememberSettingLevelChoice(const QVariant Choice) {
3673   Settings->SetValue("RememberSettingLevel",Choice);
3674   MainWindow->UpdateSettings();
3675 }
3676 
CB_StartupSettingsCheck(const QVariant State)3677 void CB_StartupSettingsCheck(const QVariant State) {
3678   Settings->SetValue("StartupSettings",State);
3679 }
3680 
CB_StartupSettingsResetCheck(const QVariant State)3681 void CB_StartupSettingsResetCheck(const QVariant State) {
3682   Settings->SetValue("StartupSettingsReset",State);
3683 }
3684 
CB_StartupSettingsButton()3685 void CB_StartupSettingsButton() {
3686   QString StartupSettingsString = QFileDialog::getOpenFileName(NULL,
3687     QObject::tr("Get preset file"),
3688     Settings->GetString("PresetDirectory"),
3689     SettingsFilePattern);
3690 
3691   if (0 == StartupSettingsString.size() ) {
3692     // Canceled just return
3693     return;
3694   } else {
3695     QFileInfo PathInfo(StartupSettingsString);
3696     Settings->SetValue("PresetDirectory",PathInfo.absolutePath());
3697     Settings->SetValue("StartupSettingsFile",PathInfo.absoluteFilePath());
3698   }
3699 
3700   // Reflect in gui.
3701   MainWindow->UpdateSettings();
3702 }
3703 
CB_StartupUIModeChoice(const QVariant Choice)3704 void CB_StartupUIModeChoice(const QVariant Choice) {
3705   Settings->SetValue("StartupUIMode",Choice);
3706 }
3707 
CB_StartupPipeSizeChoice(const QVariant Choice)3708 void CB_StartupPipeSizeChoice(const QVariant Choice) {
3709   Settings->SetValue("StartupPipeSize", Choice);
3710 }
3711 
CB_CropInitialZoomChoice(const QVariant Choice)3712 void CB_CropInitialZoomChoice(const QVariant Choice) {
3713   Settings->SetValue("CropInitialZoom",Choice);
3714 }
3715 
CB_InputsAddPowerLawCheck(const QVariant State)3716 void CB_InputsAddPowerLawCheck(const QVariant State) {
3717   Settings->SetValue("InputsAddPowerLaw",State);
3718   if (Settings->GetInt("InputsAddPowerLaw")) {
3719     Settings->SetValue("InputPowerFactor",2.2);
3720   } else {
3721     Settings->SetValue("InputPowerFactor",1.0);
3722   }
3723   Update(ptProcessorPhase_RGB);
3724 }
3725 
CB_ToolBoxModeCheck(const QVariant State)3726 void CB_ToolBoxModeCheck(const QVariant State) {
3727   Settings->SetValue("ToolBoxMode",State);
3728   MainWindow->OnToolBoxesEnabledTriggered(Settings->GetInt("ToolBoxMode"));
3729 }
3730 
CB_TabStatusIndicatorInput(const QVariant Value)3731 void CB_TabStatusIndicatorInput(const QVariant Value) {
3732   Settings->SetValue("TabStatusIndicator",Value);
3733   MainWindow->UpdateSettings();
3734 }
3735 
CB_PreviewTabModeCheck(const QVariant State)3736 void CB_PreviewTabModeCheck(const QVariant State) {
3737   Settings->SetValue("PreviewTabMode",State);
3738   if (Settings->GetInt("PreviewTabMode")) {
3739     Settings->SetValue("PreviewMode",ptPreviewMode_Tab);
3740   } else {
3741     Settings->SetValue("PreviewMode",ptPreviewMode_End);
3742   }
3743   Update(ptProcessorPhase_Preview);
3744 }
3745 
CB_BackgroundColorCheck(const QVariant State)3746 void CB_BackgroundColorCheck(const QVariant State) {
3747   Settings->SetValue("BackgroundColor",State);
3748   SetBackgroundColor(Settings->GetInt("BackgroundColor"));
3749 }
3750 
CB_BackgroundColorButton()3751 void CB_BackgroundColorButton() {
3752   QPixmap Pix(80, 14);
3753   QColor  Color;
3754   Color.setRed(Settings->GetInt("BackgroundRed"));
3755   Color.setGreen(Settings->GetInt("BackgroundGreen"));
3756   Color.setBlue(Settings->GetInt("BackgroundBlue"));
3757   QColorDialog Dialog(Color,NULL);
3758   Dialog.setStyle(Theme->systemStyle());
3759   Dialog.setPalette(Theme->systemPalette());
3760   Dialog.exec();
3761   QColor TestColor = Dialog.selectedColor();
3762   if (TestColor.isValid()) {
3763     Color = TestColor;
3764     Settings->SetValue("BackgroundRed",Color.red());
3765     Settings->SetValue("BackgroundGreen",Color.green());
3766     Settings->SetValue("BackgroundBlue",Color.blue());
3767     Pix.fill(Color);
3768     MainWindow->BackgroundColorButton->setIcon(Pix);
3769     if (Settings->GetInt("BackgroundColor")){
3770       SetBackgroundColor(1);
3771     }
3772   }
3773 }
3774 
SetBackgroundColor(int SetIt)3775 void SetBackgroundColor(int SetIt) {
3776   if (SetIt) {
3777     QPalette BGPal;
3778     BGPal.setColor(QPalette::Background, QColor(Settings->GetInt("BackgroundRed"),
3779                                                 Settings->GetInt("BackgroundGreen"),
3780                                                 Settings->GetInt("BackgroundBlue")));
3781     ViewWindow->setPalette(BGPal);
3782     MainWindow->ViewStartPage->setPalette(BGPal);
3783   } else {
3784     ViewWindow->setPalette(Theme->palette());
3785     MainWindow->ViewStartPage->setPalette(Theme->palette());
3786   }
3787 }
3788 
CB_SliderWidthInput(const QVariant Value)3789 void CB_SliderWidthInput(const QVariant Value) {
3790   Settings->SetValue("SliderWidth",Value);
3791   if (Settings->GetInt("SliderWidth") == 0)
3792 //  maximum slider width is equal to the toolbar width
3793     MainWindow->setStyleSheet("ptSlider { max-width: " + QString("%1").arg(10000) + "px; }");
3794   else
3795 //  maximum slider width is equal to "SliderWidth"
3796     MainWindow->setStyleSheet("ptSlider { max-width: " + QString("%1").arg(Settings->GetInt("SliderWidth")) + "px; }");
3797 }
3798 
CB_SaveButtonModeChoice(const QVariant Choice)3799 void CB_SaveButtonModeChoice(const QVariant Choice) {
3800   Settings->SetValue("SaveButtonMode",Choice);
3801   SaveButtonToolTip(Settings->GetInt("SaveButtonMode"));
3802 }
3803 
CB_ResetButtonModeChoice(const QVariant Value)3804 void CB_ResetButtonModeChoice(const QVariant Value) {
3805   Settings->SetValue("ResetButtonMode",Value);
3806 }
3807 
CB_SearchBarEnableCheck(const QVariant State)3808 void CB_SearchBarEnableCheck(const QVariant State) {
3809   Settings->SetValue("SearchBarEnable",State);
3810   MainWindow->SearchWidget->setVisible(Settings->GetInt("SearchBarEnable"));
3811 }
3812 
SaveButtonToolTip(const short mode)3813 void SaveButtonToolTip(const short mode) {
3814   if (mode==ptOutputMode_Full) {
3815     MainWindow->WritePipeButton->setToolTip(QObject::tr("Save full size image"));
3816   } else if (mode==ptOutputMode_Pipe) {
3817     MainWindow->WritePipeButton->setToolTip(QObject::tr("Save current pipe"));
3818   } else if (mode==ptOutputMode_Jobfile) {
3819     MainWindow->WritePipeButton->setToolTip(QObject::tr("Save job file"));
3820   } else if (mode==ptOutputMode_Settingsfile) {
3821     MainWindow->WritePipeButton->setToolTip(QObject::tr("Save settings file"));
3822   } else if (mode==ptOutputMode_Batch) {
3823     MainWindow->WritePipeButton->setToolTip(QObject::tr("Save and send to batch manager"));
3824   }
3825 }
3826 
3827 ////////////////////////////////////////////////////////////////////////////////
3828 //
3829 // Callbacks pertaining to the Camera Tab
3830 // Partim Generic Corrections.
3831 //
3832 ////////////////////////////////////////////////////////////////////////////////
3833 
CB_OpenFileButton()3834 void CB_OpenFileButton() {
3835   CB_MenuFileOpen(0);
3836 }
3837 
CB_OpenSettingsFile(QString SettingsFileName)3838 void CB_OpenSettingsFile(QString SettingsFileName) {
3839   if (0 == SettingsFileName.size()) return;
3840   short NextPhase = 1;
3841   short ReturnValue = GFilterDM->ReadPresetFile(SettingsFileName, NextPhase);
3842   if (ReturnValue) {
3843     ptMessageBox::critical(0,"Error","No valid settings file!\n" + SettingsFileName);
3844     return;
3845   }
3846   if (NextPhase == 1) {
3847     if (Settings->GetInt("HaveImage")==1) {
3848       CalculateMultipliersFromTemperature();
3849       NormalizeMultipliers(Settings->GetInt("MultiplierEnhance"));
3850     }
3851     if (Settings->GetInt("AutomaticPipeSize") && Settings->ToolIsActive("TabResize")) {
3852       if (!CalculatePipeSize())
3853         Update(ptProcessorPhase_Raw,ptProcessorPhase_Load);
3854     } else {
3855       Update(ptProcessorPhase_Raw,ptProcessorPhase_Load);
3856     }
3857   } else {
3858     //TODO: check Nextphase against automatic pipesize
3859     Update(NextPhase);
3860   }
3861   SetRatingFromXmp();
3862   if (Settings->GetInt("LoadTags"))
3863     SetTagsFromXmp();
3864 }
3865 
CB_OpenSettingsFileButton()3866 void CB_OpenSettingsFileButton() {
3867   if (!ptConfirmRequest::loadConfig(lcmGeneralCfg)) {
3868     return;
3869   }
3870 
3871   ptAddUndo();
3872 
3873   QString SettingsFilePattern =
3874     QObject::tr("All supported files (*.pts *ptj);;Settings files (*.pts);;Job files (*.ptj);;All files (*.*)");
3875   QString SettingsFileName =
3876     QFileDialog::getOpenFileName(NULL,
3877                                  QObject::tr("Open setting file"),
3878                                  Settings->GetString("RawsDirectory"),
3879                                  SettingsFilePattern);
3880   if (0 == SettingsFileName.size()) return;
3881   CB_OpenSettingsFile(SettingsFileName);
3882 }
3883 
CB_OpenPresetFileButton()3884 void CB_OpenPresetFileButton() {
3885   ptAddUndo();
3886 
3887   QString SettingsFilePattern =
3888     QObject::tr("All supported files (*.pts *ptj);;Settings files (*.pts);;Job files (*.ptj);;All files (*.*)");
3889   QString SettingsFileName =
3890     QFileDialog::getOpenFileName(NULL,
3891                                  QObject::tr("Open preset"),
3892                                  Settings->GetString("PresetDirectory"),
3893                                  SettingsFilePattern);
3894   if (0 == SettingsFileName.size()) return;
3895   CB_OpenSettingsFile(SettingsFileName);
3896 }
3897 
CB_UseThumbnailCheck(const QVariant Check)3898 void CB_UseThumbnailCheck(const QVariant Check) {
3899   Settings->SetValue("UseThumbnail", Check);
3900 
3901   if (Settings->GetInt("IsRAW")) {
3902     Update(ptProcessorPhase_Raw, ptProcessorPhase_Load);
3903   }
3904 }
3905 
3906 
CB_BadPixelsChoice(const QVariant Choice)3907 void CB_BadPixelsChoice(const QVariant Choice) {
3908   Settings->SetValue("HaveBadPixels", Choice);
3909   short Cancelled = 0;
3910   if (Choice.toInt() == 1) {
3911     // Request to load one.
3912     QString BadPixelsFileName =
3913       QFileDialog::getOpenFileName(NULL,
3914                                    QObject::tr("Open 'bad pixels' file"),
3915                                    NULL);
3916     if (0 == Settings->GetString("BadPixelsFileName").size() ) {
3917       // A cancel we'll interprate as no bad pixel
3918       Settings->SetValue("HaveBadPixels",0);
3919       Cancelled = 1;
3920     } else {
3921       Settings->SetValue("HaveBadPixels",2);
3922       Settings->SetValue("BadPixelsFileName",BadPixelsFileName);
3923     }
3924   }
3925   if (!Cancelled) {
3926     Update(ptProcessorPhase_Raw,ptProcessorPhase_Load);
3927     MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
3928   }
3929 }
3930 
CB_DarkFrameChoice(const QVariant Choice)3931 void CB_DarkFrameChoice(const QVariant Choice) {
3932   Settings->SetValue("HaveDarkFrame",Choice);
3933   short Cancelled = 0;
3934   if (Choice.toInt() == 1) {
3935     // Request to load one.
3936     QString DarkFrameFileName =
3937       QFileDialog::getOpenFileName(NULL,
3938                                    QObject::tr("Open 'dark frame' file"),
3939                                    NULL);
3940     if (0 == Settings->GetString("DarkFrameFileName").size() ) {
3941       // A cancel we'll interprate as no bad pixel
3942       Settings->SetValue("HaveDarkFrame",0);
3943       Cancelled = 1;
3944     } else {
3945       Settings->SetValue("HaveDarkFrame",2);
3946       Settings->SetValue("DarkFrameFileName",DarkFrameFileName);
3947     }
3948   }
3949   if (!Cancelled) {
3950     Update(ptProcessorPhase_Raw,ptProcessorPhase_Load);
3951     MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
3952   }
3953 }
3954 
3955 ////////////////////////////////////////////////////////////////////////////////
3956 //
3957 // Callbacks pertaining to the Camera Tab
3958 // Partim White Balance.
3959 //
3960 ////////////////////////////////////////////////////////////////////////////////
3961 void SelectSpotWBDone(const ptStatus ExitStatus, const QRect SelectionRect);
3962 
CB_WhiteBalanceChoice(const QVariant Choice)3963 void CB_WhiteBalanceChoice(const QVariant Choice) {
3964   Settings->SetValue("WhiteBalance",Choice);
3965   if (Settings->GetInt("HaveImage") == 0 || (!Settings->useRAWHandling())) return;
3966 
3967   switch (Choice.toInt()) {
3968     case ptWhiteBalance_Camera :
3969     case ptWhiteBalance_Auto :
3970     case ptWhiteBalance_Manual :
3971       // In fact all of above just translates to settings into
3972       // DcRaw handled via GuiSettingsToDcRaw. Nothing more to do.
3973       Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
3974       break;
3975 
3976     case ptWhiteBalance_Spot: {
3977       // First : make sure we have Image_AfterDcRaw in the view window.
3978       // Anything else might have undergone geometric transformations that are
3979       // impossible to calculate reverse to a spot in dcraw.
3980       ViewWindow->SaveZoom();
3981       ViewWindow->ZoomToFit();
3982       UpdatePreviewImage(TheProcessor->m_Image_AfterDcRaw);
3983 
3984       // Allow to be selected in the view window. And deactivate main.
3985       BlockTools(btmBlockAll);
3986       ViewWindow->ShowStatus(QObject::tr("Spot WB"));
3987       ReportProgress(QObject::tr("Spot WB"));
3988       ViewWindow->StartSimpleRect(SelectSpotWBDone);
3989       ViewWindow->setFocus();
3990       break;
3991     }
3992 
3993     default :
3994       // Here we have presets selected from ptWhiteBalances.
3995       // GuiSettings->m_WhiteBalance should point
3996       // to the right index into the array.
3997       Settings->SetValue("RMultiplier",
3998                          ptWhiteBalances[Choice.toInt()].m_Multipliers[0]);
3999       Settings->SetValue("GMultiplier",
4000                          ptWhiteBalances[Choice.toInt()].m_Multipliers[1]);
4001       Settings->SetValue("BMultiplier",
4002                          ptWhiteBalances[Choice.toInt()].m_Multipliers[2]);
4003       Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4004   }
4005 }
4006 
SelectSpotWBDone(const ptStatus ExitStatus,const QRect SelectionRect)4007 void SelectSpotWBDone(const ptStatus ExitStatus, const QRect SelectionRect) {
4008   // Selection is done at this point. Disallow it further and activate main.
4009   BlockTools(btmUnblock);
4010 
4011   if (ExitStatus == stSuccess) {
4012     Settings->SetValue("VisualSelectionX", SelectionRect.left());
4013     Settings->SetValue("VisualSelectionY", SelectionRect.top());
4014     Settings->SetValue("VisualSelectionWidth", SelectionRect.width());
4015     Settings->SetValue("VisualSelectionHeight", SelectionRect.height());
4016 
4017     TRACEKEYVALS("Selection X","%d",
4018                  Settings->GetInt("VisualSelectionX"));
4019     TRACEKEYVALS("Selection Y","%d",
4020                  Settings->GetInt("VisualSelectionY"));
4021     TRACEKEYVALS("Selection W","%d",
4022                  Settings->GetInt("VisualSelectionWidth"));
4023     TRACEKEYVALS("Selection H","%d",
4024                  Settings->GetInt("VisualSelectionHeight"));
4025   }
4026 
4027   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4028   ViewWindow->RestoreZoom();
4029 }
4030 
CB_SpotWBButton()4031 void CB_SpotWBButton() {
4032   CB_WhiteBalanceChoice(ptWhiteBalance_Spot);
4033 }
4034 
CB_ColorTemperatureInput(const QVariant Value)4035 void CB_ColorTemperatureInput(const QVariant Value) {
4036   Settings->SetValue("ColorTemperature",Value);
4037   Settings->SetValue("WhiteBalance",ptWhiteBalance_Manual);
4038   if (!TheDcRaw) return;
4039   CalculateMultipliersFromTemperature();
4040   NormalizeMultipliers(Settings->GetInt("MultiplierEnhance"));
4041   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4042 }
4043 
CB_GreenIntensityInput(const QVariant Value)4044 void CB_GreenIntensityInput(const QVariant Value) {
4045   Settings->SetValue("GreenIntensity",Value);
4046   Settings->SetValue("WhiteBalance",ptWhiteBalance_Manual);
4047   if (!TheDcRaw) return;
4048   CalculateMultipliersFromTemperature();
4049   NormalizeMultipliers(Settings->GetInt("MultiplierEnhance"));
4050   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4051 }
4052 
CB_MultiplierEnhanceCheck(const QVariant State)4053 void CB_MultiplierEnhanceCheck(const QVariant State) {
4054   Settings->SetValue("MultiplierEnhance",State);
4055   if (!TheDcRaw) return;
4056   TheDcRaw->m_UserSetting_MaxMultiplier = Settings->GetInt("MultiplierEnhance");
4057   NormalizeMultipliers(Settings->GetInt("MultiplierEnhance"));
4058   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4059 }
4060 
CB_RMultiplierInput(const QVariant Value)4061 void CB_RMultiplierInput(const QVariant Value) {
4062   Settings->SetValue("RMultiplier",Value);
4063   Settings->SetValue("WhiteBalance",ptWhiteBalance_Manual);
4064   NormalizeMultipliers(Settings->GetInt("MultiplierEnhance"));
4065   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4066 }
4067 
CB_GMultiplierInput(const QVariant Value)4068 void CB_GMultiplierInput(const QVariant Value) {
4069   Settings->SetValue("GMultiplier",Value);
4070   Settings->SetValue("WhiteBalance",ptWhiteBalance_Manual);
4071   NormalizeMultipliers(Settings->GetInt("MultiplierEnhance"));
4072   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4073 }
4074 
CB_BMultiplierInput(const QVariant Value)4075 void CB_BMultiplierInput(const QVariant Value) {
4076   Settings->SetValue("BMultiplier",Value);
4077   Settings->SetValue("WhiteBalance",ptWhiteBalance_Manual);
4078   NormalizeMultipliers(Settings->GetInt("MultiplierEnhance"));
4079   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4080 }
4081 
CB_ManualBlackPointCheck(const QVariant State)4082 void CB_ManualBlackPointCheck(const QVariant State) {
4083   short OldState = Settings->GetInt("ManualBlackPoint");
4084   Settings->SetValue("ManualBlackPoint",State);
4085   if (OldState) {
4086     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4087   } else {
4088     MainWindow->UpdateSettings();
4089   }
4090 }
4091 
CB_BlackPointInput(const QVariant Value)4092 void CB_BlackPointInput(const QVariant Value) {
4093   Settings->SetValue("BlackPoint",Value);
4094   if (Settings->GetInt("ManualBlackPoint")) {
4095     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4096   }
4097 }
4098 
CB_ManualWhitePointCheck(const QVariant State)4099 void CB_ManualWhitePointCheck(const QVariant State) {
4100   short OldState = Settings->GetInt("ManualWhitePoint");
4101   Settings->SetValue("ManualWhitePoint",State);
4102   if (OldState) {
4103     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4104   } else {
4105     MainWindow->UpdateSettings();
4106   }
4107 }
4108 
CB_WhitePointInput(const QVariant Value)4109 void CB_WhitePointInput(const QVariant Value) {
4110   Settings->SetValue("WhitePoint",Value);
4111   if (Settings->GetInt("ManualWhitePoint")) {
4112     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4113   }
4114 }
4115 
4116 ////////////////////////////////////////////////////////////////////////////////
4117 //
4118 // Callbacks pertaining to the Camera Tab
4119 // Partim Demosaicing.
4120 //
4121 ////////////////////////////////////////////////////////////////////////////////
4122 
CB_CaCorrectChoice(const QVariant Choice)4123 void CB_CaCorrectChoice(const QVariant Choice) {
4124   Settings->SetValue("CaCorrect",Choice);
4125   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4126 }
4127 
CB_CaRedInput(const QVariant Value)4128 void CB_CaRedInput(const QVariant Value) {
4129   Settings->SetValue("CaRed",Value);
4130   if (Settings->GetInt("CaCorrect")==ptCACorrect_Manual)
4131     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4132 }
4133 
CB_CaBlueInput(const QVariant Value)4134 void CB_CaBlueInput(const QVariant Value) {
4135   Settings->SetValue("CaBlue",Value);
4136   if (Settings->GetInt("CaCorrect")==ptCACorrect_Manual)
4137     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4138 }
4139 
CB_GreenEquilInput(const QVariant Value)4140 void CB_GreenEquilInput(const QVariant Value) {
4141   Settings->SetValue("GreenEquil",Value);
4142   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4143 }
4144 
CB_CfaLineDenoiseInput(const QVariant Value)4145 void CB_CfaLineDenoiseInput(const QVariant Value) {
4146   Settings->SetValue("CfaLineDenoise",Value);
4147   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4148 }
4149 
CB_AdjustMaximumThresholdInput(const QVariant Value)4150 void CB_AdjustMaximumThresholdInput(const QVariant Value) {
4151   Settings->SetValue("AdjustMaximumThreshold",Value);
4152   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4153 }
4154 
CB_RawDenoiseThresholdInput(const QVariant Value)4155 void CB_RawDenoiseThresholdInput(const QVariant Value) {
4156   Settings->SetValue("RawDenoiseThreshold",Value);
4157   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4158 }
4159 
CB_HotpixelReductionInput(const QVariant Value)4160 void CB_HotpixelReductionInput(const QVariant Value) {
4161   Settings->SetValue("HotpixelReduction",Value);
4162   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4163 }
4164 
CB_BayerDenoiseChoice(const QVariant Choice)4165 void CB_BayerDenoiseChoice(const QVariant Choice) {
4166   Settings->SetValue("BayerDenoise",Choice);
4167   if (!Settings->GetInt("PipeSize")) {
4168     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4169   }
4170 }
4171 
CB_InterpolationChoice(const QVariant Choice)4172 void CB_InterpolationChoice(const QVariant Choice) {
4173   Settings->SetValue("Interpolation",Choice);
4174   MainWindow->UpdateSettings();
4175   if (!Settings->GetInt("PipeSize")) {
4176     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4177   }
4178 }
4179 
CB_InterpolationPassesInput(const QVariant Value)4180 void CB_InterpolationPassesInput(const QVariant Value) {
4181   Settings->SetValue("InterpolationPasses",Value);
4182   if (!Settings->GetInt("PipeSize") &&
4183       (Settings->GetInt("Interpolation")==ptInterpolation_DCB ||
4184        Settings->GetInt("Interpolation")==ptInterpolation_DCBSoft ||
4185        Settings->GetInt("Interpolation")==ptInterpolation_DCBSharp)) {
4186     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4187   }
4188 }
4189 
CB_MedianPassesInput(const QVariant Value)4190 void CB_MedianPassesInput(const QVariant Value) {
4191   Settings->SetValue("MedianPasses",Value);
4192   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4193 }
4194 
CB_ESMedianPassesInput(const QVariant Value)4195 void CB_ESMedianPassesInput(const QVariant Value) {
4196   Settings->SetValue("ESMedianPasses",Value);
4197   if (!Settings->GetInt("PipeSize")) {
4198     Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4199   }
4200 }
4201 
CB_EeciRefineCheck(const QVariant State)4202 void CB_EeciRefineCheck(const QVariant State) {
4203   Settings->SetValue("EeciRefine",State);
4204   Update(ptProcessorPhase_Raw,ptProcessorPhase_Demosaic);
4205 }
4206 
4207 ////////////////////////////////////////////////////////////////////////////////
4208 //
4209 // Callbacks pertaining to the Camera Tab
4210 // Partim Highlight.
4211 //
4212 ////////////////////////////////////////////////////////////////////////////////
4213 
CB_ClipModeChoice(const QVariant Choice)4214 void CB_ClipModeChoice(const QVariant Choice) {
4215   Settings->SetValue("ClipMode",Choice);
4216   Update(ptProcessorPhase_Raw,ptProcessorPhase_Highlights);
4217 }
4218 
CB_ClipParameterInput(const QVariant Value)4219 void CB_ClipParameterInput(const QVariant Value) {
4220   Settings->SetValue("ClipParameter",Value);
4221   Update(ptProcessorPhase_Raw,ptProcessorPhase_Highlights);
4222 }
4223 
4224 
4225 ////////////////////////////////////////////////////////////////////////////////
4226 //
4227 // Callbacks pertaining to Lensfun (Geometry tab)
4228 //
4229 ////////////////////////////////////////////////////////////////////////////////
4230 
4231 // General tab
4232 
CB_LfunFocalInput(const QVariant Value)4233 void CB_LfunFocalInput(const QVariant Value) {
4234   Settings->SetValue("LfunFocal", Value);
4235   Update(ptProcessorPhase_Geometry);
4236 }
4237 
CB_LfunApertureInput(const QVariant Value)4238 void CB_LfunApertureInput(const QVariant Value) {
4239   Settings->SetValue("LfunAperture", Value);
4240   Update(ptProcessorPhase_Geometry);
4241 }
4242 
CB_LfunDistanceInput(const QVariant Value)4243 void CB_LfunDistanceInput(const QVariant Value) {
4244   Settings->SetValue("LfunDistance", Value);
4245   Update(ptProcessorPhase_Geometry);
4246 }
4247 
CB_LfunScaleInput(const QVariant Value)4248 void CB_LfunScaleInput(const QVariant Value) {
4249   Settings->SetValue("LfunScale", Value);
4250   Update(ptProcessorPhase_Geometry);
4251 }
4252 
CB_LfunAutoScaleCheck(const QVariant State)4253 void CB_LfunAutoScaleCheck(const QVariant State) {
4254   Settings->SetValue("LfunAutoScale",State);
4255   MainWindow->LfunScaleWidget->setEnabled(!State.toBool());
4256   Update(ptProcessorPhase_Geometry);
4257 }
4258 
4259 
4260 // CA and Vignette tab
4261 
CB_LfunCAModelChoice(const QVariant Choice)4262 void CB_LfunCAModelChoice(const QVariant Choice) {
4263   Settings->SetValue("LfunCAModel", Choice);
4264   MainWindow->UpdateLfunCAUI();
4265   Update(ptProcessorPhase_Geometry);
4266 }
4267 
CB_LfunCALinearKrInput(const QVariant Value)4268 void CB_LfunCALinearKrInput(const QVariant Value) {
4269   Settings->SetValue("LfunCALinearKr", Value);
4270   Update(ptProcessorPhase_Geometry);
4271 }
4272 
CB_LfunCALinearKbInput(const QVariant Value)4273 void CB_LfunCALinearKbInput(const QVariant Value) {
4274   Settings->SetValue("LfunCALinearKb", Value);
4275   Update(ptProcessorPhase_Geometry);
4276 }
4277 
CB_LfunCAPoly3VrInput(const QVariant Value)4278 void CB_LfunCAPoly3VrInput(const QVariant Value) {
4279   Settings->SetValue("LfunCAPoly3Vr", Value);
4280   Update(ptProcessorPhase_Geometry);
4281 }
4282 
CB_LfunCAPoly3VbInput(const QVariant Value)4283 void CB_LfunCAPoly3VbInput(const QVariant Value) {
4284   Settings->SetValue("LfunCAPoly3Vb", Value);
4285   Update(ptProcessorPhase_Geometry);
4286 }
4287 
CB_LfunCAPoly3CrInput(const QVariant Value)4288 void CB_LfunCAPoly3CrInput(const QVariant Value) {
4289   Settings->SetValue("LfunCAPoly3Cr", Value);
4290   Update(ptProcessorPhase_Geometry);
4291 }
4292 
CB_LfunCAPoly3CbInput(const QVariant Value)4293 void CB_LfunCAPoly3CbInput(const QVariant Value) {
4294   Settings->SetValue("LfunCAPoly3Cb", Value);
4295   Update(ptProcessorPhase_Geometry);
4296 }
4297 
CB_LfunCAPoly3BrInput(const QVariant Value)4298 void CB_LfunCAPoly3BrInput(const QVariant Value) {
4299   Settings->SetValue("LfunCAPoly3Br", Value);
4300   Update(ptProcessorPhase_Geometry);
4301 }
4302 
CB_LfunCAPoly3BbInput(const QVariant Value)4303 void CB_LfunCAPoly3BbInput(const QVariant Value) {
4304   Settings->SetValue("LfunCAPoly3Bb", Value);
4305   Update(ptProcessorPhase_Geometry);
4306 }
4307 
CB_LfunVignetteModelChoice(const QVariant Choice)4308 void CB_LfunVignetteModelChoice(const QVariant Choice) {
4309   Settings->SetValue("LfunVignetteModel", Choice);
4310   MainWindow->UpdateLfunVignetteUI();
4311   Update(ptProcessorPhase_Geometry);
4312 }
4313 
CB_LfunVignettePoly6K1Input(const QVariant Value)4314 void CB_LfunVignettePoly6K1Input(const QVariant Value) {
4315   Settings->SetValue("LfunVignettePoly6K1", Value);
4316   Update(ptProcessorPhase_Geometry);
4317 }
4318 
CB_LfunVignettePoly6K2Input(const QVariant Value)4319 void CB_LfunVignettePoly6K2Input(const QVariant Value) {
4320   Settings->SetValue("LfunVignettePoly6K2", Value);
4321   Update(ptProcessorPhase_Geometry);
4322 }
4323 
CB_LfunVignettePoly6K3Input(const QVariant Value)4324 void CB_LfunVignettePoly6K3Input(const QVariant Value) {
4325   Settings->SetValue("LfunVignettePoly6K3", Value);
4326   Update(ptProcessorPhase_Geometry);
4327 }
4328 
4329 
4330 // Lens correction tab
4331 
CB_LfunSrcGeoChoice(const QVariant Choice)4332 void CB_LfunSrcGeoChoice(const QVariant Choice) {
4333   Settings->SetValue("LfunSrcGeo", Choice);
4334   Update(ptProcessorPhase_Geometry);
4335 }
4336 
CB_LfunTargetGeoChoice(const QVariant Choice)4337 void CB_LfunTargetGeoChoice(const QVariant Choice) {
4338   Settings->SetValue("LfunTargetGeo", Choice);
4339   Update(ptProcessorPhase_Geometry);
4340 }
4341 
CB_LfunDistModelChoice(const QVariant Choice)4342 void CB_LfunDistModelChoice(const QVariant Choice) {
4343   Settings->SetValue("LfunDistModel", Choice);
4344   MainWindow->UpdateLfunDistUI();
4345   Update(ptProcessorPhase_Geometry);
4346 }
4347 
CB_LfunDistPoly3K1Input(const QVariant Value)4348 void CB_LfunDistPoly3K1Input(const QVariant Value) {
4349   Settings->SetValue("LfunDistPoly3K1", Value);
4350   Update(ptProcessorPhase_Geometry);
4351 }
4352 
CB_LfunDistPoly5K1Input(const QVariant Value)4353 void CB_LfunDistPoly5K1Input(const QVariant Value) {
4354   Settings->SetValue("LfunDistPoly5K1", Value);
4355   Update(ptProcessorPhase_Geometry);
4356 }
4357 
CB_LfunDistPoly5K2Input(const QVariant Value)4358 void CB_LfunDistPoly5K2Input(const QVariant Value) {
4359   Settings->SetValue("LfunDistPoly5K2", Value);
4360   Update(ptProcessorPhase_Geometry);
4361 }
4362 
CB_LfunDistFov1OmegaInput(const QVariant Value)4363 void CB_LfunDistFov1OmegaInput(const QVariant Value) {
4364   Settings->SetValue("LfunDistFov1Omega", Value);
4365   Update(ptProcessorPhase_Geometry);
4366 }
4367 
CB_LfunDistPTLensAInput(const QVariant Value)4368 void CB_LfunDistPTLensAInput(const QVariant Value) {
4369   Settings->SetValue("LfunDistPTLensA", Value);
4370   Update(ptProcessorPhase_Geometry);
4371 }
4372 
CB_LfunDistPTLensBInput(const QVariant Value)4373 void CB_LfunDistPTLensBInput(const QVariant Value) {
4374   Settings->SetValue("LfunDistPTLensB", Value);
4375   Update(ptProcessorPhase_Geometry);
4376 }
4377 
CB_LfunDistPTLensCInput(const QVariant Value)4378 void CB_LfunDistPTLensCInput(const QVariant Value) {
4379   Settings->SetValue("LfunDistPTLensC", Value);
4380   Update(ptProcessorPhase_Geometry);
4381 }
4382 
4383 ////////////////////////////////////////////////////////////////////////////////
4384 //
4385 // Callbacks pertaining to the Geometry Tab
4386 // Partim Defish
4387 //
4388 ////////////////////////////////////////////////////////////////////////////////
4389 
CB_DefishCheck(const QVariant State)4390 void CB_DefishCheck(const QVariant State) {
4391   Settings->SetValue("Defish",State);
4392   Update(ptProcessorPhase_Geometry);
4393 }
4394 
CB_DefishFocalLengthInput(const QVariant Value)4395 void CB_DefishFocalLengthInput(const QVariant Value) {
4396   Settings->SetValue("DefishFocalLength", Value);
4397   if (Settings->GetInt("Defish"))
4398     Update(ptProcessorPhase_Geometry);
4399 }
4400 
CB_DefishScaleInput(const QVariant Value)4401 void CB_DefishScaleInput(const QVariant Value) {
4402   Settings->SetValue("DefishScale", Value);
4403   if (Settings->GetInt("Defish"))
4404     Update(ptProcessorPhase_Geometry);
4405 }
4406 
CB_DefishAutoScaleCheck(const QVariant State)4407 void CB_DefishAutoScaleCheck(const QVariant State) {
4408   Settings->SetValue("DefishAutoScale",State);
4409   MainWindow->DefishScaleWidget->setEnabled(!State.toBool());
4410   Update(ptProcessorPhase_Geometry);
4411 }
4412 
4413 ////////////////////////////////////////////////////////////////////////////////
4414 //
4415 // Callbacks pertaining to the Geometry Tab
4416 // Partim Rotate
4417 //
4418 ////////////////////////////////////////////////////////////////////////////////
4419 
CB_RotateLeftButton()4420 void CB_RotateLeftButton() {
4421   double Value = Settings->GetDouble("Rotate");
4422   Value -= 90.0;
4423   if (Value < -180.0) Value += 360.0;
4424   Settings->SetValue("Rotate",Value);
4425   Update(ptProcessorPhase_Geometry);
4426 }
4427 
CB_RotateRightButton()4428 void CB_RotateRightButton() {
4429   double Value = Settings->GetDouble("Rotate");
4430   Value += 90.0;
4431   if (Value > 180.0) Value -= 360.0;
4432   Settings->SetValue("Rotate",Value);
4433   Update(ptProcessorPhase_Geometry);
4434 }
4435 
CB_RotateAngleButton()4436 void CB_RotateAngleButton() {
4437   if (Settings->GetInt("HaveImage")==0) {
4438     ptMessageBox::information(MainWindow,
4439       QObject::tr("No selection"),
4440       QObject::tr("Open an image first."));
4441     return;
4442   }
4443 
4444   // Rerun the part of geometry stage before rotate to get correct preview
4445   // image in TheProcessor->m_Image_AfterGeometry
4446   TheProcessor->RunGeometry(ptProcessorStopBefore::Rotate);
4447   ViewWindow->SaveZoom();
4448   ViewWindow->ZoomToFit();
4449   UpdatePreviewImage(TheProcessor->m_Image_AfterGeometry); // Calculate in any case.
4450 
4451   // Allow to be selected in the view window. And deactivate main.
4452   ViewWindow->ShowStatus(QObject::tr("Get angle"));
4453   ReportProgress(QObject::tr("Get angle"));
4454 
4455   BlockTools(btmBlockAll);
4456   ViewWindow->StartLine();
4457   ViewWindow->setFocus();
4458 }
4459 
RotateAngleDetermined(const ptStatus ExitStatus,double RotateAngle)4460 void RotateAngleDetermined(const ptStatus ExitStatus, double RotateAngle) {
4461   // Selection is done at this point. Disallow it further and activate main.
4462   BlockTools(btmUnblock);
4463 
4464   if (ExitStatus == stSuccess) {
4465     if (RotateAngle < -45.0) {
4466       RotateAngle += 180.0;
4467     }
4468     if (fabs(fabs(RotateAngle) - 90.0) < 45.0) {
4469       RotateAngle -= 90.0;
4470     }
4471     Settings->SetValue("Rotate",RotateAngle);
4472   }
4473 
4474   ViewWindow->RestoreZoom();
4475   Update(ptProcessorPhase_Geometry);
4476 }
4477 
CB_RotateInput(const QVariant Value)4478 void CB_RotateInput(const QVariant Value) {
4479   Settings->SetValue("Rotate",Value);
4480   Update(ptProcessorPhase_Geometry);
4481 }
4482 
CB_PerspectiveFocalLengthInput(const QVariant Value)4483 void CB_PerspectiveFocalLengthInput(const QVariant Value) {
4484   Settings->SetValue("PerspectiveFocalLength",Value);
4485   Update(ptProcessorPhase_Geometry);
4486 }
4487 
CB_PerspectiveTiltInput(const QVariant Value)4488 void CB_PerspectiveTiltInput(const QVariant Value) {
4489   Settings->SetValue("PerspectiveTilt",Value);
4490   Update(ptProcessorPhase_Geometry);
4491 }
4492 
CB_PerspectiveTurnInput(const QVariant Value)4493 void CB_PerspectiveTurnInput(const QVariant Value) {
4494   Settings->SetValue("PerspectiveTurn",Value);
4495   Update(ptProcessorPhase_Geometry);
4496 }
4497 
CB_PerspectiveScaleXInput(const QVariant Value)4498 void CB_PerspectiveScaleXInput(const QVariant Value) {
4499   Settings->SetValue("PerspectiveScaleX",Value);
4500   Update(ptProcessorPhase_Geometry);
4501 }
4502 
CB_PerspectiveScaleYInput(const QVariant Value)4503 void CB_PerspectiveScaleYInput(const QVariant Value) {
4504   Settings->SetValue("PerspectiveScaleY",Value);
4505   Update(ptProcessorPhase_Geometry);
4506 }
4507 
CB_GridCheck(const QVariant State)4508 void CB_GridCheck(const QVariant State) {
4509   Settings->SetValue("Grid",State);
4510   ViewWindow->setGrid(Settings->GetInt("Grid"), Settings->GetInt("GridX"), Settings->GetInt("GridY"));
4511   Update(ptProcessorPhase_Preview);
4512 }
4513 
CB_GridXInput(const QVariant Value)4514 void CB_GridXInput(const QVariant Value) {
4515   Settings->SetValue("GridX",Value);
4516   if (Settings->GetInt("Grid")) {
4517     ViewWindow->setGrid(Settings->GetInt("Grid"), Settings->GetInt("GridX"), Settings->GetInt("GridY"));
4518     Update(ptProcessorPhase_Preview);
4519   }
4520 }
4521 
CB_GridYInput(const QVariant Value)4522 void CB_GridYInput(const QVariant Value) {
4523   Settings->SetValue("GridY",Value);
4524   if (Settings->GetInt("Grid")) {
4525     ViewWindow->setGrid(Settings->GetInt("Grid"), Settings->GetInt("GridX"), Settings->GetInt("GridY"));
4526     Update(ptProcessorPhase_Preview);
4527   }
4528 }
4529 
CB_FlipModeChoice(const QVariant Value)4530 void CB_FlipModeChoice(const QVariant Value) {
4531   Settings->SetValue("FlipMode",Value);
4532   Update(ptProcessorPhase_Geometry);
4533 }
4534 
CB_GeometryBlockCheck(const QVariant State)4535 void CB_GeometryBlockCheck(const QVariant State) {
4536   Settings->SetValue("GeometryBlock",State);
4537   Update(ptProcessorPhase_RGB);
4538 }
4539 
4540 ////////////////////////////////////////////////////////////////////////////////
4541 //
4542 // Callbacks pertaining to the Geometry Tab
4543 // Partim Crop
4544 //
4545 ////////////////////////////////////////////////////////////////////////////////
4546 
CB_FixedAspectRatioCheck(const QVariant Check)4547 void CB_FixedAspectRatioCheck(const QVariant Check) {
4548   Settings->SetValue("FixedAspectRatio", Check);
4549   MainWindow->UpdateCropToolUI();
4550   if (ViewWindow->interaction() == iaCrop) {
4551     ViewWindow->crop()->setAspectRatio(Settings->GetInt("FixedAspectRatio"),
4552                                        Settings->GetInt("AspectRatioW"),
4553                                        Settings->GetInt("AspectRatioH"));
4554     ViewWindow->setFocus();
4555   }
4556 }
4557 
CB_AspectRatioWChoice(const QVariant Value)4558 void CB_AspectRatioWChoice(const QVariant Value) {
4559   Settings->SetValue("AspectRatioW",Value);
4560   if (ViewWindow->interaction() == iaCrop) {
4561     ViewWindow->crop()->setAspectRatio(Settings->GetInt("FixedAspectRatio"),
4562                                        Settings->GetInt("AspectRatioW"),
4563                                        Settings->GetInt("AspectRatioH"));
4564     ViewWindow->setFocus();
4565   }
4566 }
4567 
CB_AspectRatioHChoice(const QVariant Value)4568 void CB_AspectRatioHChoice(const QVariant Value) {
4569   Settings->SetValue("AspectRatioH",Value);
4570   if (ViewWindow->interaction() == iaCrop) {
4571     ViewWindow->crop()->setAspectRatio(Settings->GetInt("FixedAspectRatio"),
4572                                        Settings->GetInt("AspectRatioW"),
4573                                        Settings->GetInt("AspectRatioH"));
4574     ViewWindow->setFocus();
4575   }
4576 }
4577 
CB_CropExposureInput(const QVariant Value)4578 void CB_CropExposureInput(const QVariant Value) {
4579   Settings->SetValue("CropExposure", Value);
4580 
4581   if (ViewWindow->interaction() == iaCrop) {
4582     if (GBusy) return;
4583     else GBusy = true;
4584     UpdatePreviewImage(TheProcessor->m_Image_AfterGeometry); // Calculate in any case.
4585     GBusy = false;
4586   }
4587 }
4588 
CB_CropOrientationButton()4589 void CB_CropOrientationButton() {
4590   int w = Settings->GetInt("AspectRatioW");
4591   int h = Settings->GetInt("AspectRatioH");
4592 
4593   if (w != h) {
4594     Settings->SetValue("AspectRatioW", h);
4595     Settings->SetValue("AspectRatioH", w);
4596     if (ViewWindow->interaction() == iaCrop) {
4597       ViewWindow->crop()->flipAspectRatio();
4598       ViewWindow->setFocus();
4599     }
4600   }
4601 }
4602 
CB_CropCenterHorButton()4603 void CB_CropCenterHorButton() {
4604   if (ViewWindow->interaction() == iaCrop) {
4605     ViewWindow->crop()->moveToCenter(1, 0);
4606     ViewWindow->setFocus();
4607   }
4608 }
4609 
CB_CropCenterVertButton()4610 void CB_CropCenterVertButton() {
4611   if (ViewWindow->interaction() == iaCrop) {
4612     ViewWindow->crop()->moveToCenter(0, 1);
4613     ViewWindow->setFocus();
4614   }
4615 }
4616 
CB_CropGuidelinesChoice(const QVariant Choice)4617 void CB_CropGuidelinesChoice(const QVariant Choice) {
4618   Settings->SetValue("CropGuidelines",Choice);
4619   if (ViewWindow->interaction() == iaCrop) {
4620     ViewWindow->crop()->setGuidelines(Choice.toInt());
4621     ViewWindow->setFocus();
4622   }
4623 }
4624 
CB_LightsOutChoice(const QVariant Choice)4625 void CB_LightsOutChoice(const QVariant Choice) {
4626   // View window takes care of Settings
4627   if (ViewWindow->interaction() == iaCrop) {
4628     ViewWindow->crop()->setLightsOut(Choice.toInt());
4629     ViewWindow->setFocus();
4630   }
4631 }
4632 
4633 
4634 // Prepare and start image crop interaction
CB_MakeCropButton()4635 void CB_MakeCropButton() {
4636   if (Settings->GetInt("HaveImage")==0) {
4637     ptMessageBox::information(MainWindow,
4638       QObject::tr("No crop possible"),
4639       QObject::tr("Open an image first."));
4640     return;
4641   }
4642 
4643   ViewWindow->ShowStatus(QObject::tr("Prepare"));
4644   ReportProgress(QObject::tr("Prepare for cropping"));
4645 
4646   // Rerun the part of geometry stage before crop to get correct preview
4647   // image in TheProcessor->m_Image_AfterGeometry
4648   TheProcessor->RunGeometry(ptProcessorStopBefore::Crop);
4649   UpdatePreviewImage(TheProcessor->m_Image_AfterGeometry); // Calculate in any case.
4650 
4651   // Allow to be selected in the view window. And deactivate main.
4652   ViewWindow->ShowStatus(QObject::tr("Crop"));
4653   ReportProgress(QObject::tr("Crop"));
4654   BlockTools(btmBlockForCrop);
4655 
4656   switch (Settings->GetInt("CropInitialZoom")) {
4657     case ptZoomLevel_Current:
4658       // nothing to do
4659       break;
4660 
4661     case ptZoomLevel_Fit:
4662       ViewWindow->ZoomToFit(0);
4663       break;
4664 
4665     default:
4666       ViewWindow->ZoomTo((float)Settings->GetInt("CropInitialZoom") / 100);
4667       break;
4668   }
4669 
4670   ViewWindow->StartCrop();          // always start the interaction first,
4671   MainWindow->UpdateCropToolUI();   // *then* update main window
4672   ViewWindow->setFocus();
4673 }
4674 
4675 
4676 // After-crop processing and cleanup.
CleanupAfterCrop(const ptStatus CropStatus,const QRect CropRect)4677 void CleanupAfterCrop(const ptStatus CropStatus, const QRect CropRect) {
4678   BlockTools(btmUnblock);
4679 
4680   if (CropStatus == stSuccess) {
4681     // Account for the pipesize factor.
4682     int XScale = 1<<Settings->GetInt("PipeSize");
4683     int YScale = 1<<Settings->GetInt("PipeSize");
4684 
4685     if ((CropRect.width() * XScale < 4) || (CropRect.height() * YScale < 4)) {
4686       ptMessageBox::information(MainWindow,
4687           QObject::tr("Crop too small"),
4688           QObject::tr("Crop rectangle needs to be at least 4x4 pixels in size.\nNo crop, try again."));
4689 
4690       if ((Settings->GetInt("CropW") < 4) || (Settings->GetInt("CropH") < 4)) {
4691         Settings->SetValue("Crop", 0);
4692         QCheckBox(MainWindow->CropWidget).setCheckState(Qt::Unchecked);
4693       }
4694 
4695       if(Settings->GetInt("RunMode")==1) {
4696         // we're in manual mode!
4697         Update(ptProcessorPhase_Preview);
4698       }
4699     } else {
4700       Settings->SetValue("Crop",1);
4701       Settings->SetValue("CropX",CropRect.left() * XScale);
4702       Settings->SetValue("CropY",CropRect.top() * YScale);
4703       Settings->SetValue("CropW",CropRect.width() * XScale);
4704       Settings->SetValue("CropH",CropRect.height() * YScale);
4705     }
4706 
4707     TRACEKEYVALS("PreviewImageW","%d",PreviewImage->m_Width);
4708     TRACEKEYVALS("PreviewImageH","%d",PreviewImage->m_Height);
4709     TRACEKEYVALS("XScale","%d",XScale);
4710     TRACEKEYVALS("YScale","%d",YScale);
4711     TRACEKEYVALS("CropX","%d",Settings->GetInt("CropX"));
4712     TRACEKEYVALS("CropY","%d",Settings->GetInt("CropY"));
4713     TRACEKEYVALS("CropW","%d",Settings->GetInt("CropW"));
4714     TRACEKEYVALS("CropH","%d",Settings->GetInt("CropH"));
4715 
4716 
4717   // Crop aborted, disable crop checkbox when no previous crop present
4718   } else {
4719     if ((Settings->GetInt("CropW") < 4) || (Settings->GetInt("CropH") < 4)) {
4720       Settings->SetValue("Crop", 0);
4721     }
4722   }
4723 
4724   Update(ptProcessorPhase_Geometry);
4725   MainWindow->UpdateCropToolUI();
4726 }
4727 
4728 
CB_ConfirmCropButton()4729 void CB_ConfirmCropButton() {
4730   ViewWindow->crop()->stop(stSuccess);    // user confirmed crop
4731 }
4732 
CB_CancelCropButton()4733 void CB_CancelCropButton() {
4734   ViewWindow->crop()->stop(stFailure);    // user cancelled crop
4735 }
4736 
4737 
4738 // En/disable an existing crop in the pipe
CB_CropCheck(const QVariant State)4739 void CB_CropCheck(const QVariant State) {
4740   Settings->SetValue("Crop",State);
4741 
4742   if (State.toInt() != 0 &&
4743       (Settings->GetInt("CropW") <= 4 || Settings->GetInt("CropH") <= 4))
4744   {
4745     ptMessageBox::information(MainWindow,
4746         QObject::tr("No previous crop found"),
4747         QObject::tr("Set a crop rectangle now."));
4748 
4749     CB_MakeCropButton();
4750     return;
4751   }
4752 
4753   Update(ptProcessorPhase_Geometry);
4754 }
4755 
4756 
4757 ////////////////////////////////////////////////////////////////////////////////
4758 //
4759 // Callbacks pertaining to the Geometry Tab
4760 // Partim Liquid rescale
4761 //
4762 ////////////////////////////////////////////////////////////////////////////////
4763 
CB_LqrEnergyChoice(const QVariant Choice)4764 void CB_LqrEnergyChoice(const QVariant Choice) {
4765   Settings->SetValue("LqrEnergy",Choice);
4766   Update(ptProcessorPhase_Geometry);
4767 }
4768 
CB_LqrScalingChoice(const QVariant Choice)4769 void CB_LqrScalingChoice(const QVariant Choice) {
4770   Settings->SetValue("LqrScaling",Choice);
4771   MainWindow->UpdateLiquidRescaleUI();
4772   if (Settings->ToolIsActive("TabLiquidRescale"))
4773     Update(ptProcessorPhase_Geometry);
4774 }
4775 
CB_LqrHorScaleInput(const QVariant Value)4776 void CB_LqrHorScaleInput(const QVariant Value) {
4777   Settings->SetValue("LqrHorScale",Value);
4778   if (Settings->ToolIsActive("TabLiquidRescale"))
4779     Update(ptProcessorPhase_Geometry);
4780 }
4781 
CB_LqrVertScaleInput(const QVariant Value)4782 void CB_LqrVertScaleInput(const QVariant Value) {
4783   Settings->SetValue("LqrVertScale",Value);
4784   if (Settings->ToolIsActive("TabLiquidRescale"))
4785     Update(ptProcessorPhase_Geometry);
4786 }
4787 
CB_LqrWidthInput(const QVariant Value)4788 void CB_LqrWidthInput(const QVariant Value) {
4789   Settings->SetValue("LqrWidth",Value);
4790   if (Settings->ToolIsActive("TabLiquidRescale"))
4791     Update(ptProcessorPhase_Geometry);
4792 }
4793 
CB_LqrHeightInput(const QVariant Value)4794 void CB_LqrHeightInput(const QVariant Value) {
4795   Settings->SetValue("LqrHeight",Value);
4796   if (Settings->ToolIsActive("TabLiquidRescale"))
4797     Update(ptProcessorPhase_Geometry);
4798 }
4799 
CB_LqrVertFirstCheck(const QVariant Check)4800 void CB_LqrVertFirstCheck(const QVariant Check) {
4801   Settings->SetValue("LqrVertFirst",Check);
4802   if (Settings->ToolIsActive("TabLiquidRescale"))
4803     Update(ptProcessorPhase_Geometry);
4804 }
4805 
4806 
4807 ////////////////////////////////////////////////////////////////////////////////
4808 //
4809 // Callbacks pertaining to the Geometry Tab
4810 // Partim Resize
4811 //
4812 ////////////////////////////////////////////////////////////////////////////////
4813 
CalculatePipeSizeHelper(const short Size,const bool NewImage)4814 void CalculatePipeSizeHelper(const short Size, const bool NewImage) {
4815   if (NewImage) {
4816     Settings->SetValue("PipeSize",Size);
4817   } else {
4818     CB_PipeSizeChoice(Size);
4819   }
4820 }
4821 
4822 // returns 1 if pipe was updated
CalculatePipeSize(const bool NewImage)4823 int CalculatePipeSize(const bool NewImage /* = False */) {
4824   uint16_t InSize = 0;
4825   if (Settings->GetInt("HaveImage")==0) return 0;
4826   if (Settings->GetInt("Crop")==0) {
4827     InSize = MAX(Settings->GetInt("ImageW"),Settings->GetInt("ImageH"));
4828   } else {
4829     InSize = MAX(Settings->GetInt("CropW"),Settings->GetInt("CropH"));
4830   }
4831   int s = MAX(0,((int)floor(logf((float)InSize*0.9/(float)Settings->GetInt("ResizeScale"))/logf(2))));
4832   if (s < Settings->GetInt("PipeSize")) {
4833     if (Settings->GetInt("RunMode") != 1) {// not manual mode
4834       ImageSaved = 1; // bad hack to check what happens in the next step
4835       CalculatePipeSizeHelper(s, NewImage);
4836       if (ImageSaved == 1 && !NewImage) {
4837         if (Settings->GetInt("PipeSize")==1) {
4838           ptMessageBox::information(NULL,"Failure!","Could not run on full size!\nWill stay on half size instead!");
4839           ImageSaved = 0;
4840           return 0;
4841         } else {
4842           ptMessageBox::information(NULL,"Failure!","Could not run on full size!\nWill run on half size instead!");
4843           CalculatePipeSizeHelper(1, NewImage);
4844         }
4845       }
4846     } else {
4847       CalculatePipeSizeHelper(s, NewImage);
4848     }
4849     return 1;
4850   }
4851   return 0;
4852 }
4853 
CB_ResizeCheck(const QVariant Check)4854 void CB_ResizeCheck(const QVariant Check) {
4855   Settings->SetValue("Resize",Check);
4856   if (Settings->GetInt("AutomaticPipeSize") && Settings->GetInt("Resize")) {
4857     if (!CalculatePipeSize())
4858       Update(ptProcessorPhase_Geometry);
4859   } else {
4860     Update(ptProcessorPhase_Geometry);
4861   }
4862   MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
4863 }
4864 
CB_ResizeDimensionChoice(const QVariant Choice)4865 void CB_ResizeDimensionChoice(const QVariant Choice) {
4866   Settings->SetValue("ResizeDimension",Choice);
4867   if (Settings->GetInt("Resize")) {
4868     if (Settings->GetInt("AutomaticPipeSize")) {
4869       if (!CalculatePipeSize())
4870         Update(ptProcessorPhase_Geometry);
4871     } else {
4872       Update(ptProcessorPhase_Geometry);
4873     }
4874     MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
4875   } else {
4876     MainWindow->UpdateSettings();
4877   }
4878 }
4879 
CB_ResizeScaleInput(const QVariant Value)4880 void CB_ResizeScaleInput(const QVariant Value) {
4881   Settings->SetValue("ResizeScale",Value);
4882   if (Settings->GetInt("Resize")) {
4883     if (Settings->GetInt("AutomaticPipeSize")) {
4884       if (!CalculatePipeSize())
4885         Update(ptProcessorPhase_Geometry);
4886     } else {
4887       Update(ptProcessorPhase_Geometry);
4888     }
4889     MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
4890   }
4891 }
4892 
CB_ResizeHeightInput(const QVariant Value)4893 void CB_ResizeHeightInput(const QVariant Value) {
4894   Settings->SetValue("ResizeHeight",Value);
4895   if (Settings->GetInt("Resize") &&
4896       Settings->GetInt("ResizeDimension") == ptResizeDimension_WidthHeight) {
4897     if (Settings->GetInt("AutomaticPipeSize")) {
4898       if (!CalculatePipeSize())
4899         Update(ptProcessorPhase_Geometry);
4900     } else {
4901       Update(ptProcessorPhase_Geometry);
4902     }
4903     MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
4904   }
4905 }
4906 
CB_ResizeFilterChoice(const QVariant Choice)4907 void CB_ResizeFilterChoice(const QVariant Choice) {
4908   Settings->SetValue("ResizeFilter",Choice);
4909   if (Settings->GetInt("Resize")) {
4910     if (Settings->GetInt("AutomaticPipeSize")) {
4911       if (!CalculatePipeSize())
4912         Update(ptProcessorPhase_Geometry);
4913     } else {
4914       Update(ptProcessorPhase_Geometry);
4915     }
4916     MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
4917   }
4918 }
4919 
CB_AutomaticPipeSizeCheck(const QVariant Check)4920 void CB_AutomaticPipeSizeCheck(const QVariant Check) {
4921   Settings->SetValue("AutomaticPipeSize",Check);
4922   if (Settings->GetInt("Resize")) {
4923     if (Settings->GetInt("AutomaticPipeSize")) {
4924       if (!CalculatePipeSize())
4925         Update(ptProcessorPhase_Geometry);
4926     } else {
4927       Update(ptProcessorPhase_Geometry);
4928     }
4929     MainWindow->UpdateExifInfo(TheProcessor->m_ExifData);
4930   }
4931 }
4932 
4933 ////////////////////////////////////////////////////////////////////////////////
4934 //
4935 // Callbacks pertaining to Out Tab
4936 //
4937 ////////////////////////////////////////////////////////////////////////////////
4938 
CB_SaveFormatChoice(const QVariant Choice)4939 void CB_SaveFormatChoice(const QVariant Choice) {
4940   Settings->SetValue("SaveFormat",Choice);
4941   MainWindow->UpdateSettings();
4942 }
4943 
CB_EraseExifThumbnailCheck(const QVariant State)4944 void CB_EraseExifThumbnailCheck(const QVariant State) {
4945   Settings->SetValue("EraseExifThumbnail",State);
4946   TheProcessor->ReadExifBuffer();
4947 }
4948 
BlockExport(bool Block)4949 inline void BlockExport(bool Block) {
4950   if (!Block) QApplication::processEvents();
4951   MainWindow->ToGimpButton->setEnabled(!Block);
4952   QApplication::processEvents();
4953 }
4954 
BlockSave(bool Block)4955 inline void BlockSave(bool Block) {
4956   if (!Block) QApplication::processEvents();
4957   MainWindow->WritePipeButton->setEnabled(!Block);
4958   QApplication::processEvents();
4959 }
4960 
4961 //==============================================================================
4962 
GetCurrentImageBaseName()4963 QString GetCurrentImageBaseName() {
4964   if (Settings->GetInt("HaveImage")==0) return "";
4965 
4966   QStringList InputFileNameList = Settings->GetStringList("InputFileNameList");
4967   QFileInfo PathInfo(InputFileNameList[0]);
4968   return PathInfo.dir().absolutePath() + QDir::separator() + PathInfo.baseName() +
4969       Settings->GetString("OutputFileNameSuffix") + ".";
4970 }
4971 
4972 //==============================================================================
4973 
SaveOutput(const short mode)4974 void SaveOutput(const short mode) {
4975   BlockSave(true);
4976 
4977   if (mode==ptOutputMode_Full) {
4978     CB_MenuFileSaveOutput();
4979 
4980   } else if (mode==ptOutputMode_Pipe) {
4981     WritePipe();
4982 
4983   } else if (mode==ptOutputMode_Jobfile) {
4984     GFilterDM->WriteJobFile();
4985 
4986   } else if (mode==ptOutputMode_Settingsfile) {
4987     GFilterDM->WritePresetFile(GetCurrentImageBaseName());
4988 
4989   } else if (mode==ptOutputMode_Batch) {
4990     GFilterDM->SendToBatch(GetCurrentImageBaseName());
4991   }
4992 
4993   BlockSave(false);
4994 }
4995 
4996 //==============================================================================
4997 
Export(const short mode)4998 void Export(const short mode) {
4999   BlockExport(true);
5000   if (mode==ptExportMode_GimpPipe && Settings->GetInt("ExportToGimp")) {
5001     GimpExport(1);
5002     BlockExport(false);
5003     return;
5004   } else if (mode==ptExportMode_GimpFull && Settings->GetInt("ExportToGimp")) {
5005     GimpExport(0);
5006     BlockExport(false);
5007     return;
5008   }
5009 
5010   // regular export without plugin
5011   // We generate a temporary name.
5012   QString ImageFileName = QDir::tempPath() + QDir::separator() +
5013                           "ptTemp" + QString::number(QDateTime::currentMSecsSinceEpoch()) + ".tif";
5014 
5015   short Temp = Settings->GetInt("SaveFormat");
5016   Settings->SetValue("SaveFormat", ptSaveFormat_TIFF16);
5017 
5018   if (mode==ptExportMode_GimpPipe && !Settings->GetInt("ExportToGimp")) {
5019     WritePipe(ImageFileName);
5020   } else if (mode==ptExportMode_GimpFull && !Settings->GetInt("ExportToGimp")) {
5021     CB_MenuFileSaveOutput(ImageFileName);
5022   }
5023 
5024   Settings->SetValue("SaveFormat", Temp);
5025 
5026   QString ExportCommand = Settings->GetString("GimpExecCommand");
5027   QStringList ExportArguments;
5028   ExportArguments << ImageFileName;
5029   QProcess* ExportProcess = new QProcess();
5030   ExportProcess->startDetached(ExportCommand,ExportArguments);
5031   BlockExport(false);
5032 }
5033 
CB_WritePipeButton()5034 void CB_WritePipeButton() {
5035   SaveOutput(Settings->GetInt("SaveButtonMode"));
5036 }
5037 
CB_FileMgrUseThumbMaxRowColCheck(const QVariant checked)5038 void CB_FileMgrUseThumbMaxRowColCheck(const QVariant checked) {
5039   Settings->SetValue("FileMgrUseThumbMaxRowCol", checked);
5040   MainWindow->FileMgrThumbMaxRowColWidget->setEnabled(checked.toBool());
5041 }
5042 
5043 
5044 ////////////////////////////////////////////////////////////////////////////////
5045 //
5046 // Callback dispatcher
5047 //
5048 // For refactoring:
5049 // The control switching the active state of the tool needs always to trigger
5050 // a pipe run (also if it just disabled the tool!) The only exception is the
5051 // external blocked state (blocked or hidden tools!).
5052 //
5053 ////////////////////////////////////////////////////////////////////////////////
5054 
5055 // For simple switches, just get the value to the settings
Standard_CB_JustSet(const QString ObjectName,const QVariant Value)5056 void Standard_CB_JustSet (const QString ObjectName, const QVariant Value) {
5057   QString Temp = ObjectName;
5058   if (Temp.endsWith("Input") || Temp.endsWith("Check")) Temp.chop(5);
5059   if (Temp.endsWith("Choice")) Temp.chop(6);
5060   Settings->SetValue(Temp,Value);
5061 }
5062 
5063 // Standard form of call backs, value to settings and pipe run if needed
Standard_CB_SetAndRun(const QString ObjectName,const QVariant Value)5064 void Standard_CB_SetAndRun (const QString ObjectName, const QVariant Value) {
5065   QString Key = ObjectName;
5066   if (Key.endsWith("Input") || Key.endsWith("Check")) Key.chop(5);
5067   if (Key.endsWith("Choice")) Key.chop(6);
5068 
5069   QWidget* CurrentControl = Settings->GetGuiWidget(Key);
5070   if (CurrentControl == NULL) assert(!"Widget not found");
5071   ptGroupBox* CurrentTool = dynamic_cast<ptGroupBox*>(CurrentControl);
5072 
5073   while (CurrentTool == NULL) {
5074     CurrentControl = CurrentControl->parentWidget();
5075     CurrentTool = dynamic_cast<ptGroupBox*>(CurrentControl);
5076   }
5077   QString ToolName = CurrentTool->objectName();
5078 
5079   // Save previous state for rerun when disabling a filter
5080   short PreviousActiveState = Settings->ToolIsActive(ToolName);
5081 
5082   Settings->SetValue(Key,Value);
5083 
5084   short NewActiveState = Settings->ToolIsActive(ToolName);
5085   CurrentTool->SetActive(NewActiveState);
5086 
5087   if (NewActiveState || PreviousActiveState) {
5088     Update(ToolName);
5089   } else {
5090     MainWindow->UpdateSettings();
5091   }
5092 }
5093 
CB_InputChanged(const QString ObjectName,const QVariant Value)5094 void CB_InputChanged(const QString ObjectName, const QVariant Value) {
5095   // No CB processing while in startup phase. Too much
5096   // noise events otherwise.
5097   if (InStartup) return;
5098 
5099   if (ObjectName != "ZoomInput" &&
5100       ObjectName != "PipeSizeChoice" &&
5101       ObjectName != "RunModeCheck" &&
5102       ObjectName != "SpecialPreviewChoice" &&
5103       ObjectName != "UseThumbnailCheck")
5104   {
5105     ptAddUndo();
5106   }
5107 
5108   if (ObjectName == "ZoomInput") {
5109     CB_ZoomInput(Value);
5110 
5111   #define M_Dispatch(Name)\
5112   } else if (ObjectName == #Name) { CB_ ## Name (Value);
5113 
5114   #define M_JustSetDispatch(Name)\
5115   } else if (ObjectName == #Name) { Standard_CB_JustSet(#Name,Value);
5116 
5117   #define M_SetAndRunDispatch(Name)\
5118   } else if (ObjectName == #Name) { Standard_CB_SetAndRun(#Name,Value);
5119 
5120   M_Dispatch(CameraColorChoice)
5121   M_Dispatch(CameraColorProfileIntentChoice)
5122   M_Dispatch(CameraColorGammaChoice)
5123 
5124   M_Dispatch(WorkColorChoice)
5125   M_Dispatch(CMQualityChoice)
5126 
5127   M_Dispatch(PreviewColorProfileIntentChoice)
5128 
5129   M_Dispatch(StyleChoice)
5130   M_Dispatch(StyleHighLightChoice)
5131 
5132   M_Dispatch(SaveConfirmationCheck)
5133   M_Dispatch(AutosaveSettingsCheck)
5134   M_Dispatch(ResetSettingsConfirmationCheck)
5135   M_Dispatch(FullPipeConfirmationCheck)
5136 
5137   M_Dispatch(WriteBackupSettingsCheck)
5138 
5139   M_JustSetDispatch(FileMgrThumbnailSizeInput)
5140   M_JustSetDispatch(FileMgrThumbnailPaddingInput)
5141   M_Dispatch(FileMgrUseThumbMaxRowColCheck)
5142   M_JustSetDispatch(FileMgrThumbMaxRowColInput)
5143   M_JustSetDispatch(FileMgrThumbSaveSizeInput)
5144   M_JustSetDispatch(FileMgrStartupOpenCheck)
5145   M_JustSetDispatch(FileMgrThumbCacheSizeInput)
5146 
5147   M_JustSetDispatch(BatchMgrAutosaveCheck)
5148   M_JustSetDispatch(BatchMgrAutosaveFileChoice)
5149   M_JustSetDispatch(BatchMgrAutoloadCheck)
5150 
5151   M_Dispatch(MemoryTestInput)
5152 
5153   M_Dispatch(ExportToGimpCheck)
5154 
5155   M_Dispatch(StartupSettingsCheck)
5156   M_Dispatch(StartupSettingsResetCheck)
5157   M_Dispatch(StartupUIModeChoice)
5158   M_Dispatch(StartupPipeSizeChoice)
5159   M_JustSetDispatch(EscToExitCheck)
5160   M_JustSetDispatch(LoadTagsCheck)
5161 
5162   M_JustSetDispatch(StartupSwitchARCheck)
5163 
5164   M_Dispatch(CropInitialZoomChoice)
5165 
5166   M_Dispatch(RememberSettingLevelChoice)
5167   M_Dispatch(InputsAddPowerLawCheck)
5168   M_Dispatch(ToolBoxModeCheck)
5169   M_Dispatch(TabStatusIndicatorInput)
5170   M_Dispatch(PreviewTabModeCheck)
5171   M_Dispatch(BackgroundColorCheck)
5172   M_Dispatch(SliderWidthInput)
5173   M_Dispatch(SaveButtonModeChoice)
5174   M_Dispatch(ResetButtonModeChoice)
5175   M_Dispatch(SearchBarEnableCheck)
5176 
5177   M_Dispatch(PipeSizeChoice)
5178   M_Dispatch(RunModeCheck)
5179   M_Dispatch(SpecialPreviewChoice)
5180 
5181   M_Dispatch(UseThumbnailCheck)
5182 
5183   M_Dispatch(BadPixelsChoice)
5184   M_Dispatch(DarkFrameChoice)
5185 
5186   M_Dispatch(WhiteBalanceChoice)
5187   M_Dispatch(ColorTemperatureInput)
5188   M_Dispatch(GreenIntensityInput)
5189   M_Dispatch(MultiplierEnhanceCheck)
5190   M_Dispatch(RMultiplierInput)
5191   M_Dispatch(GMultiplierInput)
5192   M_Dispatch(BMultiplierInput)
5193   M_Dispatch(ManualBlackPointCheck)
5194   M_Dispatch(BlackPointInput)
5195   M_Dispatch(ManualWhitePointCheck)
5196   M_Dispatch(WhitePointInput)
5197   M_Dispatch(CaCorrectChoice)
5198   M_Dispatch(CaRedInput)
5199   M_Dispatch(CaBlueInput)
5200   M_Dispatch(GreenEquilInput)
5201   M_Dispatch(CfaLineDenoiseInput)
5202   M_Dispatch(AdjustMaximumThresholdInput)
5203   M_Dispatch(RawDenoiseThresholdInput)
5204   M_Dispatch(HotpixelReductionInput)
5205   M_Dispatch(BayerDenoiseChoice)
5206   M_Dispatch(InterpolationChoice)
5207   M_Dispatch(InterpolationPassesInput)
5208   M_Dispatch(MedianPassesInput)
5209   M_Dispatch(ESMedianPassesInput)
5210   M_Dispatch(EeciRefineCheck)
5211   M_Dispatch(ClipModeChoice)
5212   M_Dispatch(ClipParameterInput)
5213 
5214   M_Dispatch(LfunFocalInput)
5215   M_Dispatch(LfunApertureInput)
5216   M_Dispatch(LfunDistanceInput)
5217   M_Dispatch(LfunScaleInput)
5218   M_Dispatch(LfunAutoScaleCheck)
5219   M_Dispatch(LfunCAModelChoice)
5220   M_Dispatch(LfunCALinearKbInput)
5221   M_Dispatch(LfunCALinearKrInput)
5222   M_Dispatch(LfunCAPoly3VrInput)
5223   M_Dispatch(LfunCAPoly3VbInput)
5224   M_Dispatch(LfunCAPoly3CrInput)
5225   M_Dispatch(LfunCAPoly3CbInput)
5226   M_Dispatch(LfunCAPoly3BrInput)
5227   M_Dispatch(LfunCAPoly3BbInput)
5228   M_Dispatch(LfunVignetteModelChoice)
5229   M_Dispatch(LfunVignettePoly6K1Input)
5230   M_Dispatch(LfunVignettePoly6K2Input)
5231   M_Dispatch(LfunVignettePoly6K3Input)
5232   M_Dispatch(LfunSrcGeoChoice)
5233   M_Dispatch(LfunTargetGeoChoice)
5234   M_Dispatch(LfunDistModelChoice)
5235   M_Dispatch(LfunDistPoly3K1Input)
5236   M_Dispatch(LfunDistPoly5K1Input)
5237   M_Dispatch(LfunDistPoly5K2Input)
5238 #if LF_VERSION < (3 << 16)
5239   M_Dispatch(LfunDistFov1OmegaInput)
5240 #endif
5241   M_Dispatch(LfunDistPTLensAInput)
5242   M_Dispatch(LfunDistPTLensBInput)
5243   M_Dispatch(LfunDistPTLensCInput)
5244 
5245   M_Dispatch(DefishCheck)
5246   M_Dispatch(DefishFocalLengthInput)
5247   M_Dispatch(DefishScaleInput)
5248   M_Dispatch(DefishAutoScaleCheck)
5249 
5250   M_Dispatch(RotateInput)
5251   M_Dispatch(PerspectiveFocalLengthInput)
5252   M_Dispatch(PerspectiveTiltInput)
5253   M_Dispatch(PerspectiveTurnInput)
5254   M_Dispatch(PerspectiveScaleXInput)
5255   M_Dispatch(PerspectiveScaleYInput)
5256   M_Dispatch(GridCheck)
5257   M_Dispatch(GridXInput)
5258   M_Dispatch(GridYInput)
5259 
5260   M_Dispatch(CropCheck)
5261   M_Dispatch(CropGuidelinesChoice)
5262   M_Dispatch(LightsOutChoice)
5263   M_Dispatch(FixedAspectRatioCheck)
5264   M_Dispatch(AspectRatioWChoice)
5265   M_Dispatch(AspectRatioHChoice)
5266   M_Dispatch(CropExposureInput)
5267 
5268   M_Dispatch(LqrEnergyChoice)
5269   M_Dispatch(LqrScalingChoice)
5270   M_Dispatch(LqrHorScaleInput)
5271   M_Dispatch(LqrVertScaleInput)
5272   M_Dispatch(LqrWidthInput)
5273   M_Dispatch(LqrHeightInput)
5274   M_Dispatch(LqrVertFirstCheck)
5275 
5276   M_Dispatch(ResizeCheck)
5277   M_Dispatch(ResizeDimensionChoice)
5278   M_Dispatch(ResizeScaleInput)
5279   M_Dispatch(ResizeHeightInput)
5280   M_Dispatch(ResizeFilterChoice)
5281   M_Dispatch(AutomaticPipeSizeCheck)
5282 
5283   M_Dispatch(FlipModeChoice)
5284 
5285   M_Dispatch(GeometryBlockCheck)
5286 
5287   M_SetAndRunDispatch(OutputGammaCompensationCheck)
5288   M_SetAndRunDispatch(OutputGammaInput)
5289   M_SetAndRunDispatch(OutputLinearityInput)
5290 
5291   M_SetAndRunDispatch(WebResizeChoice)
5292   M_SetAndRunDispatch(WebResizeDimensionChoice)
5293   M_SetAndRunDispatch(WebResizeBeforeGammaCheck)
5294   M_SetAndRunDispatch(WebResizeScaleInput)
5295   M_SetAndRunDispatch(WebResizeFilterChoice)
5296 
5297   M_Dispatch(OutputColorProfileIntentChoice)
5298 
5299   M_JustSetDispatch(SaveQualityInput)
5300   M_JustSetDispatch(SaveResolutionInput)
5301   M_Dispatch(SaveFormatChoice)
5302   M_JustSetDispatch(SaveSamplingChoice)
5303   M_JustSetDispatch(IncludeExifCheck)
5304   M_Dispatch(EraseExifThumbnailCheck)
5305   M_JustSetDispatch(ImageRatingInput)
5306 
5307   } else {
5308     fprintf(stderr,"(%s,%d) Unexpected ObjectName '%s'\n",
5309             __FILE__,__LINE__,ObjectName.toLocal8Bit().data());
5310     assert(0);
5311   }
5312 }
5313 
5314 //==============================================================================
5315 
5316 /*!
5317  * Reads Sidecar file
5318  * Places data into \var IptcData and \var XmpData
5319  */
ReadSidecar(const QString & Sidecar)5320 void ReadSidecar(const QString& Sidecar)
5321 {
5322   if (Sidecar.size() == 0) return;
5323 
5324   if (Exiv2::ImageFactory::getType(Sidecar.toLocal8Bit().data()) == Exiv2::ImageType::none) {
5325     return;
5326   }
5327 
5328   Exiv2::Image::AutoPtr hImage = Exiv2::ImageFactory::open(Sidecar.toLocal8Bit().data());
5329 
5330   if (!hImage.get()) {
5331     return;
5332   }
5333   hImage->readMetadata();
5334   IptcData = hImage->iptcData();
5335   XmpData = hImage->xmpData();
5336 }
5337 
5338 //==============================================================================
5339 
5340 /*!
5341  * Sets ImageRating value, which is taken from Xmp.xmp.Rating
5342  * Places data into IptcData and XmpData
5343  */
SetRatingFromXmp()5344 void SetRatingFromXmp()
5345 {
5346   Exiv2::XmpData::const_iterator Pos;
5347   if ((Pos = XmpData.findKey(Exiv2::XmpKey("Xmp.xmp.Rating"))) != XmpData.end()) {
5348     std::stringstream str;
5349     str << *Pos;
5350     int Rating;
5351     sscanf(str.str().c_str(),"%d",&Rating);
5352     Settings->SetValue("ImageRating", Rating);
5353   }
5354 }
5355 
5356 //==============================================================================
5357 
5358 /*!
5359  * Sets Tags value, which is taken from Xmp.digiKam.TagsList
5360  * Places data into IptcData and XmpData
5361  */
SetTagsFromXmp()5362 void SetTagsFromXmp()
5363 {
5364   Exiv2::XmpData::const_iterator Pos;
5365   if ((Pos = XmpData.findKey(Exiv2::XmpKey("Xmp.digiKam.TagsList"))) != XmpData.end()) {
5366     std::stringstream str;
5367     str << *Pos;
5368     QString tags = str.str().c_str();
5369     MainWindow->TagsEditWidget->setPlainText(tags);
5370   }
5371 }
5372 
5373 //==============================================================================
5374 
5375 /*! Returns the type of an image file.
5376   \param filename
5377     path/filename of the image. An empty string is interpreted as the current global
5378     input file, i.e. InputFileNameList[0]. Note that \c CheckImageType never changes
5379     the value of InputFileNameList[0].
5380   \param width
5381     A pointer to a variable that holds the width of the image. Pass NULL if you
5382     do not need to know the width. If the width of the file cannot be determined,
5383     \c CheckImageType sets this variable to \c 0.
5384   \param height
5385     Same as \c width, but for the image height.
5386   \param dcRaw
5387     An optional pointer to an existing and properly initialized ptDcRaw object that the
5388     function should use. Note that the file associated with that dcraw gets changed to
5389     \c filename.
5390 */
CheckImageType(QString filename,uint16_t * width,uint16_t * height,ptDcRaw * dcRaw)5391 ptImageType CheckImageType(QString filename,
5392                            uint16_t* width, uint16_t* height,
5393                            ptDcRaw* dcRaw /*= NULL*/)
5394 {
5395   ptImageType result = itUndetermined;
5396   ptDcRaw* LocalDcRaw = NULL;
5397   bool UseLocalDcRaw = dcRaw == NULL;
5398 
5399   // Setup dcraw
5400   if (UseLocalDcRaw) {
5401     LocalDcRaw = new ptDcRaw;
5402     Settings->ToDcRaw(LocalDcRaw);
5403   } else {
5404     LocalDcRaw = dcRaw;
5405   }
5406 
5407   // Setup file name
5408   QStringList InputFileNameList = Settings->GetStringList("InputFileNameList");
5409   if (filename.isEmpty())
5410     filename = InputFileNameList[0];
5411 
5412   if (filename != InputFileNameList[0]) {
5413     FREE(LocalDcRaw->m_UserSetting_InputFileName);
5414     LocalDcRaw->m_UserSetting_InputFileName =
5415       (char*) MALLOC(1+strlen(filename.toLocal8Bit().data()));
5416     ptMemoryError(LocalDcRaw->m_UserSetting_InputFileName,__FILE__,__LINE__);
5417     strcpy(LocalDcRaw->m_UserSetting_InputFileName,filename.toLocal8Bit().data());
5418   }
5419 
5420   if (LocalDcRaw->Identify() == 0) {
5421     // we have a raw file
5422     result = itRaw;
5423     if (Settings->GetInt("UseThumbnail") == 0) {
5424       if (width != NULL)  *width  = LocalDcRaw->m_Width;
5425       if (height != NULL) *height = LocalDcRaw->m_Height;
5426     } else {
5427       if (width != NULL)  *width  = LocalDcRaw->m_ThumbWidth;
5428       if (height != NULL) *height = LocalDcRaw->m_ThumbHeight;
5429     }
5430 
5431   } else {
5432     // Not a raw image. We use GraphicsMagick to check for valid Bitmaps.
5433     MagickWand* image = NewMagickWand();
5434     MagickPingImage(image, filename.toLocal8Bit().data());
5435 
5436     ExceptionType MagickExcept;
5437     const char* MagickErrorMsg = MagickGetException(image, &MagickExcept);
5438 
5439     if (MagickExcept == UndefinedException) {
5440       // image could be pinged without problems: we have a bitmap
5441       result = itBitmap;
5442       if (width != NULL) *width = MagickGetImageWidth(image);
5443       if (height != NULL) *height = MagickGetImageHeight(image);
5444 
5445     } else {
5446       // not a supported image format
5447       printf("%s", MagickErrorMsg);
5448       result = itNotSupported;
5449       if (width != NULL) *width = 0;
5450       if (height != NULL) *height = 0;
5451     }
5452 
5453     DestroyMagickWand(image);
5454   }
5455 
5456   if (UseLocalDcRaw)
5457     DelAndNull(LocalDcRaw);
5458 
5459   return result;
5460 }
5461 
5462 //==============================================================================
5463 QList<QByteArray> ptUndoBuffer;
5464 QList<QByteArray> ptRedoBuffer;
5465 QByteArray ptClipboard;
5466 
5467 ////////////////////////////////////////////////////////////////////////////////
5468 //
5469 // ptSettingsToQByteArray
5470 //
5471 // Copies Settings to a byte array
5472 //
5473 ////////////////////////////////////////////////////////////////////////////////
5474 
ptSettingsToQByteArray()5475 QByteArray ptSettingsToQByteArray() {
5476   ptTempFile* tempFile = new ptTempFile();
5477   GFilterDM->WritePresetFile(tempFile->fileName());
5478   QFile file(tempFile->fileName());
5479   file.open(QIODevice::ReadOnly);
5480   QByteArray arr = file.readAll();
5481   file.close();
5482   delete tempFile;
5483   return arr;
5484 }
5485 
5486 
5487 ////////////////////////////////////////////////////////////////////////////////
5488 //
5489 // ptQByteArrayToSettings
5490 //
5491 // Loads Settings from a byte array
5492 //
5493 ////////////////////////////////////////////////////////////////////////////////
5494 
ptQByteArrayToSettings(const QByteArray & arr)5495 void ptQByteArrayToSettings(const QByteArray &arr) {
5496   ptTempFile* tempFile = new ptTempFile();
5497   QFile file(tempFile->fileName());
5498   file.open(QIODevice::WriteOnly);
5499   file.write(arr);
5500   file.close();
5501   CB_OpenSettingsFile(tempFile->fileName());
5502   delete tempFile;
5503 }
5504 
5505 
5506 ////////////////////////////////////////////////////////////////////////////////
5507 //
5508 // ptAddUndo
5509 //
5510 // Adds current Settings to undo buffer
5511 //
5512 ////////////////////////////////////////////////////////////////////////////////
5513 
ptAddUndo()5514 void ptAddUndo() {
5515   QByteArray arr = ptSettingsToQByteArray();
5516   ptUndoBuffer << arr;
5517   ptRedoBuffer.clear();
5518 }
5519 
5520 ////////////////////////////////////////////////////////////////////////////////
5521 //
5522 // ptMakeUndo
5523 //
5524 // Loads Settings from undo buffer
5525 //
5526 ////////////////////////////////////////////////////////////////////////////////
5527 
ptMakeUndo()5528 void ptMakeUndo() {
5529   if (ptUndoBuffer.isEmpty())
5530     return;
5531 
5532   QByteArray arr = ptSettingsToQByteArray();
5533   ptRedoBuffer << arr;
5534   arr = ptUndoBuffer.last();
5535   ptUndoBuffer.removeLast();
5536 
5537   ptQByteArrayToSettings(arr);
5538 }
5539 
5540 ////////////////////////////////////////////////////////////////////////////////
5541 //
5542 // ptMakeRedo
5543 //
5544 // Loads Settings from redo buffer
5545 //
5546 ////////////////////////////////////////////////////////////////////////////////
5547 
ptMakeRedo()5548 void ptMakeRedo() {
5549   if (ptRedoBuffer.isEmpty())
5550     return;
5551 
5552   QByteArray arr = ptSettingsToQByteArray();
5553   ptUndoBuffer << arr;
5554   arr = ptRedoBuffer.last();
5555   ptRedoBuffer.removeLast();
5556 
5557   ptQByteArrayToSettings(arr);
5558 }
5559 
5560 ////////////////////////////////////////////////////////////////////////////////
5561 //
5562 // ptClearUndoRedo
5563 //
5564 // Clears undo-redo buffers
5565 //
5566 ////////////////////////////////////////////////////////////////////////////////
5567 
ptClearUndoRedo()5568 void ptClearUndoRedo() {
5569   ptUndoBuffer.clear();
5570   ptRedoBuffer.clear();
5571 }
5572 
5573 ////////////////////////////////////////////////////////////////////////////////
5574 //
5575 // ptMakeFullUndo
5576 //
5577 // Loads Settings from the first slot of undobuffer
5578 //
5579 ////////////////////////////////////////////////////////////////////////////////
5580 
ptMakeFullUndo()5581 void ptMakeFullUndo() {
5582   if (ptUndoBuffer.isEmpty())
5583     return;
5584 
5585   QByteArray arr = ptUndoBuffer.first();
5586   ptQByteArrayToSettings(arr);
5587   ptClearUndoRedo();
5588 }
5589 
5590 ////////////////////////////////////////////////////////////////////////////////
5591 //
5592 // ptResetSettingsToDefault
5593 //
5594 // Loads initial Settings
5595 //
5596 ////////////////////////////////////////////////////////////////////////////////
5597 
ptResetSettingsToDefault()5598 void ptResetSettingsToDefault() {
5599   ptAddUndo();
5600   CB_OpenSettingsFile(Settings->GetString("StartupSettingsFile"));
5601 }
5602 
5603 ////////////////////////////////////////////////////////////////////////////////
5604 //
5605 // ptCopySettingsToClipboard
5606 //
5607 // Copies Settings to a "clipboard"
5608 //
5609 ////////////////////////////////////////////////////////////////////////////////
5610 
ptCopySettingsToClipboard()5611 void ptCopySettingsToClipboard() {
5612   ptClipboard = ptSettingsToQByteArray();
5613 }
5614 
5615 ////////////////////////////////////////////////////////////////////////////////
5616 //
5617 // ptPasteSettingsFromClipboard
5618 //
5619 // Pastes Settings from a "clipboard"
5620 //
5621 ////////////////////////////////////////////////////////////////////////////////
5622 
ptPasteSettingsFromClipboard()5623 void ptPasteSettingsFromClipboard() {
5624   if (ptClipboard.isEmpty())
5625     return;
5626 
5627   ptAddUndo();
5628   ptQByteArrayToSettings(ptClipboard);
5629 }
5630