1 /*
2 *  This file is part of RawTherapee.
3 *
4 *  Copyright (c) 2012 Oliver Duis <oduis@oliverduis.de>
5 *
6 *  RawTherapee is free software: you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation, either version 3 of the License, or
9 *  (at your option) any later version.
10 *
11 *  RawTherapee is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with RawTherapee.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <glibmm.h>
20 #include <iostream>
21 #include "lensprofile.h"
22 #include "guiutils.h"
23 #include "../rtengine/lcp.h"
24 #include <sstream>
25 #include "rtimage.h"
26 #include "../rtengine/rtlensfun.h"
27 #include <map>
28 #include <set>
29 #include "../rtengine/lensexif.h"
30 #include "eventmapper.h"
31 #ifdef EXIF
32 #  undef EXIF
33 #endif
34 
35 using namespace rtengine;
36 using namespace rtengine::procparams;
37 
LensProfilePanel()38 LensProfilePanel::LensProfilePanel() :
39     FoldableToolPanel(this, "lensprof", M("TP_LENSPROFILE_LABEL"), false, true, true),
40     lcModeChanged(false),
41     lcpFileChanged(false),
42     useDistChanged(false),
43     useVignChanged(false),
44     useCAChanged(false),
45     useLensfunChanged(false),
46     lensfunAutoChanged(false),
47     lensfunCameraChanged(false),
48     lensfunLensChanged(false),
49     allowFocusDep(true),
50     isRaw(true),
51     metadata(nullptr),
52     modesGrid(Gtk::manage(new Gtk::Grid())),
53     distGrid(Gtk::manage((new Gtk::Grid()))),
54     corrExif(Gtk::manage((new Gtk::RadioButton(corrGroup, M("TP_LENSPROFILE_CORRECTION_EXIF"))))),
55     corrLensfunAutoRB(Gtk::manage((new Gtk::RadioButton(corrGroup, M("TP_LENSPROFILE_CORRECTION_AUTOMATCH"))))),
56     corrLensfunManualRB(Gtk::manage((new Gtk::RadioButton(corrGroup, M("TP_LENSPROFILE_CORRECTION_MANUAL"))))),
57     corrLcpFileRB(Gtk::manage((new Gtk::RadioButton(corrGroup, M("TP_LENSPROFILE_CORRECTION_LCPFILE"))))),
58     corrLcpFileChooser(Gtk::manage((new MyFileChooserButton(M("TP_LENSPROFILE_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)))),
59     lensfunCamerasLbl(Gtk::manage((new Gtk::Label(M("EXIFFILTER_CAMERA"))))),
60     lensfunCameras(Gtk::manage((new MyComboBox()))),
61     lensfunLensesLbl(Gtk::manage((new Gtk::Label(M("EXIFFILTER_LENS"))))),
62     lensfunLenses(Gtk::manage((new MyComboBox()))),
63     warning(Gtk::manage(new RTImage("warning.png"))),
64     ckbUseDist(Gtk::manage((new Gtk::CheckButton(M("TP_LENSPROFILE_USE_GEOMETRIC"))))),
65     ckbUseVign(Gtk::manage((new Gtk::CheckButton(M("TP_LENSPROFILE_USE_VIGNETTING"))))),
66     ckbUseCA(Gtk::manage((new Gtk::CheckButton(M("TP_LENSPROFILE_USE_CA")))))
67 {
68     EvToolEnabled.set_action(DARKFRAME); // might need to redo vignetting
69     EvToolReset.set_action(DARKFRAME);
70 
71     if (!lf) {
72         lf = new LFDbHelper();
73     }
74 
75     // Main containers:
76 
77     Gtk::Frame *nodesFrame = Gtk::manage(new Gtk::Frame(M("TP_LENSPROFILE_MODE_HEADER")));
78 
79     modesGrid->get_style_context()->add_class("grid-spacing");
80     setExpandAlignProperties(modesGrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
81 
82     Gtk::Frame *distFrame = Gtk::manage(new Gtk::Frame(M("TP_LENSPROFILE_USE_HEADER")));
83 
84     distGrid->get_style_context()->add_class("grid-spacing");
85     setExpandAlignProperties(distGrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
86 
87     // Mode choice widgets:
88 
89     setExpandAlignProperties(corrLcpFileChooser, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
90 
91     // Manually-selected profile widgets:
92 
93     setExpandAlignProperties(lensfunCamerasLbl, false, false, Gtk::ALIGN_END, Gtk::ALIGN_CENTER);
94 
95     lensfunCameras->set_model(lf->lensfunCameraModel);
96     lensfunCameras->pack_start(lf->lensfunModelCam.model);
97     lensfunCameras->setPreferredWidth(50, 120);
98     setExpandAlignProperties(lensfunCameras, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
99 
100     Gtk::CellRendererText* const camerasCellRenderer = static_cast<Gtk::CellRendererText*>(lensfunCameras->get_first_cell());
101     camerasCellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE;
102     camerasCellRenderer->property_ellipsize_set() = true;
103 
104     setExpandAlignProperties(lensfunLensesLbl, false, false, Gtk::ALIGN_END, Gtk::ALIGN_CENTER);
105 
106     lensfunLenses->set_model(lf->lensfunLensModel);
107     lensfunLenses->pack_start(lf->lensfunModelLens.prettylens);
108     lensfunLenses->setPreferredWidth(50, 120);
109     setExpandAlignProperties(lensfunLenses, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
110 
111     Gtk::CellRendererText* const lensesCellRenderer = static_cast<Gtk::CellRendererText*>(lensfunLenses->get_first_cell());
112     lensesCellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE;
113     lensesCellRenderer->property_ellipsize_set() = true;
114 
115     warning->set_tooltip_text(M("TP_LENSPROFILE_LENS_WARNING"));
116     warning->hide();
117 
118     // LCP file filter config:
119 
120     const Glib::RefPtr<Gtk::FileFilter> filterLCP = Gtk::FileFilter::create();
121     filterLCP->set_name(M("FILECHOOSER_FILTER_LCP"));
122     filterLCP->add_pattern("*.lcp");
123     filterLCP->add_pattern("*.LCP");
124     corrLcpFileChooser->add_filter(filterLCP);
125 
126     const Glib::ustring defDir = LCPStore::getInstance()->getDefaultCommonDirectory();
127 
128     if (!defDir.empty()) {
129 #ifdef WIN32
130         corrLcpFileChooser->set_show_hidden(true);  // ProgramData is hidden on Windows
131 #endif
132         corrLcpFileChooser->set_current_folder(defDir);
133     } else if (!options.lastLensProfileDir.empty()) {
134         corrLcpFileChooser->set_current_folder(options.lastLensProfileDir);
135     }
136 
137     bindCurrentFolder(*corrLcpFileChooser, options.lastLensProfileDir);
138 
139     // Choice of properties to correct, applicable to all modes:
140 
141     // Populate modes grid:
142 
143     modesGrid->attach(*corrExif, 0, 0, 3, 1);
144     modesGrid->attach(*corrLensfunAutoRB, 0, 1, 3, 1);
145     modesGrid->attach(*corrLensfunManualRB, 0, 2, 3, 1);
146 
147     modesGrid->attach(*lensfunCamerasLbl, 0, 3, 1, 1);
148     modesGrid->attach(*lensfunCameras, 1, 3, 1, 1);
149     modesGrid->attach(*lensfunLensesLbl, 0, 4, 1, 1);
150     modesGrid->attach(*lensfunLenses, 1, 4, 1, 1);
151     modesGrid->attach(*warning, 2, 3, 1, 2);
152 
153     modesGrid->attach(*corrLcpFileRB, 0, 5, 1, 1);
154     modesGrid->attach(*corrLcpFileChooser, 1, 5, 1, 1);
155 
156 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 20
157     modesGrid->set_row_spacing(2);
158     modesGrid->set_column_spacing(4);
159 #endif
160 
161     // Populate distortions grid:
162 
163     distGrid->attach(*ckbUseDist, 0, 0, 1, 1);
164     distGrid->attach(*ckbUseVign, 0, 1, 1, 1);
165     distGrid->attach(*ckbUseCA, 0, 2, 1, 1);
166 
167     // Attach grids:
168     nodesFrame->add(*modesGrid);
169     distFrame->add(*distGrid);
170 
171     pack_start(*nodesFrame, Gtk::PACK_EXPAND_WIDGET);
172     pack_start(*distFrame, Gtk::PACK_EXPAND_WIDGET);
173 
174     // Signals:
175 
176     conLCPFile = corrLcpFileChooser->signal_file_set().connect(sigc::mem_fun(*this, &LensProfilePanel::onLCPFileChanged));
177     conUseDist = ckbUseDist->signal_toggled().connect(sigc::mem_fun(*this, &LensProfilePanel::onUseDistChanged));
178     ckbUseVign->signal_toggled().connect(sigc::mem_fun(*this, &LensProfilePanel::onUseVignChanged));
179     ckbUseCA->signal_toggled().connect(sigc::mem_fun(*this, &LensProfilePanel::onUseCAChanged));
180 
181     lensfunCameras->signal_changed().connect(sigc::mem_fun(*this, &LensProfilePanel::onLensfunCameraChanged));
182     lensfunLenses->signal_changed().connect(sigc::mem_fun(*this, &LensProfilePanel::onLensfunLensChanged));
183     corrExif->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged), corrExif));
184     corrLensfunAutoRB->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged), corrLensfunAutoRB));
185     corrLensfunManualRB->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged), corrLensfunManualRB));
186     corrLcpFileRB->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged), corrLcpFileRB));
187 }
188 
read(const rtengine::procparams::ProcParams * pp)189 void LensProfilePanel::read(const rtengine::procparams::ProcParams* pp)
190 {
191     disableListener();
192     conUseDist.block(true);
193 
194     setEnabled(true);
195 
196     switch (pp->lensProf.lcMode) {
197         case procparams::LensProfParams::LcMode::LCP: {
198             corrLcpFileRB->set_active(true);
199             break;
200         }
201 
202         case procparams::LensProfParams::LcMode::LENSFUNAUTOMATCH: {
203             corrLensfunAutoRB->set_active(true);
204             break;
205         }
206 
207         case procparams::LensProfParams::LcMode::LENSFUNMANUAL: {
208             corrLensfunManualRB->set_active(true);
209             break;
210         }
211 
212         case procparams::LensProfParams::LcMode::EXIF: {
213             if (metadata) {
214                 if (rtengine::ExifLensCorrection::ok(metadata)) {
215                     corrExif->set_active(true);
216                     corrExif->set_sensitive(true);
217                     ckbUseCA->set_sensitive(true);
218                 } else {
219                     corrExif->set_sensitive(false);
220                     corrLensfunAutoRB->set_active(true);
221                 }
222             } else {
223                 corrExif->set_sensitive(false);
224                 setEnabled(false);
225             }
226             break;
227         }
228 
229         case procparams::LensProfParams::LcMode::NONE: {
230             setEnabled(false);
231             break;
232         }
233     }
234 
235     if (pp->lensProf.lcpFile.empty()) {
236         const Glib::ustring lastFolder = corrLcpFileChooser->get_current_folder();
237         corrLcpFileChooser->set_current_folder(lastFolder);
238         corrLcpFileChooser->unselect_all();
239         bindCurrentFolder(*corrLcpFileChooser, options.lastLensProfileDir);
240         updateDisabled();
241     } else if (LCPStore::getInstance()->isValidLCPFileName(pp->lensProf.lcpFile)) {
242         corrLcpFileChooser->set_filename(pp->lensProf.lcpFile);
243 
244         if (corrLcpFileRB->get_active()) {
245             updateDisabled();
246         }
247     } else {
248         corrLcpFileChooser->unselect_filename(corrLcpFileChooser->get_filename());
249         updateDisabled();
250     }
251 
252     setManualParamsVisibility(corrLensfunAutoRB->get_active() || corrLensfunManualRB->get_active());
253 
254     const LFDatabase* const db = LFDatabase::getInstance();
255     LFCamera c;
256 
257     if (pp->lensProf.lfAutoMatch()) {
258         if (metadata) {
259             c = db->findCamera(metadata->getMake(), metadata->getModel());
260             setLensfunCamera(c.getMake(), c.getModel());
261         }
262     } else if (pp->lensProf.lfManual()) {
263         setLensfunCamera(pp->lensProf.lfCameraMake, pp->lensProf.lfCameraModel);
264     }
265 
266     if (pp->lensProf.lfAutoMatch()) {
267         if (metadata) {
268             const LFLens l = db->findLens(c, metadata->getLens());
269             setLensfunLens(l.getLens());
270         }
271     } else if (pp->lensProf.lfManual()) {
272         setLensfunLens(pp->lensProf.lfLens);
273     }
274 
275 
276     ckbUseDist->set_active(pp->lensProf.useDist);
277     ckbUseVign->set_active(pp->lensProf.useVign);
278     ckbUseCA->set_active(pp->lensProf.useCA);
279 
280     lcModeChanged = lcpFileChanged = useDistChanged = useVignChanged = useCAChanged = false;
281     useLensfunChanged = lensfunAutoChanged = lensfunCameraChanged = lensfunLensChanged = false;
282 
283     updateLensfunWarning();
284     enableListener();
285     conUseDist.block(false);
286 }
287 
write(rtengine::procparams::ProcParams * pp)288 void LensProfilePanel::write(rtengine::procparams::ProcParams* pp)
289 {
290     if (!getEnabled()) {
291         pp->lensProf.lcMode = procparams::LensProfParams::LcMode::NONE;
292     } else if (corrLcpFileRB->get_active()) {
293         pp->lensProf.lcMode = procparams::LensProfParams::LcMode::LCP;
294     }
295     else if (corrLensfunManualRB->get_active()) {
296         pp->lensProf.lcMode = procparams::LensProfParams::LcMode::LENSFUNMANUAL;
297     }
298     else if (corrLensfunAutoRB->get_active()) {
299         pp->lensProf.lcMode = procparams::LensProfParams::LcMode::LENSFUNAUTOMATCH;
300     }
301     else if (corrExif->get_active()) {
302         pp->lensProf.lcMode = procparams::LensProfParams::LcMode::EXIF;
303     }
304 
305     if (LCPStore::getInstance()->isValidLCPFileName(corrLcpFileChooser->get_filename())) {
306         pp->lensProf.lcpFile = corrLcpFileChooser->get_filename();
307     } else {
308         pp->lensProf.lcpFile = "";
309     }
310 
311     pp->lensProf.useDist = ckbUseDist->get_active();
312     pp->lensProf.useVign = ckbUseVign->get_active();
313     pp->lensProf.useCA   = ckbUseCA->get_active();
314 
315     const auto itc = lensfunCameras->get_active();
316 
317     if (itc && !corrLensfunAutoRB->get_active()) {
318         pp->lensProf.lfCameraMake = (*itc)[lf->lensfunModelCam.make];
319         pp->lensProf.lfCameraModel = (*itc)[lf->lensfunModelCam.model];
320     } else {
321         pp->lensProf.lfCameraMake = "";
322         pp->lensProf.lfCameraModel = "";
323     }
324 
325     const auto itl = lensfunLenses->get_active();
326 
327     if (itl && !corrLensfunAutoRB->get_active()) {
328         pp->lensProf.lfLens = (*itl)[lf->lensfunModelLens.lens];
329     } else {
330         pp->lensProf.lfLens = "";
331     }
332 }
333 
setRawMeta(bool raw,const rtengine::FramesMetaData * pMeta)334 void LensProfilePanel::setRawMeta(bool raw, const rtengine::FramesMetaData* pMeta)
335 {
336     disableListener();
337     // if ((!raw || pMeta->getFocusDist() <= 0)) {
338 
339     //     // CA is very focus layer dependent, otherwise it might even worsen things
340     //     allowFocusDep = false;
341     //     ckbUseCA->set_active(false);
342     //     ckbUseCA->set_sensitive(false);
343     // }
344 
345     isRaw = raw;
346     metadata = pMeta;
347 
348     if (metadata) {
349         if (!rtengine::ExifLensCorrection::ok(metadata)) {
350             corrExif->set_sensitive(false);
351         } else {
352             ckbUseCA->set_sensitive(true);
353         }
354     } else {
355         corrExif->set_sensitive(false);
356     }
357     enableListener();
358 }
359 
onLCPFileChanged()360 void LensProfilePanel::onLCPFileChanged()
361 {
362     lcpFileChanged = true;
363     const bool valid = LCPStore::getInstance()->isValidLCPFileName(corrLcpFileChooser->get_filename());
364     updateDisabled();
365 
366     if (listener) {
367         if (valid) {
368             disableListener();
369             corrLcpFileRB->set_active(true);
370             enableListener();
371         }
372 
373         listener->panelChanged(EvLCPFile, Glib::path_get_basename(corrLcpFileChooser->get_filename()));
374     }
375 }
376 
onUseDistChanged()377 void LensProfilePanel::onUseDistChanged()
378 {
379     useDistChanged = true;
380     if (ckbUseDist->get_inconsistent()) {
381         ckbUseDist->set_inconsistent(false);
382         ckbUseDist->set_active(false);
383     }
384 
385     if (listener) {
386         listener->panelChanged(EvLCPUseDist, ckbUseDist->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED"));
387     }
388 }
389 
onUseVignChanged()390 void LensProfilePanel::onUseVignChanged()
391 {
392     useVignChanged = true;
393     if (ckbUseVign->get_inconsistent()) {
394         ckbUseVign->set_inconsistent(false);
395         ckbUseVign->set_active(false);
396     }
397 
398     if (listener) {
399         listener->panelChanged(EvLCPUseVign, ckbUseVign->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED"));
400     }
401 }
402 
onUseCAChanged()403 void LensProfilePanel::onUseCAChanged()
404 {
405     useCAChanged = true;
406     if (ckbUseCA->get_inconsistent()) {
407         ckbUseCA->set_inconsistent(false);
408         ckbUseCA->set_active(false);
409     }
410 
411     if (listener) {
412         listener->panelChanged(EvLCPUseCA, ckbUseCA->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED"));
413     }
414 }
415 
416 
onLensfunCameraChanged()417 void LensProfilePanel::onLensfunCameraChanged()
418 {
419     const auto iter = lensfunCameras->get_active();
420 
421     if (iter) {
422         lensfunCameraChanged = true;
423 
424         if (listener) {
425             disableListener();
426             corrLensfunManualRB->set_active(true);
427             enableListener();
428 
429             const Glib::ustring name = (*iter)[lf->lensfunModelCam.model];
430             listener->panelChanged(EvLensCorrLensfunCamera, name);
431         }
432     }
433 
434     updateLensfunWarning();
435 }
436 
onLensfunLensChanged()437 void LensProfilePanel::onLensfunLensChanged()
438 {
439     const auto iter = lensfunLenses->get_active();
440 
441     if (iter) {
442         lensfunLensChanged = true;
443 
444         if (listener) {
445             disableListener();
446             corrLensfunManualRB->set_active(true);
447             enableListener();
448 
449             const Glib::ustring name = (*iter)[lf->lensfunModelLens.prettylens];
450             listener->panelChanged(EvLensCorrLensfunLens, name);
451         }
452     }
453 
454     updateLensfunWarning();
455 }
456 
onCorrModeChanged(const Gtk::RadioButton * rbChanged)457 void LensProfilePanel::onCorrModeChanged(const Gtk::RadioButton* rbChanged)
458 {
459     if (rbChanged->get_active()) {
460         Glib::ustring mode;
461         if (rbChanged == corrLensfunAutoRB) {
462             lcModeChanged = true;
463             useLensfunChanged = true;
464             lensfunAutoChanged = true;
465             lensfunCameraChanged = true;
466             lensfunLensChanged = true;
467             lcpFileChanged = false;
468 
469             const bool disabled = disableListener();
470             if (metadata) {
471                 const LFDatabase* const db = LFDatabase::getInstance();
472                 const LFCamera c = db->findCamera(metadata->getMake(), metadata->getModel());
473                 const LFLens l = db->findLens(c, metadata->getLens());
474                 setLensfunCamera(c.getMake(), c.getModel());
475                 setLensfunLens(l.getLens());
476             }
477             if (disabled) {
478                 enableListener();
479             }
480 
481             mode = M("TP_LENSPROFILE_CORRECTION_AUTOMATCH");
482 
483         } else if (rbChanged == corrLensfunManualRB) {
484             lcModeChanged = true;
485             useLensfunChanged = true;
486             lensfunAutoChanged = true;
487             lensfunCameraChanged = true;
488             lensfunLensChanged = true;
489             lcpFileChanged = false;
490 
491             mode = M("TP_LENSPROFILE_CORRECTION_MANUAL");
492 
493         } else if (rbChanged == corrLcpFileRB || rbChanged == corrExif) {
494             lcModeChanged = true;
495             useLensfunChanged = true;
496             lensfunAutoChanged = true;
497             lcpFileChanged = true;
498 
499 
500             mode = M("TP_LENSPROFILE_CORRECTION_LCPFILE");
501         }
502 
503         updateLensfunWarning();
504         updateDisabled();
505 
506         if (rbChanged == corrLensfunManualRB || (rbChanged == corrLensfunAutoRB)) {
507             setManualParamsVisibility(true);
508         } else {
509             setManualParamsVisibility(false);
510         }
511 
512         if (listener) {
513             listener->panelChanged(EvLensCorrMode, mode);
514         }
515     }
516 }
517 
518 //-----------------------------------------------------------------------------
519 // LFDbHelper
520 //-----------------------------------------------------------------------------
521 
LFDbHelper()522 LensProfilePanel::LFDbHelper::LFDbHelper()
523 {
524     lensfunCameraModel = Gtk::TreeStore::create(lensfunModelCam);
525     lensfunLensModel = Gtk::TreeStore::create(lensfunModelLens);
526 
527 #ifdef _OPENMP
528 #pragma omp parallel sections if (!options.rtSettings.verbose)
529 #endif
530     {
531 #ifdef _OPENMP
532 #pragma omp section
533 #endif
534         {
535             fillLensfunCameras();
536         }
537 #ifdef _OPENMP
538 #pragma omp section
539 #endif
540         {
541             fillLensfunLenses();
542         }
543     }
544 }
545 
fillLensfunCameras()546 void LensProfilePanel::LFDbHelper::fillLensfunCameras()
547 {
548     if (options.rtSettings.verbose) {
549         std::cout << "LENSFUN, scanning cameras:" << std::endl;
550     }
551 
552     std::map<Glib::ustring, std::set<Glib::ustring>> camnames;
553     const auto camlist = LFDatabase::getInstance()->getCameras();
554 
555     for (const auto& c : camlist) {
556         camnames[c.getMake()].insert(c.getModel());
557 
558         if (options.rtSettings.verbose) {
559             std::cout << "  found: " << c.getDisplayString().c_str() << std::endl;
560         }
561     }
562 
563     for (const auto& p : camnames) {
564         Gtk::TreeModel::Row row = *(lensfunCameraModel->append());
565         row[lensfunModelCam.make] = p.first;
566         row[lensfunModelCam.model] = p.first;
567 
568         for (const auto& c : p.second) {
569             Gtk::TreeModel::Row child = *(lensfunCameraModel->append(row.children()));
570             child[lensfunModelCam.make] = p.first;
571             child[lensfunModelCam.model] = c;
572         }
573     }
574 }
575 
fillLensfunLenses()576 void LensProfilePanel::LFDbHelper::fillLensfunLenses()
577 {
578     if (options.rtSettings.verbose) {
579         std::cout << "LENSFUN, scanning lenses:" << std::endl;
580     }
581 
582     std::map<Glib::ustring, std::set<Glib::ustring>> lenses;
583     const auto lenslist = LFDatabase::getInstance()->getLenses();
584 
585     for (const auto& l : lenslist) {
586         const auto& name = l.getLens();
587         const auto& make = l.getMake();
588         lenses[make].insert(name);
589 
590         if (options.rtSettings.verbose) {
591             std::cout << "  found: " << l.getDisplayString().c_str() << std::endl;
592         }
593     }
594 
595     for (const auto& p : lenses) {
596         Gtk::TreeModel::Row row = *(lensfunLensModel->append());
597         row[lensfunModelLens.lens] = p.first;
598         row[lensfunModelLens.prettylens] = p.first;
599 
600         for (auto &c : p.second) {
601             Gtk::TreeModel::Row child = *(lensfunLensModel->append(row.children()));
602             child[lensfunModelLens.lens] = c;
603 
604             if (c.find(p.first, p.first.size() + 1) == p.first.size() + 1) {
605                 child[lensfunModelLens.prettylens] = c.substr(p.first.size() + 1);
606             } else {
607                 child[lensfunModelLens.prettylens] = c;
608             }
609         }
610     }
611 }
612 
updateDisabled()613 void LensProfilePanel::updateDisabled()
614 {
615     ckbUseDist->set_sensitive(true);
616     ckbUseVign->set_sensitive(true);
617     ckbUseCA->set_sensitive(true);
618 
619     ckbUseVign->set_sensitive(isRaw);
620     // ckbUseCA->set_sensitive(allowFocusDep || corrExif->get_active());
621 }
622 
setLensfunCamera(const Glib::ustring & make,const Glib::ustring & model)623 bool LensProfilePanel::setLensfunCamera(const Glib::ustring& make, const Glib::ustring& model)
624 {
625     if (!make.empty() && !model.empty()) {
626         const auto camera_it = lensfunCameras->get_active();
627 
628         if (camera_it && (*camera_it)[lf->lensfunModelCam.make] == make && (*camera_it)[lf->lensfunModelCam.model] == model) {
629             return true;
630         }
631 
632         // search for the active row
633         for (const auto& row : lf->lensfunCameraModel->children()) {
634             if (row[lf->lensfunModelCam.make] == make) {
635                 const auto& c = row.children();
636 
637                 for (auto model_it = c.begin(), end = c.end(); model_it != end; ++model_it) {
638                     const auto& childrow = *model_it;
639 
640                     if (childrow[lf->lensfunModelCam.model] == model) {
641                         lensfunCameras->set_active(model_it);
642                         return true;
643                     }
644                 }
645 
646                 break;
647             }
648         }
649     }
650 
651     lensfunCameras->set_active(-1);
652     return false;
653 }
654 
setLensfunLens(const Glib::ustring & lens)655 bool LensProfilePanel::setLensfunLens(const Glib::ustring& lens)
656 {
657     if (!lens.empty()) {
658         const auto lens_it = lensfunLenses->get_active();
659 
660         if (lens_it && (*lens_it)[lf->lensfunModelLens.lens] == lens) {
661             return true;
662         }
663 
664         bool first_maker_found = false;
665 
666         for (const auto& row : lf->lensfunLensModel->children()) {
667             if (lens.find(row[lf->lensfunModelLens.lens]) == 0) {
668                 const auto& c = row.children();
669 
670                 for (auto model_it = c.begin(), end = c.end(); model_it != end; ++model_it) {
671                     const auto& childrow = *model_it;
672 
673                     if (childrow[lf->lensfunModelLens.lens] == lens) {
674                         lensfunLenses->set_active(model_it);
675                         return true;
676                     }
677                 }
678 
679                 // we do not break immediately here, because there might be multiple makers
680                 // sharing the same prefix (e.g. "Leica" and "Leica Camera AG").
681                 // therefore, we break below when the lens doesn't match any of them
682                 first_maker_found = true;
683             } else if (first_maker_found) {
684                 break;
685             }
686         }
687     }
688 
689     lensfunLenses->set_active(-1);
690     return false;
691 }
692 
checkLensfunCanCorrect(bool automatch)693 bool LensProfilePanel::checkLensfunCanCorrect(bool automatch)
694 {
695     if (!metadata) {
696         return false;
697     }
698 
699     rtengine::procparams::ProcParams lpp;
700     write(&lpp);
701     const std::unique_ptr<LFModifier> mod(LFDatabase::getInstance()->findModifier(lpp.lensProf, metadata, 100, 100, lpp.coarse, -1));
702     return static_cast<bool>(mod);
703 }
704 
setManualParamsVisibility(bool setVisible)705 void LensProfilePanel::setManualParamsVisibility(bool setVisible)
706 {
707     if (setVisible) {
708         lensfunCamerasLbl->show();
709         lensfunCameras->show();
710         lensfunLensesLbl->show();
711         lensfunLenses->show();
712         updateLensfunWarning();
713     } else {
714         lensfunCamerasLbl->hide();
715         lensfunCameras->hide();
716         lensfunLensesLbl->hide();
717         lensfunLenses->hide();
718         warning->hide();
719     }
720 }
721 
updateLensfunWarning()722 void LensProfilePanel::updateLensfunWarning()
723 {
724     warning->hide();
725 
726     ckbUseVign->set_sensitive(isRaw);
727     ckbUseDist->set_sensitive(true);
728     ckbUseCA->set_sensitive(true);
729 
730     if (corrLensfunManualRB->get_active() || corrLensfunAutoRB->get_active()) {
731         const LFDatabase* const db = LFDatabase::getInstance();
732 
733         const auto itc = lensfunCameras->get_active();
734 
735         if (!itc) {
736             return;
737         }
738 
739         const LFCamera c = db->findCamera((*itc)[lf->lensfunModelCam.make], (*itc)[lf->lensfunModelCam.model]);
740         const auto itl = lensfunLenses->get_active();
741 
742         if (!itl) {
743             return;
744         }
745 
746         const LFLens l = db->findLens(LFCamera(), (*itl)[lf->lensfunModelLens.lens]);
747         const float lenscrop = l.getCropFactor();
748         const float camcrop = c.getCropFactor();
749 
750         if (lenscrop <= 0 || camcrop <= 0 || lenscrop / camcrop >= 1.01f) {
751             warning->show();
752         }
753 
754         ckbUseVign->set_sensitive(l.hasVignettingCorrection());
755         ckbUseDist->set_sensitive(l.hasDistortionCorrection());
756         ckbUseCA->set_sensitive(l.hasCACorrection()); // && allowFocusDep);
757 
758         if (!isRaw || !l.hasVignettingCorrection()) {
759             ckbUseVign->set_active(false);
760         }
761 
762         if (!l.hasDistortionCorrection()) {
763             ckbUseDist->set_active(false);
764         }
765 
766         if (!l.hasCACorrection()) {
767             ckbUseCA->set_active(false);
768         }
769     }
770 }
771 
772 LensProfilePanel::LFDbHelper* LensProfilePanel::lf(nullptr);
773 
774 
setDefaults(const ProcParams * def)775 void LensProfilePanel::setDefaults(const ProcParams *def)
776 {
777     initial_params = def->lensProf;
778 }
779 
780 
toolReset(bool to_initial)781 void LensProfilePanel::toolReset(bool to_initial)
782 {
783     ProcParams pp;
784     if (to_initial) {
785         pp.lensProf = initial_params;
786     }
787     read(&pp);
788     if (listener && !getEnabled()) {
789         listener->panelChanged(EvToolReset, M("GENERAL_RESET"));
790     }
791 }
792