1 /*
2  *  This file is part of RawTherapee.
3  *
4  *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
5  *  Copyright (c) 2010 Oliver Duis <www.oliverduis.de>
6  *
7  *  RawTherapee is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  RawTherapee is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with RawTherapee.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 #include "editorpanel.h"
21 
22 #include <iostream>
23 
24 #include "../rtengine/imagesource.h"
25 #include "../rtengine/iccstore.h"
26 #include "soundman.h"
27 #include "rtimage.h"
28 #include "rtwindow.h"
29 #include "guiutils.h"
30 #include "popupbutton.h"
31 #include "options.h"
32 #include "progressconnector.h"
33 #include "procparamchangers.h"
34 #include "placesbrowser.h"
35 #include "fastexport.h"
36 #include "../rtengine/imgiomanager.h"
37 
38 using namespace rtengine::procparams;
39 using ScopeType = Options::ScopeType;
40 
41 namespace
42 {
43 
setprogressStrUI(double val,const Glib::ustring str,MyProgressBar * pProgress)44 void setprogressStrUI(double val, const Glib::ustring str, MyProgressBar* pProgress)
45 {
46     if (!str.empty()) {
47         pProgress->set_text(M(str));
48     }
49 
50     if (val >= 0.0) {
51         pProgress->set_fraction(val);
52     }
53 }
54 
55 
find_default_monitor_profile(GdkWindow * rootwin,Glib::ustring & defprof,Glib::ustring & defprofname)56 bool find_default_monitor_profile (GdkWindow *rootwin, Glib::ustring &defprof, Glib::ustring &defprofname)
57 {
58 #ifdef WIN32
59     HDC hDC = GetDC (nullptr);
60 
61     if (hDC != nullptr) {
62         if (SetICMMode (hDC, ICM_ON)) {
63             char profileName[MAX_PATH + 1];
64             DWORD profileLength = MAX_PATH;
65 
66             if (GetICMProfileA (hDC, &profileLength, profileName)) {
67                 defprof = Glib::ustring (profileName);
68                 defprofname = Glib::path_get_basename (defprof);
69                 size_t pos = defprofname.rfind (".");
70 
71                 if (pos != Glib::ustring::npos) {
72                     defprofname = defprofname.substr (0, pos);
73                 }
74 
75                 defprof = Glib::ustring ("file:") + defprof;
76                 return true;
77             }
78 
79             // might fail if e.g. the monitor has no profile
80         }
81 
82         ReleaseDC (NULL, hDC);
83     }
84 
85 #elif !defined(__APPLE__)
86     // taken from geeqie (image.c) and adapted
87     // Originally licensed as GPL v2+, with the following copyright:
88     // * Copyright (C) 2006 John Ellis
89     // * Copyright (C) 2008 - 2016 The Geeqie Team
90     //
91     guchar *prof = nullptr;
92     gint proflen;
93     GdkAtom type = GDK_NONE;
94     gint format = 0;
95 
96     if (gdk_property_get (rootwin, gdk_atom_intern ("_ICC_PROFILE", FALSE), GDK_NONE, 0, 64 * 1024 * 1024, FALSE, &type, &format, &proflen, &prof) && proflen > 0) {
97         cmsHPROFILE p = cmsOpenProfileFromMem (prof, proflen);
98 
99         if (p) {
100             defprofname = "from GDK";
101             defprof = Glib::build_filename (Options::rtdir, "GDK_ICC_PROFILE.icc");
102 
103             if (cmsSaveProfileToFile (p, defprof.c_str())) {
104                 cmsCloseProfile (p);
105 
106                 if (prof) {
107                     g_free (prof);
108                 }
109 
110                 defprof = Glib::ustring ("file:") + defprof;
111                 return true;
112             }
113         }
114     }
115 
116     if (prof) {
117         g_free (prof);
118     }
119 
120 #endif
121     return false;
122 }
123 
124 
125 }
126 
127 class EditorPanel::ColorManagementToolbar
128 {
129 private:
130 #if !defined(__APPLE__) // monitor profile not supported on apple
131     MyComboBoxText profileBox;
132 #endif
133     PopUpButton intentBox;
134     Gtk::ToggleButton softProof;
135     Gtk::ToggleButton spGamutCheck;
136     sigc::connection profileConn, intentConn, softproofConn;
137     Glib::ustring defprof;
138 
139     rtengine::StagedImageProcessor* const& processor;
140 
141 private:
142 #if !defined(__APPLE__) // monitor profile not supported on apple
prepareProfileBox()143     void prepareProfileBox ()
144     {
145         profileBox.setPreferredWidth (70, 200);
146         setExpandAlignProperties (&profileBox, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
147 
148         profileBox.append (M ("PREFERENCES_PROFILE_NONE"));
149         Glib::ustring defprofname;
150 
151         if (find_default_monitor_profile (profileBox.get_root_window()->gobj(), defprof, defprofname)) {
152             profileBox.append (M ("MONITOR_PROFILE_SYSTEM") + " (" + defprofname + ")");
153 
154             if (options.rtSettings.autoMonitorProfile) {
155                 rtengine::ICCStore::getInstance()->setDefaultMonitorProfileName (defprof);
156                 profileBox.set_active (1);
157             } else {
158                 profileBox.set_active (0);
159             }
160         } else {
161             profileBox.set_active (0);
162         }
163 
164         const std::vector<Glib::ustring> profiles = rtengine::ICCStore::getInstance()->getProfilesFromDir(options.rtSettings.monitorIccDirectory);
165 
166         for (const auto &profile : profiles) {
167             profileBox.append(profile);
168         }
169 
170         profileBox.set_tooltip_text (profileBox.get_active_text ());
171     }
172 #endif
173 
prepareIntentBox()174     void prepareIntentBox ()
175     {
176         // same order as the enum
177         intentBox.addEntry ("intent-perceptual.png", M ("PREFERENCES_INTENT_PERCEPTUAL"));
178         intentBox.addEntry ("intent-relative.png", M ("PREFERENCES_INTENT_RELATIVE"));
179         intentBox.addEntry ("intent-absolute.png", M ("PREFERENCES_INTENT_ABSOLUTE"));
180         setExpandAlignProperties (intentBox.buttonGroup, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
181 
182         intentBox.setSelected (1);
183         intentBox.show ();
184     }
185 
prepareSoftProofingBox()186     void prepareSoftProofingBox ()
187     {
188         Gtk::Image *softProofImage = Gtk::manage (new RTImage ("gamut-softproof.png"));
189         softProofImage->set_padding (0, 0);
190         softProof.add (*softProofImage);
191         softProof.set_relief (Gtk::RELIEF_NONE);
192         softProof.set_tooltip_markup (M ("SOFTPROOF_TOOLTIP"));
193 
194         softProof.set_active (false);
195         softProof.show ();
196 
197         Gtk::Image *spGamutCheckImage = Gtk::manage (new RTImage ("gamut-warning.png"));
198         spGamutCheckImage->set_padding (0, 0);
199         spGamutCheck.add (*spGamutCheckImage);
200         spGamutCheck.set_relief (Gtk::RELIEF_NONE);
201         spGamutCheck.set_tooltip_markup (M ("SOFTPROOF_GAMUTCHECK_TOOLTIP"));
202 
203         spGamutCheck.set_active (false);
204         spGamutCheck.set_sensitive (true);
205         spGamutCheck.show ();
206     }
207 
208 #if !defined(__APPLE__)
profileBoxChanged()209     void profileBoxChanged ()
210     {
211         updateParameters ();
212     }
213 #endif
214 
intentBoxChanged(int)215     void intentBoxChanged (int)
216     {
217         updateParameters ();
218     }
219 
softProofToggled()220     void softProofToggled ()
221     {
222         updateSoftProofParameters ();
223     }
224 
spGamutCheckToggled()225     void spGamutCheckToggled ()
226     {
227         updateSoftProofParameters ();
228     }
229 
updateParameters(bool noEvent=false)230     void updateParameters (bool noEvent = false)
231     {
232 #if !defined(__APPLE__) // monitor profile not supported on apple
233         ConnectionBlocker profileBlocker (profileConn);
234 #endif
235         ConnectionBlocker intentBlocker (intentConn);
236 
237         Glib::ustring profile;
238 
239 #if !defined(__APPLE__) // monitor profile not supported on apple
240 
241         if (!defprof.empty() && profileBox.get_active_row_number () == 1) {
242             profile = defprof;
243 
244             if (profile.empty ()) {
245                 profile = options.rtSettings.monitorProfile;
246             }
247 
248             if (profile.empty ()) {
249                 profile = "sRGB IEC61966-2.1";
250             }
251         } else if (profileBox.get_active_row_number () > 0) {
252             profile = profileBox.get_active_text ();
253         }
254 
255 #else
256         profile = options.rtSettings.srgb;
257 #endif
258 
259 #if !defined(__APPLE__) // monitor profile not supported on apple
260 
261         if (profileBox.get_active_row_number () == 0) {
262 
263             profile.clear ();
264 
265             intentBox.set_sensitive (false);
266             intentBox.setSelected (1);
267             softProof.set_sensitive (false);
268             spGamutCheck.set_sensitive (false);
269 
270             profileBox.set_tooltip_text ("");
271 
272         } else {
273             const uint8_t supportedIntents = rtengine::ICCStore::getInstance()->getProofIntents (profile);
274             const bool supportsRelativeColorimetric = supportedIntents & 1 << INTENT_RELATIVE_COLORIMETRIC;
275             const bool supportsPerceptual = supportedIntents & 1 << INTENT_PERCEPTUAL;
276             const bool supportsAbsoluteColorimetric = supportedIntents & 1 << INTENT_ABSOLUTE_COLORIMETRIC;
277 
278             if (supportsPerceptual || supportsRelativeColorimetric || supportsAbsoluteColorimetric) {
279                 intentBox.set_sensitive (true);
280                 intentBox.setItemSensitivity (0, supportsPerceptual);
281                 intentBox.setItemSensitivity (1, supportsRelativeColorimetric);
282                 intentBox.setItemSensitivity (2, supportsAbsoluteColorimetric);
283                 softProof.set_sensitive (true);
284                 spGamutCheck.set_sensitive (true);
285             } else {
286                 intentBox.setItemSensitivity (0, true);
287                 intentBox.setItemSensitivity (1, true);
288                 intentBox.setItemSensitivity (2, true);
289                 intentBox.set_sensitive (false);
290                 intentBox.setSelected (1);
291                 softProof.set_sensitive (false);
292                 spGamutCheck.set_sensitive (true);
293             }
294 
295             profileBox.set_tooltip_text (profileBox.get_active_text ());
296         }
297 
298 #endif
299         rtengine::RenderingIntent intent;
300 
301         switch (intentBox.getSelected ()) {
302             default:
303             case 0:
304                 intent = rtengine::RI_PERCEPTUAL;
305                 break;
306 
307             case 1:
308                 intent = rtengine::RI_RELATIVE;
309                 break;
310 
311             case 2:
312                 intent = rtengine::RI_ABSOLUTE;
313                 break;
314         }
315 
316         if (!processor) {
317             return;
318         }
319 
320         if (!noEvent) {
321             processor->beginUpdateParams ();
322         }
323 
324         processor->setMonitorProfile (profile, intent);
325         processor->setSoftProofing (softProof.get_sensitive() && softProof.get_active(), spGamutCheck.get_sensitive() && spGamutCheck.get_active());
326 
327         if (!noEvent) {
328             processor->endUpdateParams (rtengine::EvMonitorTransform);
329         }
330     }
331 
updateSoftProofParameters(bool noEvent=false)332     void updateSoftProofParameters (bool noEvent = false)
333     {
334 #if !defined(__APPLE__) // monitor profile not supported on apple
335         softProof.set_sensitive (profileBox.get_active_row_number () > 0);
336         spGamutCheck.set_sensitive(profileBox.get_active_row_number () > 0);
337 #endif
338 
339 
340 #if !defined(__APPLE__) // monitor profile not supported on apple
341 
342         if (profileBox.get_active_row_number () > 0) {
343 #endif
344 
345             if (processor) {
346                 if (!noEvent) {
347                     processor->beginUpdateParams ();
348                 }
349 
350                 processor->setSoftProofing (softProof.get_sensitive() && softProof.get_active(), spGamutCheck.get_active());
351 
352                 if (!noEvent) {
353                     processor->endUpdateParams (rtengine::EvMonitorTransform);
354                 }
355             }
356 
357 #if !defined(__APPLE__) // monitor profile not supported on apple
358         }
359 
360 #endif
361     }
362 
363 public:
ColorManagementToolbar(rtengine::StagedImageProcessor * const & ipc)364     explicit ColorManagementToolbar (rtengine::StagedImageProcessor* const& ipc) :
365         intentBox (Glib::ustring (), true),
366         processor (ipc)
367     {
368 #if !defined(__APPLE__) // monitor profile not supported on apple
369         prepareProfileBox ();
370 #endif
371         prepareIntentBox ();
372         prepareSoftProofingBox ();
373 
374         reset ();
375 
376         softproofConn = softProof.signal_toggled().connect (sigc::mem_fun (this, &ColorManagementToolbar::softProofToggled));
377         spGamutCheck.signal_toggled().connect (sigc::mem_fun (this, &ColorManagementToolbar::spGamutCheckToggled));
378 #if !defined(__APPLE__) // monitor profile not supported on apple
379         profileConn = profileBox.signal_changed ().connect (sigc::mem_fun (this, &ColorManagementToolbar::profileBoxChanged));
380 #endif
381         intentConn = intentBox.signal_changed ().connect (sigc::mem_fun (this, &ColorManagementToolbar::intentBoxChanged));
382     }
383 
pack_right_in(Gtk::Grid * grid)384     void pack_right_in (Gtk::Grid* grid)
385     {
386 #if !defined(__APPLE__) // monitor profile not supported on apple
387         grid->attach_next_to (profileBox, Gtk::POS_RIGHT, 1, 1);
388 #endif
389         grid->attach_next_to (*intentBox.buttonGroup, Gtk::POS_RIGHT, 1, 1);
390         grid->attach_next_to (softProof, Gtk::POS_RIGHT, 1, 1);
391         grid->attach_next_to (spGamutCheck, Gtk::POS_RIGHT, 1, 1);
392     }
393 
updateProcessor()394     void updateProcessor()
395     {
396         if (processor) {
397             updateParameters (true);
398         }
399     }
400 
reset()401     void reset ()
402     {
403         ConnectionBlocker intentBlocker (intentConn);
404 #if !defined(__APPLE__) // monitor profile not supported on apple
405         ConnectionBlocker profileBlocker (profileConn);
406 
407         if (!defprof.empty() && options.rtSettings.autoMonitorProfile) {
408             profileBox.set_active (1);
409         } else {
410             setActiveTextOrIndex (profileBox, options.rtSettings.monitorProfile, 0);
411         }
412 
413 #endif
414 
415         switch (options.rtSettings.monitorIntent) {
416             default:
417             case rtengine::RI_PERCEPTUAL:
418                 intentBox.setSelected (0);
419                 break;
420 
421             case rtengine::RI_RELATIVE:
422                 intentBox.setSelected (1);
423                 break;
424 
425             case rtengine::RI_ABSOLUTE:
426                 intentBox.setSelected (2);
427                 break;
428         }
429 
430         updateParameters ();
431     }
432 
updateHistogram()433     void updateHistogram()
434     {
435       updateParameters();
436     }
437 
438 
defaultMonitorProfileChanged(const Glib::ustring & profile_name,bool auto_monitor_profile)439     void defaultMonitorProfileChanged (const Glib::ustring &profile_name, bool auto_monitor_profile)
440     {
441         ConnectionBlocker profileBlocker (profileConn);
442 
443         if (auto_monitor_profile && !defprof.empty()) {
444             rtengine::ICCStore::getInstance()->setDefaultMonitorProfileName (defprof);
445 #ifndef __APPLE__
446             profileBox.set_active (1);
447 #endif
448         } else {
449             rtengine::ICCStore::getInstance()->setDefaultMonitorProfileName (profile_name);
450 #ifndef __APPLE__
451             setActiveTextOrIndex (profileBox, profile_name, 0);
452 #endif
453         }
454     }
455 
456 };
457 
EditorPanel(FilePanel * filePanel)458 EditorPanel::EditorPanel (FilePanel* filePanel)
459     : catalogPane (nullptr), realized (false), tbBeforeLock (nullptr), iHistoryShow (nullptr), iHistoryHide (nullptr),
460       iTopPanel_1_Show (nullptr), iTopPanel_1_Hide (nullptr), iRightPanel_1_Show (nullptr), iRightPanel_1_Hide (nullptr),
461       iBeforeLockON (nullptr), iBeforeLockOFF (nullptr), previewHandler (nullptr), beforePreviewHandler (nullptr),
462       beforeIarea (nullptr), beforeBox (nullptr), afterBox (nullptr), beforeLabel (nullptr), afterLabel (nullptr),
463       beforeHeaderBox (nullptr), afterHeaderBox (nullptr), parent (nullptr), parentWindow (nullptr), openThm (nullptr),
464       selectedFrame(0), isrc (nullptr), ipc (nullptr), beforeIpc (nullptr), err (0), isProcessing (false),
465       histogram_observable(nullptr), histogram_scope_type(ScopeType::NONE)
466 {
467 
468     epih = new EditorPanelIdleHelper;
469     epih->epanel = this;
470     epih->destroyed = false;
471     epih->pending = 0;
472     //rtengine::befaf=true;
473     processingStartedTime = 0;
474     firstProcessingDone = false;
475 
476     // construct toolpanelcoordinator
477     tpc = new ToolPanelCoordinator();
478     tpc->setProgressListener(this);
479 
480     // build GUI
481 
482     // build left side panel
483     leftbox = new Gtk::Paned (Gtk::ORIENTATION_VERTICAL);
484 
485     // make a subbox to allow resizing of the histogram (if it's on the left)
486     leftsubbox = new Gtk::Box (Gtk::ORIENTATION_VERTICAL);
487     leftsubbox->set_size_request (230, 250);
488 
489     histogramPanel = nullptr;
490 
491     profilep = Gtk::manage (new ProfilePanel ());
492     ppframe = new Gtk::Frame ();
493     ppframe->set_name ("ProfilePanel");
494     ppframe->add (*profilep);
495     ppframe->set_label (M ("PROFILEPANEL_LABEL"));
496     //leftsubbox->pack_start (*ppframe, Gtk::PACK_SHRINK, 4);
497 
498     navigator = Gtk::manage (new Navigator ());
499     navigator->previewWindow->set_size_request (-1, 150 * RTScalable::getScale());
500     leftsubbox->pack_start (*navigator, Gtk::PACK_SHRINK, 2);
501 
502     history = Gtk::manage (new History ());
503     leftsubbox->pack_start (*history);
504 
505     leftsubbox->show_all ();
506 
507     leftbox->pack2 (*leftsubbox, true, true);
508     leftbox->show_all ();
509 
510     // build the middle of the screen
511     Gtk::Box* editbox = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_VERTICAL));
512 
513     info = Gtk::manage (new Gtk::ToggleButton ());
514     Gtk::Image* infoimg = Gtk::manage (new RTImage ("info.png"));
515     info->add (*infoimg);
516     info->set_relief (Gtk::RELIEF_NONE);
517     info->set_tooltip_markup (M ("MAIN_TOOLTIP_QINFO"));
518 
519     beforeAfter = Gtk::manage (new Gtk::ToggleButton ());
520     Gtk::Image* beforeAfterIcon = Gtk::manage (new RTImage ("beforeafter.png"));
521     beforeAfter->add (*beforeAfterIcon);
522     beforeAfter->set_relief (Gtk::RELIEF_NONE);
523     beforeAfter->set_tooltip_markup (M ("MAIN_TOOLTIP_TOGGLE"));
524 
525     iBeforeLockON = new RTImage ("padlock-locked-small.png");
526     iBeforeLockOFF = new RTImage ("padlock-unlocked-small.png");
527 
528     Gtk::VSeparator* vsept = Gtk::manage (new Gtk::VSeparator ());
529     Gtk::VSeparator* vsepz = Gtk::manage (new Gtk::VSeparator ());
530     Gtk::VSeparator* vsepi = Gtk::manage (new Gtk::VSeparator ());
531     Gtk::VSeparator* vseph = Gtk::manage (new Gtk::VSeparator ());
532 
533     hidehp = Gtk::manage (new Gtk::ToggleButton ());
534 
535     iHistoryShow = new RTImage ("panel-to-right.png");
536     iHistoryHide = new RTImage ("panel-to-left.png");
537 
538     hidehp->set_relief (Gtk::RELIEF_NONE);
539     hidehp->set_active (options.showHistory);
540     hidehp->set_tooltip_markup (M ("MAIN_TOOLTIP_HIDEHP"));
541 
542     if (options.showHistory) {
543         hidehp->set_image (*iHistoryHide);
544     } else {
545         hidehp->set_image (*iHistoryShow);
546     }
547 
548     tbTopPanel_1 = nullptr;
549 
550     if (!simpleEditor && filePanel) {
551         tbTopPanel_1 = new Gtk::ToggleButton ();
552         iTopPanel_1_Show = new RTImage ("panel-to-bottom.png");
553         iTopPanel_1_Hide = new RTImage ("panel-to-top.png");
554         tbTopPanel_1->set_relief (Gtk::RELIEF_NONE);
555         tbTopPanel_1->set_active (true);
556         tbTopPanel_1->set_tooltip_markup (M ("MAIN_TOOLTIP_SHOWHIDETP1"));
557         tbTopPanel_1->set_image (*iTopPanel_1_Hide);
558     }
559 
560     Gtk::VSeparator* vsepcl = Gtk::manage (new Gtk::VSeparator ());
561     Gtk::VSeparator* vsepz2 = Gtk::manage (new Gtk::VSeparator ());
562     Gtk::VSeparator* vsepz3 = Gtk::manage (new Gtk::VSeparator ());
563     Gtk::VSeparator* vsepz4 = Gtk::manage (new Gtk::VSeparator ());
564 
565     Gtk::VSeparator* vsep1 = Gtk::manage (new Gtk::VSeparator ());
566     Gtk::VSeparator* vsep2 = Gtk::manage (new Gtk::VSeparator ());
567 
568     // Histogram profile toggle controls
569     toggleHistogramProfile = Gtk::manage (new Gtk::ToggleButton ());
570     Gtk::Image* histProfImg = Gtk::manage (new RTImage ("gamut-hist.png"));
571     toggleHistogramProfile->add (*histProfImg);
572     toggleHistogramProfile->set_relief (Gtk::RELIEF_NONE);
573     toggleHistogramProfile->set_active (options.rtSettings.HistogramWorking);
574     toggleHistogramProfile->set_tooltip_markup ( (M ("PREFERENCES_HISTOGRAM_TOOLTIP")));
575 
576     Gtk::VSeparator* vsep3 = Gtk::manage (new Gtk::VSeparator ());
577 
578     iareapanel = new ImageAreaPanel ();
579     tpc->setEditProvider (iareapanel->imageArea);
580     tpc->getToolBar()->setLockablePickerToolListener (iareapanel->imageArea);
581 
582     Gtk::Box* toolBarPanel = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_HORIZONTAL));
583     toolBarPanel->set_name ("EditorTopPanel");
584     toolBarPanel->pack_start (*hidehp, Gtk::PACK_SHRINK, 1);
585     toolBarPanel->pack_start (*vseph, Gtk::PACK_SHRINK, 2);
586     toolBarPanel->pack_start (*info, Gtk::PACK_SHRINK, 1);
587     toolBarPanel->pack_start (*beforeAfter, Gtk::PACK_SHRINK, 1);
588     toolBarPanel->pack_start (*vsepi, Gtk::PACK_SHRINK, 2);
589     toolBarPanel->pack_start (*tpc->getToolBar(), Gtk::PACK_SHRINK, 1);
590     toolBarPanel->pack_start (*vsept, Gtk::PACK_SHRINK, 2);
591 
592     if (tbTopPanel_1) {
593         Gtk::VSeparator* vsep = Gtk::manage (new Gtk::VSeparator ());
594         toolBarPanel->pack_end   (*tbTopPanel_1, Gtk::PACK_SHRINK, 1);
595         toolBarPanel->pack_end   (*vsep, Gtk::PACK_SHRINK, 2);
596     }
597 
598     toolBarPanel->pack_end   (*tpc->coarse, Gtk::PACK_SHRINK, 2);
599     toolBarPanel->pack_end   (*vsepcl, Gtk::PACK_SHRINK, 2);
600     // Histogram profile toggle
601     toolBarPanel->pack_end (*toggleHistogramProfile, Gtk::PACK_SHRINK, 1);
602     toolBarPanel->pack_end (*vsep3, Gtk::PACK_SHRINK, 2);
603 
604     toolBarPanel->pack_end   (*iareapanel->imageArea->indClippedPanel, Gtk::PACK_SHRINK, 0);
605     toolBarPanel->pack_end   (*vsepz, Gtk::PACK_SHRINK, 2);
606     toolBarPanel->pack_end   (*iareapanel->imageArea->previewModePanel, Gtk::PACK_SHRINK, 0);
607     toolBarPanel->pack_end   (*vsepz4, Gtk::PACK_SHRINK, 2);
608 
609     afterBox = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_VERTICAL));
610     afterBox->pack_start (*iareapanel);
611 
612     beforeAfterBox = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_HORIZONTAL));
613     beforeAfterBox->set_name ("BeforeAfterContainer");
614     beforeAfterBox->pack_start (*afterBox);
615 
616     MyScrolledToolbar *stb1 = Gtk::manage(new MyScrolledToolbar());
617     stb1->set_name("EditorToolbarTop");
618     stb1->add(*toolBarPanel);
619     editbox->pack_start (*stb1, Gtk::PACK_SHRINK, 2);
620     editbox->pack_start (*beforeAfterBox);
621 
622     // build right side panel
623     vboxright = new Gtk::Paned (Gtk::ORIENTATION_VERTICAL);
624 
625     vsubboxright = new Gtk::Box (Gtk::ORIENTATION_VERTICAL, 0);
626     vsubboxright->set_size_request (300, 250);
627 
628     vsubboxright->pack_start (*ppframe, Gtk::PACK_SHRINK, 2);
629     // main notebook
630     vsubboxright->pack_start (*tpc->toolPanelNotebook);
631 
632     vboxright->pack2 (*vsubboxright, true, true);
633 
634     // Save buttons
635     Gtk::Grid *iops = new Gtk::Grid ();
636     iops->set_name ("IopsPanel");
637     iops->set_orientation (Gtk::ORIENTATION_HORIZONTAL);
638     iops->set_row_spacing (2);
639     iops->set_column_spacing (2);
640 
641     Gtk::Image *saveButtonImage =  Gtk::manage (new RTImage ("save.png"));
642     saveimgas = Gtk::manage (new Gtk::Button ());
643     saveimgas->set_relief(Gtk::RELIEF_NONE);
644     saveimgas->add (*saveButtonImage);
645     saveimgas->set_tooltip_markup (M ("MAIN_BUTTON_SAVE_TOOLTIP"));
646     setExpandAlignProperties (saveimgas, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
647 
648     Gtk::Image *queueButtonImage = Gtk::manage (new RTImage ("gears.png"));
649     queueimg = Gtk::manage (new Gtk::Button ());
650     queueimg->set_relief(Gtk::RELIEF_NONE);
651     queueimg->add (*queueButtonImage);
652     queueimg->set_tooltip_markup (M ("MAIN_BUTTON_PUTTOQUEUE_TOOLTIP"));
653     setExpandAlignProperties (queueimg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
654 
655     Gtk::Image *sendToEditorButtonImage = Gtk::manage (new RTImage ("palette-brush.png"));
656     sendtogimp = Gtk::manage (new Gtk::Button ());
657     sendtogimp->set_relief(Gtk::RELIEF_NONE);
658     sendtogimp->add (*sendToEditorButtonImage);
659     sendtogimp->set_tooltip_markup (M ("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP"));
660     setExpandAlignProperties (sendtogimp, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
661 
662     // Status box
663     progressLabel = Gtk::manage (new MyProgressBar (300));
664     progressLabel->set_show_text (true);
665     setExpandAlignProperties (progressLabel, true, false, Gtk::ALIGN_START, Gtk::ALIGN_FILL);
666     progressLabel->set_fraction (0.0);
667 
668     // tbRightPanel_1
669     tbRightPanel_1 = new Gtk::ToggleButton ();
670     iRightPanel_1_Show = new RTImage ("panel-to-left.png");
671     iRightPanel_1_Hide = new RTImage ("panel-to-right.png");
672     tbRightPanel_1->set_relief (Gtk::RELIEF_NONE);
673     tbRightPanel_1->set_active (true);
674     tbRightPanel_1->set_tooltip_markup (M ("MAIN_TOOLTIP_SHOWHIDERP1"));
675     tbRightPanel_1->set_image (*iRightPanel_1_Hide);
676     setExpandAlignProperties (tbRightPanel_1, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
677 
678     // ShowHideSidePanels
679     tbShowHideSidePanels = new Gtk::ToggleButton ();
680     iShowHideSidePanels = new RTImage ("crossed-arrows-out.png");
681     iShowHideSidePanels_exit = new RTImage ("crossed-arrows-in.png");
682     tbShowHideSidePanels->set_relief (Gtk::RELIEF_NONE);
683     tbShowHideSidePanels->set_active (false);
684     tbShowHideSidePanels->set_tooltip_markup (M ("MAIN_BUTTON_SHOWHIDESIDEPANELS_TOOLTIP"));
685     tbShowHideSidePanels->set_image (*iShowHideSidePanels);
686     setExpandAlignProperties (tbShowHideSidePanels, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
687 
688     navPrev = navNext = navSync = nullptr;
689 
690     if (!simpleEditor && !options.tabbedUI) {
691         // Navigation buttons
692         Gtk::Image *navPrevImage = Gtk::manage (new RTImage ("arrow2-left.png"));
693         navPrevImage->set_padding (0, 0);
694         navPrev = Gtk::manage (new Gtk::Button ());
695         navPrev->add (*navPrevImage);
696         navPrev->set_relief (Gtk::RELIEF_NONE);
697         navPrev->set_tooltip_markup (M ("MAIN_BUTTON_NAVPREV_TOOLTIP"));
698         setExpandAlignProperties (navPrev, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
699 
700         Gtk::Image *navNextImage = Gtk::manage (new RTImage ("arrow2-right.png"));
701         navNextImage->set_padding (0, 0);
702         navNext = Gtk::manage (new Gtk::Button ());
703         navNext->add (*navNextImage);
704         navNext->set_relief (Gtk::RELIEF_NONE);
705         navNext->set_tooltip_markup (M ("MAIN_BUTTON_NAVNEXT_TOOLTIP"));
706         setExpandAlignProperties (navNext, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
707 
708         Gtk::Image *navSyncImage = Gtk::manage (new RTImage ("arrow-updown.png"));
709         navSyncImage->set_padding (0, 0);
710         navSync = Gtk::manage (new Gtk::Button ());
711         navSync->add (*navSyncImage);
712         navSync->set_relief (Gtk::RELIEF_NONE);
713         navSync->set_tooltip_markup (M ("MAIN_BUTTON_NAVSYNC_TOOLTIP"));
714         setExpandAlignProperties (navSync, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
715     }
716 
717     // ==================  PACKING THE BOTTOM WIDGETS =================
718 
719     // Adding widgets from center to the left, on the left side (using Gtk::POS_LEFT)
720     iops->attach_next_to (*vsep2, Gtk::POS_LEFT, 1, 1);
721     iops->attach_next_to (*progressLabel, Gtk::POS_LEFT, 1, 1);
722     iops->attach_next_to (*vsep1, Gtk::POS_LEFT, 1, 1);
723 
724     if (!gimpPlugin) {
725         iops->attach_next_to (*sendtogimp, Gtk::POS_LEFT, 1, 1);
726     }
727 
728     if (!gimpPlugin && !simpleEditor) {
729         iops->attach_next_to (*queueimg, Gtk::POS_LEFT, 1, 1);
730     }
731 
732     if (!gimpPlugin) {
733         iops->attach_next_to (*saveimgas, Gtk::POS_LEFT, 1, 1);
734     }
735 
736 
737     // Color management toolbar
738     colorMgmtToolBar.reset (new ColorManagementToolbar (ipc));
739     colorMgmtToolBar->pack_right_in (iops);
740 
741     if (!simpleEditor && !options.tabbedUI) {
742         Gtk::VSeparator* vsep3 = Gtk::manage (new Gtk::VSeparator ());
743         iops->attach_next_to (*vsep3, Gtk::POS_RIGHT, 1, 1);
744         iops->attach_next_to (*navPrev, Gtk::POS_RIGHT, 1, 1);
745         iops->attach_next_to (*navSync, Gtk::POS_RIGHT, 1, 1);
746         iops->attach_next_to (*navNext, Gtk::POS_RIGHT, 1, 1);
747     }
748 
749     iops->attach_next_to (*vsepz2, Gtk::POS_RIGHT, 1, 1);
750     iops->attach_next_to (*iareapanel->imageArea->zoomPanel, Gtk::POS_RIGHT, 1, 1);
751     iops->attach_next_to (*vsepz3, Gtk::POS_RIGHT, 1, 1);
752     iops->attach_next_to (*tbShowHideSidePanels, Gtk::POS_RIGHT, 1, 1);
753     iops->attach_next_to (*tbRightPanel_1, Gtk::POS_RIGHT, 1, 1);
754 
755     MyScrolledToolbar *stb2 = Gtk::manage(new MyScrolledToolbar());
756     stb2->set_name("EditorToolbarBottom");
757     stb2->add(*iops);
758 
759     editbox->pack_start (*stb2, Gtk::PACK_SHRINK, 0);
760     editbox->show_all ();
761 
762     // build screen
763     hpanedl = Gtk::manage (new Gtk::Paned (Gtk::ORIENTATION_HORIZONTAL));
764     hpanedl->set_name ("EditorLeftPaned");
765     hpanedr = Gtk::manage (new Gtk::Paned (Gtk::ORIENTATION_HORIZONTAL));
766     hpanedr->set_name ("EditorRightPaned");
767     leftbox->reference ();
768     vboxright->reference ();
769 
770     if (options.showHistory) {
771         hpanedl->pack1 (*leftbox, false, false);
772         hpanedl->set_position (options.historyPanelWidth);
773     }
774 
775     Gtk::Paned *viewpaned = Gtk::manage (new Gtk::Paned (Gtk::ORIENTATION_VERTICAL));
776     fPanel = filePanel;
777 
778     if (filePanel) {
779         catalogPane = new Gtk::Paned();
780         viewpaned->pack1 (*catalogPane, false, true);
781     }
782 
783     viewpaned->pack2 (*editbox, true, true);
784 
785     hpanedl->pack2 (*viewpaned, true, true);
786 
787     hpanedr->pack1 (*hpanedl, true, false);
788     hpanedr->pack2 (*vboxright, false, false);
789     hpanedl->signal_button_release_event().connect_notify ( sigc::mem_fun (*this, &EditorPanel::leftPaneButtonReleased) );
790     hpanedr->signal_button_release_event().connect_notify ( sigc::mem_fun (*this, &EditorPanel::rightPaneButtonReleased) );
791 
792     pack_start (*hpanedr);
793 
794     updateHistogramPosition (0, options.histogramPosition);
795 
796     show_all ();
797     /*
798         // save as dialog
799         if (Glib::file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR))
800             saveAsDialog = new SaveAsDialog (options.lastSaveAsPath);
801         else
802             saveAsDialog = new SaveAsDialog (safe_get_user_picture_dir());
803 
804         saveAsDialog->set_default_size (options.saveAsDialogWidth, options.saveAsDialogHeight);
805     */
806     // connect listeners
807     profilep->setProfileChangeListener (tpc);
808     history->setProfileChangeListener (tpc);
809     history->setHistoryBeforeAfterListener (this);
810     tpc->addPParamsChangeListener (profilep);
811     tpc->addPParamsChangeListener (history);
812     tpc->addPParamsChangeListener (this);
813     iareapanel->imageArea->setCropGUIListener (tpc->getCropGUIListener());
814     iareapanel->imageArea->setPointerMotionListener (navigator);
815     iareapanel->imageArea->setImageAreaToolListener (tpc);
816     iareapanel->imageArea->setAreaDrawListenerProvider(tpc);
817 
818     // initialize components
819     info->set_active (options.showInfo);
820     tpc->readOptions ();
821 
822     // connect event handlers
823     info->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::info_toggled) );
824     beforeAfter->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::beforeAfterToggled) );
825     hidehp->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::hideHistoryActivated) );
826     tbRightPanel_1->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::tbRightPanel_1_toggled) );
827     // saveimgas->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::saveAsPressed) );
828     // queueimg->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::queueImgPressed) );
829     saveimgas->signal_button_release_event().connect_notify(sigc::mem_fun(*this, &EditorPanel::saveAsPressed));
830     queueimg->signal_button_release_event().connect_notify(sigc::mem_fun(*this, &EditorPanel::queueImgPressed));
831     sendtogimp->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::sendToGimpPressed) );
832     toggleHistogramProfile->signal_toggled().connect( sigc::mem_fun (*this, &EditorPanel::histogramProfile_toggled) );
833 
834     if (navPrev) {
835         navPrev->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::openPreviousEditorImage) );
836     }
837 
838     if (navNext) {
839         navNext->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::openNextEditorImage) );
840     }
841 
842     if (navSync) {
843         navSync->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::syncFileBrowser) );
844     }
845 
846     ShowHideSidePanelsconn = tbShowHideSidePanels->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::toggleSidePanels), true);
847 
848     if (tbTopPanel_1) {
849         tbTopPanel_1->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::tbTopPanel_1_toggled) );
850     }
851 }
852 
853 
~EditorPanel()854 EditorPanel::~EditorPanel ()
855 {
856     if (autosave_conn_.connected()) {
857         autosave_conn_.disconnect();
858     }
859 
860     idle_register.destroy();
861 
862     history->setHistoryBeforeAfterListener (nullptr);
863     // the order is important!
864 
865     iareapanel->setBeforeAfterViews (nullptr, iareapanel);
866     delete iareapanel;
867     iareapanel = nullptr;
868 
869     if (beforeIpc) {
870         beforeIpc->stopProcessing ();
871     }
872 
873     delete beforeIarea;
874     beforeIarea = nullptr;
875 
876     if (beforeIpc) {
877         beforeIpc->setPreviewImageListener (nullptr);
878     }
879 
880     delete beforePreviewHandler;
881     beforePreviewHandler = nullptr;
882 
883     if (beforeIpc) {
884         rtengine::StagedImageProcessor::destroy (beforeIpc);
885     }
886 
887     beforeIpc = nullptr;
888 
889     close ();
890 
891     if (epih->pending) {
892         epih->destroyed = true;
893     } else {
894         delete epih;
895     }
896 
897     delete tpc;
898 
899     delete ppframe;
900     delete leftsubbox;
901     delete leftbox;
902     delete vsubboxright;
903     delete vboxright;
904 
905     //delete saveAsDialog;
906     if (catalogPane) {
907         delete catalogPane;
908     }
909 
910     if (iTopPanel_1_Show) {
911         delete iTopPanel_1_Show;
912     }
913 
914     if (iTopPanel_1_Hide) {
915         delete iTopPanel_1_Hide;
916     }
917 
918     if (iHistoryShow) {
919         delete iHistoryShow;
920     }
921 
922     if (iHistoryHide) {
923         delete iHistoryHide;
924     }
925 
926     if (iBeforeLockON) {
927         delete iBeforeLockON;
928     }
929 
930     if (iBeforeLockOFF) {
931         delete iBeforeLockOFF;
932     }
933 
934     if (iRightPanel_1_Show) {
935         delete iRightPanel_1_Show;
936     }
937 
938     if (iRightPanel_1_Hide) {
939         delete iRightPanel_1_Hide;
940     }
941 }
942 
943 
cleanup()944 void EditorPanel::cleanup()
945 {
946     if (tpc) {
947         tpc->setEditProvider(nullptr);
948     }
949 }
950 
951 
leftPaneButtonReleased(GdkEventButton * event)952 void EditorPanel::leftPaneButtonReleased (GdkEventButton *event)
953 {
954     if (event->button == 1) {
955         // Button 1 released : it's a resize
956         options.historyPanelWidth = hpanedl->get_position();
957     }
958 
959     /*else if (event->button == 3) {
960     }*/
961 }
962 
rightPaneButtonReleased(GdkEventButton * event)963 void EditorPanel::rightPaneButtonReleased (GdkEventButton *event)
964 {
965     if (event->button == 1) {
966         int winW, winH;
967         parentWindow->get_size (winW, winH);
968         // Button 1 released : it's a resize
969         options.toolPanelWidth = winW - hpanedr->get_position();
970     }
971 
972     /*else if (event->button == 3) {
973     }*/
974 }
975 
writeOptions()976 void EditorPanel::writeOptions()
977 {
978     if (profilep) {
979         profilep->writeOptions();
980     }
981 
982     if (tpc) {
983         tpc->writeOptions();
984     }
985 }
986 
987 
writeToolExpandedStatus(std::vector<int> & tpOpen)988 void EditorPanel::writeToolExpandedStatus (std::vector<int> &tpOpen)
989 {
990     if (tpc) {
991         tpc->writeToolExpandedStatus (tpOpen);
992     }
993 }
994 
showTopPanel(bool show)995 void EditorPanel::showTopPanel (bool show)
996 {
997     if (tbTopPanel_1->get_active() != show) {
998         tbTopPanel_1->set_active (show);
999     }
1000 }
1001 
setAspect()1002 void EditorPanel::setAspect ()
1003 {
1004     int winW, winH;
1005     parentWindow->get_size (winW, winH);
1006     hpanedl->set_position (options.historyPanelWidth);
1007     hpanedr->set_position (winW - options.toolPanelWidth);
1008 
1009     // initialize components
1010     if (info->get_active() != options.showInfo) {
1011         info->set_active (options.showInfo);
1012     }
1013 }
1014 
on_realize()1015 void EditorPanel::on_realize ()
1016 {
1017     realized = true;
1018     Gtk::VBox::on_realize ();
1019     // This line is needed to avoid autoexpansion of the window :-/
1020     //vboxright->set_size_request (options.toolPanelWidth, -1);
1021     tpc->updateToolState();
1022 }
1023 
open(Thumbnail * tmb,rtengine::InitialImage * isrc)1024 void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc)
1025 {
1026     thumbImageUpdater->slowDown();
1027     previewLoader->slowDown();
1028 
1029     close();
1030 
1031     isProcessing = true; // prevents closing-on-init
1032 
1033     // initialize everything
1034     openThm = tmb;
1035     openThm->increaseRef ();
1036 
1037     fname = openThm->getFileName();
1038     lastSaveAsFileName = removeExtension (Glib::path_get_basename (fname));
1039 
1040     previewHandler = new PreviewHandler ();
1041 
1042     this->isrc = isrc;
1043     ipc = rtengine::StagedImageProcessor::create (isrc);
1044     ipc->setProgressListener (this);
1045     colorMgmtToolBar->updateProcessor();
1046     ipc->setPreviewImageListener (previewHandler);
1047     ipc->setPreviewScale (10);  // Important
1048     tpc->initImage (ipc, tmb->getType() == FT_Raw);
1049     ipc->setHistogramListener (this);
1050     iareapanel->imageArea->indClippedPanel->silentlyDisableSharpMask();
1051     ipc->setSizeListener(this);
1052 
1053 //    iarea->fitZoom ();   // tell to the editorPanel that the next image has to be fitted to the screen
1054     iareapanel->imageArea->setPreviewHandler (previewHandler);
1055     iareapanel->imageArea->setImProcCoordinator (ipc);
1056     navigator->previewWindow->setPreviewHandler (previewHandler);
1057     navigator->previewWindow->setImageArea (iareapanel->imageArea);
1058 
1059     rtengine::ImageSource* is = isrc->getImageSource();
1060     is->setProgressListener ( this );
1061 
1062     // try to load the last saved parameters from the cache or from the paramfile file
1063     std::unique_ptr<ProcParams> ldprof(openThm->createProcParamsForUpdate (true, false)); // will be freed by initProfile
1064 
1065     // initialize profile
1066     Glib::ustring defProf = openThm->getType() == FT_Raw ? options.defProfRaw : options.defProfImg;
1067     auto metadata = openThm->getMetaData();
1068     profilep->initProfile (defProf, ldprof.get(), metadata.get());
1069     profilep->setInitialFileName (fname);
1070 
1071     openThm->addThumbnailListener (this);
1072     info_toggled ();
1073 
1074     if (beforeIarea) {
1075         beforeAfterToggled();
1076         beforeAfterToggled();
1077     }
1078 
1079     // If in single tab mode, the main crop window is not constructed the very first time
1080     // since there was no resize event
1081     if (iareapanel->imageArea->mainCropWindow) {
1082         iareapanel->imageArea->mainCropWindow->cropHandler.newImage (ipc, false);
1083     } else {
1084         Gtk::Allocation alloc;
1085         iareapanel->imageArea->on_resized (alloc);
1086     }
1087 
1088     history->resetSnapShotNumber();
1089     navigator->setInvalid(ipc->getFullWidth(),ipc->getFullHeight());
1090 
1091     history->setPParamsSnapshotListener(openThm);
1092     history->setSnapshots(openThm->getProcParamsSnapshots());
1093     history->enableSnapshots(false);
1094 
1095     // When passing a photo as an argument to the RawTherapee executable, the user wants
1096     // this auto-loaded photo's thumbnail to be selected and visible in the Filmstrip.
1097     syncFileBrowser();
1098 
1099     if (options.sidecar_autosave_interval > 0) {
1100         autosave_conn_ = Glib::signal_timeout().connect(sigc::mem_fun(*this, &EditorPanel::autosave), options.sidecar_autosave_interval * 60000);
1101     }
1102 }
1103 
close()1104 void EditorPanel::close ()
1105 {
1106     if (ipc) {
1107         saveProfile ();
1108         // close image processor and the current thumbnail
1109         tpc->closeImage ();    // this call stops image processing
1110         tpc->writeOptions ();
1111         rtengine::ImageSource* is = isrc->getImageSource();
1112         is->setProgressListener ( nullptr );
1113 
1114         if (ipc) {
1115             ipc->setPreviewImageListener (nullptr);
1116         }
1117 
1118         if (beforeIpc) {
1119             beforeIpc->setPreviewImageListener (nullptr);
1120         }
1121 
1122         delete previewHandler;
1123         previewHandler = nullptr;
1124 
1125         if (iareapanel) {
1126             iareapanel->imageArea->setPreviewHandler (nullptr);
1127             iareapanel->imageArea->setImProcCoordinator (nullptr);
1128             iareapanel->imageArea->unsubscribe();
1129         }
1130 
1131         rtengine::StagedImageProcessor::destroy (ipc);
1132         ipc = nullptr;
1133         navigator->previewWindow->setPreviewHandler (nullptr);
1134 
1135         // If the file was deleted somewhere, the openThm.descreaseRef delete the object, but we don't know here
1136         if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) {
1137             openThm->removeThumbnailListener (this);
1138             openThm->decreaseRef ();
1139         }
1140     }
1141     openThm = nullptr;
1142 }
1143 
saveProfile()1144 void EditorPanel::saveProfile ()
1145 {
1146     if (!ipc || !openThm) {
1147         return;
1148     }
1149 
1150     if (autosave_conn_.connected()) {
1151         autosave_conn_.disconnect();
1152     }
1153 
1154     // If the file was deleted, do not generate ghost entries
1155     if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) {
1156         ProcParams params;
1157         ipc->getParams (&params);
1158 
1159         // Will call updateCache, which will update both the cached and sidecar files if necessary
1160         openThm->setProcParams(FullPartialProfile(params), EDITOR);
1161     }
1162 
1163     if (options.sidecar_autosave_interval > 0) {
1164         autosave_conn_ = Glib::signal_timeout().connect(sigc::mem_fun(*this, &EditorPanel::autosave), options.sidecar_autosave_interval * 60000);
1165     }
1166 }
1167 
getShortName()1168 Glib::ustring EditorPanel::getShortName ()
1169 {
1170     if (openThm) {
1171         return Glib::path_get_basename (openThm->getFileName ());
1172     } else {
1173         return "";
1174     }
1175 }
1176 
getFileName()1177 Glib::ustring EditorPanel::getFileName ()
1178 {
1179     if (openThm) {
1180         return openThm->getFileName ();
1181     } else {
1182         return "";
1183     }
1184 }
1185 
1186 // TODO!!!
procParamsChanged(const rtengine::procparams::ProcParams * params,const rtengine::ProcEvent & ev,const Glib::ustring & descr,const ParamsEdited * paramsEdited)1187 void EditorPanel::procParamsChanged(
1188     const rtengine::procparams::ProcParams* params,
1189     const rtengine::ProcEvent& ev,
1190     const Glib::ustring& descr,
1191     const ParamsEdited* paramsEdited
1192 )
1193 {
1194 
1195 //    if (ev!=EvPhotoLoaded)
1196 //        saveLabel->set_markup (Glib::ustring("<span foreground=\"#AA0000\" weight=\"bold\">") + M("MAIN_BUTTON_SAVE") + "</span>");
1197 
1198     rtengine::eSensorType sensorType = isrc->getImageSource()->getSensorType();
1199 
1200     selectedFrame = 0;
1201     if (sensorType == rtengine::ST_BAYER) {
1202         selectedFrame = params->raw.bayersensor.imageNum;
1203     //} else if (sensorType == rtengine::ST_FUJI_XTRANS) {
1204     //    selectedFrame = params->raw.xtranssensor.imageNum;
1205     }
1206     selectedFrame = rtengine::LIM<int>(selectedFrame, 0, isrc->getImageSource()->getMetaData()->getFrameCount() - 1);
1207 
1208     info_toggled();
1209 }
1210 
clearParamChanges()1211 void EditorPanel::clearParamChanges()
1212 {
1213 }
1214 
setProgress(double p)1215 void EditorPanel::setProgress(double p)
1216 {
1217     MyProgressBar* const pl = progressLabel;
1218 
1219     idle_register.add(
1220         [p, pl]() -> bool
1221         {
1222             setprogressStrUI(p, {}, pl);
1223             return false;
1224         }
1225     );
1226 }
1227 
setProgressStr(const Glib::ustring & str)1228 void EditorPanel::setProgressStr(const Glib::ustring& str)
1229 {
1230     MyProgressBar* const pl = progressLabel;
1231 
1232     idle_register.add(
1233         [str, pl]() -> bool
1234         {
1235             setprogressStrUI(-1.0, str, pl);
1236             return false;
1237         }, G_PRIORITY_LOW
1238     );
1239 }
1240 
setProgressState(bool inProcessing)1241 void EditorPanel::setProgressState(bool inProcessing)
1242 {
1243     epih->pending++;
1244 
1245     idle_register.add(
1246         [this, inProcessing]() -> bool
1247         {
1248             if (epih->destroyed)
1249             {
1250                 if (epih->pending == 1) {
1251                     delete epih;
1252                 } else {
1253                     --epih->pending;
1254                 }
1255 
1256                 return false;
1257             }
1258 
1259             epih->epanel->refreshProcessingState(inProcessing);
1260             --epih->pending;
1261 
1262             return false;
1263         }
1264     );
1265 }
1266 
error(const Glib::ustring & descr)1267 void EditorPanel::error(const Glib::ustring& descr)
1268 {
1269     parent->error(descr);
1270 }
1271 
error(const Glib::ustring & title,const Glib::ustring & descr)1272 void EditorPanel::error(const Glib::ustring& title, const Glib::ustring& descr)
1273 {
1274     epih->pending++;
1275 
1276     idle_register.add(
1277         [this, descr, title]() -> bool
1278         {
1279             if (epih->destroyed) {
1280                 if (epih->pending == 1) {
1281                     delete epih;
1282                 } else {
1283                     --epih->pending;
1284                 }
1285 
1286                 return false;
1287             }
1288 
1289             epih->epanel->displayError(title, descr);
1290             --epih->pending;
1291 
1292             return false;
1293         }
1294     );
1295 }
1296 
displayError(const Glib::ustring & title,const Glib::ustring & descr)1297 void EditorPanel::displayError(const Glib::ustring& title, const Glib::ustring& descr)
1298 {
1299     parent->error(title + ": " + descr);
1300     // GtkWidget* msgd = gtk_message_dialog_new_with_markup (nullptr,
1301     //                   GTK_DIALOG_DESTROY_WITH_PARENT,
1302     //                   GTK_MESSAGE_ERROR,
1303     //                   GTK_BUTTONS_OK,
1304     //                   "<b>%s</b>",
1305     //                   descr.data());
1306     // gtk_window_set_title ((GtkWindow*)msgd, title.data());
1307     // g_signal_connect_swapped (msgd, "response",
1308     //                           G_CALLBACK (gtk_widget_destroy),
1309     //                           msgd);
1310     // gtk_widget_show_all (msgd);
1311 }
1312 
1313 // This is only called from the ThreadUI, so within the gtk thread
refreshProcessingState(bool inProcessingP)1314 void EditorPanel::refreshProcessingState (bool inProcessingP)
1315 {
1316     double val;
1317     Glib::ustring str;
1318 
1319     if (inProcessingP) {
1320         if (processingStartedTime == 0) {
1321             processingStartedTime = ::time (nullptr);
1322         }
1323 
1324         val = 1.0;
1325         str = "PROGRESSBAR_PROCESSING";
1326     } else {
1327         // Set proc params of thumbnail. It saves it into the cache and updates the file browser.
1328         if (ipc && openThm && tpc->getChangedState()) {
1329             rtengine::procparams::ProcParams pparams;
1330             ipc->getParams (&pparams);
1331             openThm->setProcParams(pparams, EDITOR, false);
1332         }
1333 
1334         // Ring a sound if it was a long event
1335         if (processingStartedTime != 0) {
1336             time_t curTime = ::time (nullptr);
1337 
1338             if (::difftime (curTime, processingStartedTime) > options.sndLngEditProcDoneSecs) {
1339                 SoundManager::playSoundAsync (options.sndLngEditProcDone);
1340             }
1341 
1342             processingStartedTime = 0;
1343         }
1344 
1345         // Set progress bar "done"
1346         val = 0.0;
1347         str = "PROGRESSBAR_READY";
1348 
1349 #ifdef WIN32
1350 
1351         // Maybe accessing "parent", which is a Gtk object, can justify to get the Gtk lock...
1352         if (!firstProcessingDone && static_cast<RTWindow*> (parent)->getIsFullscreen()) {
1353             parent->fullscreen();
1354         }
1355 
1356 #endif
1357         firstProcessingDone = true;
1358 
1359         history->enableSnapshots(true);
1360     }
1361 
1362     isProcessing = inProcessingP;
1363 
1364     setprogressStrUI(val, str, progressLabel);
1365 }
1366 
info_toggled()1367 void EditorPanel::info_toggled ()
1368 {
1369 
1370     Glib::ustring infoString;
1371     Glib::ustring expcomp;
1372 
1373     if (!ipc || !openThm) {
1374         return;
1375     }
1376 
1377     const rtengine::FramesMetaData* idata = ipc->getInitialImage()->getMetaData();
1378 
1379     if (idata && idata->hasExif()) {
1380         infoString = Glib::ustring::compose ("%1 + %2\n<span size=\"small\">f/</span><span size=\"large\">%3</span>  <span size=\"large\">%4</span><span size=\"small\">s</span>  <span size=\"small\">%5</span><span size=\"large\">%6</span>  <span size=\"large\">%7</span><span size=\"small\">mm</span>",
1381                                               Glib::ustring (idata->getMake() + " " + idata->getModel()),
1382                                               Glib::ustring (idata->getLens()),
1383                                               Glib::ustring (idata->apertureToString (idata->getFNumber())),
1384                                               Glib::ustring (idata->shutterToString (idata->getShutterSpeed())),
1385                                               M ("QINFO_ISO"), idata->getISOSpeed(),
1386                                               Glib::ustring::format (std::setw (3), std::fixed, std::setprecision (2), idata->getFocalLen()));
1387 
1388         expcomp = Glib::ustring (idata->expcompToString (idata->getExpComp(), true)); // maskZeroexpcomp
1389 
1390         if (!expcomp.empty ()) {
1391             infoString = Glib::ustring::compose ("%1  <span size=\"large\">%2</span><span size=\"small\">EV</span>",
1392                                                   infoString,
1393                                                   expcomp /*Glib::ustring(idata->expcompToString(idata->getExpComp()))*/);
1394         }
1395 
1396         infoString = Glib::ustring::compose ("%1\n<span size=\"small\">%2</span><span>%3</span>",
1397                                               infoString,
1398                                               escapeHtmlChars (Glib::path_get_dirname (openThm->getFileName())) + G_DIR_SEPARATOR_S,
1399                                               escapeHtmlChars (Glib::path_get_basename (openThm->getFileName()))  );
1400 
1401         int ww = -1, hh = -1;
1402         //idata->getDimensions(ww, hh);
1403         if (ww <= 0) {
1404             ww = ipc->getFullWidth();
1405             hh = ipc->getFullHeight();
1406         }
1407 
1408         //megapixels
1409         infoString = Glib::ustring::compose ("%1\n<span size=\"small\">%2 MP (%3x%4)</span>",
1410                                              infoString,
1411                                              Glib::ustring::format (std::setw (4), std::fixed, std::setprecision (1), (float)ww * hh / 1000000),
1412                                              ww, hh);
1413 
1414         //adding special characteristics
1415         bool isHDR = idata->getHDR();
1416         bool isPixelShift = idata->getPixelShift();
1417         unsigned int numFrames = idata->getFrameCount();
1418         if (isHDR) {
1419             infoString = Glib::ustring::compose ("%1\n" + M("QINFO_HDR"), infoString, numFrames);
1420             if (numFrames == 1) {
1421                 int sampleFormat = idata->getSampleFormat();
1422                 infoString = Glib::ustring::compose ("%1 / %2", infoString, M(Glib::ustring::compose("SAMPLEFORMAT_%1", sampleFormat)));
1423             }
1424         } else if (isPixelShift) {
1425             infoString = Glib::ustring::compose ("%1\n" + M("QINFO_PIXELSHIFT"), infoString, numFrames);
1426         } else if (numFrames > 1) {
1427             infoString = Glib::ustring::compose ("%1\n" + M("QINFO_FRAMECOUNT"), infoString, numFrames);
1428         }
1429     } else {
1430         infoString = M ("QINFO_NOEXIF");
1431     }
1432 
1433     iareapanel->imageArea->setInfoText (infoString);
1434     iareapanel->imageArea->infoEnabled (info->get_active ());
1435 }
1436 
hideHistoryActivated()1437 void EditorPanel::hideHistoryActivated ()
1438 {
1439 
1440     removeIfThere (hpanedl, leftbox, false);
1441 
1442     if (hidehp->get_active()) {
1443         hpanedl->pack1 (*leftbox, false, false);
1444     }
1445 
1446     options.showHistory = hidehp->get_active();
1447 
1448     if (options.showHistory) {
1449         hidehp->set_image (*iHistoryHide);
1450     } else {
1451         hidehp->set_image (*iHistoryShow);
1452     }
1453 
1454     tbShowHideSidePanels_managestate();
1455 }
1456 
1457 
tbRightPanel_1_toggled()1458 void EditorPanel::tbRightPanel_1_toggled ()
1459 {
1460     /*
1461         removeIfThere (hpanedr, vboxright, false);
1462         if (tbRightPanel_1->get_active()){
1463             hpanedr->pack2(*vboxright, false, true);
1464             tbRightPanel_1->set_image (*iRightPanel_1_Hide);
1465         }
1466         else {
1467             tbRightPanel_1->set_image (*iRightPanel_1_Show);
1468         }
1469         tbShowHideSidePanels_managestate();
1470         */
1471     if (vboxright) {
1472         if (tbRightPanel_1->get_active()) {
1473             vboxright->show();
1474             tbRightPanel_1->set_image (*iRightPanel_1_Hide);
1475         } else {
1476             vboxright->hide();
1477             tbRightPanel_1->set_image (*iRightPanel_1_Show);
1478         }
1479 
1480         tbShowHideSidePanels_managestate();
1481     }
1482 }
1483 
tbTopPanel_1_visible(bool visible)1484 void EditorPanel::tbTopPanel_1_visible (bool visible)
1485 {
1486     if (!tbTopPanel_1) {
1487         return;
1488     }
1489 
1490     if (visible) {
1491         tbTopPanel_1->show();
1492     } else {
1493         tbTopPanel_1->hide();
1494     }
1495 }
1496 
tbTopPanel_1_toggled()1497 void EditorPanel::tbTopPanel_1_toggled ()
1498 {
1499 
1500     if (catalogPane) { // catalogPane does not exist in multitab mode
1501 
1502         if (tbTopPanel_1->get_active()) {
1503             catalogPane->show();
1504             tbTopPanel_1->set_image (*iTopPanel_1_Hide);
1505             options.editorFilmStripOpened = true;
1506         } else {
1507             catalogPane->hide();
1508             tbTopPanel_1->set_image (*iTopPanel_1_Show);
1509             options.editorFilmStripOpened = false;
1510         }
1511 
1512         tbShowHideSidePanels_managestate();
1513     }
1514 }
1515 
1516 /*
1517  * WARNING: Take care of the simpleEditor value when adding or modifying shortcut keys,
1518  *          since handleShortcutKey is now also triggered in simple editor mode
1519  */
handleShortcutKey(GdkEventKey * event)1520 bool EditorPanel::handleShortcutKey (GdkEventKey* event)
1521 {
1522 
1523     bool ctrl = event->state & GDK_CONTROL_MASK;
1524     bool shift = event->state & GDK_SHIFT_MASK;
1525     bool alt = event->state & GDK_MOD1_MASK;
1526 #ifdef __WIN32__
1527     bool altgr = event->state & GDK_MOD2_MASK;
1528 #else
1529     bool altgr = event->state & GDK_MOD5_MASK;
1530 #endif
1531 
1532     // Editor Layout
1533     switch (event->keyval) {
1534         case GDK_KEY_L:
1535             if (tbTopPanel_1) {
1536                 tbTopPanel_1->set_active (!tbTopPanel_1->get_active());    // toggle top panel
1537             }
1538 
1539             return true;
1540             break;
1541 
1542         case GDK_KEY_l:
1543             if (alt) { // toggle left and right panels
1544                 hidehp->set_active (!hidehp->get_active());
1545                 tbRightPanel_1->set_active (!tbRightPanel_1->get_active());
1546             } else if (ctrl) { // toggle right panel
1547                 tbRightPanel_1->set_active (!tbRightPanel_1->get_active());
1548             } else {
1549                 hidehp->set_active (!hidehp->get_active()); // toggle History (left panel)
1550             }
1551             return true;
1552 
1553             break;
1554 
1555         case GDK_KEY_m: // Maximize preview panel: hide top AND right AND history panels
1556             if (!ctrl && !alt) {
1557                 toggleSidePanels();
1558                 return true;
1559             }
1560 
1561             break;
1562 
1563         case GDK_KEY_M: // Maximize preview panel: hide top AND right AND history panels AND (fit image preview)
1564             if (!ctrl && !alt) {
1565                 toggleSidePanelsZoomFit();
1566                 return true;
1567             }
1568 
1569             break;
1570     }
1571 
1572 #ifdef __WIN32__
1573 
1574     if (!alt && !ctrl && !altgr && event->hardware_keycode == 0x39 ) {
1575         iareapanel->imageArea->previewModePanel->togglebackColor();
1576         return true;
1577     }
1578 
1579 #else
1580 
1581     if (!alt && !ctrl && !altgr && event->hardware_keycode == 0x12 ) {
1582         iareapanel->imageArea->previewModePanel->togglebackColor();
1583         return true;
1584     }
1585 
1586 #endif
1587 
1588     if (!alt) {
1589         if (!ctrl) {
1590             // Normal
1591             switch (event->keyval) {
1592                 case GDK_KEY_bracketright:
1593                     tpc->coarse->rotateRight();
1594                     return true;
1595 
1596                 case GDK_KEY_bracketleft:
1597                     tpc->coarse->rotateLeft();
1598                     return true;
1599 
1600                 case GDK_KEY_i:
1601                 case GDK_KEY_I:
1602                     info->set_active (!info->get_active());
1603                     return true;
1604 
1605                 case GDK_KEY_B:
1606                     beforeAfter->set_active (!beforeAfter->get_active());
1607                     return true;
1608 
1609                 case GDK_KEY_plus:
1610                 case GDK_KEY_equal:
1611                 case GDK_KEY_KP_Add:
1612                     iareapanel->imageArea->zoomPanel->zoomInClicked();
1613                     return true;
1614 
1615                 case GDK_KEY_minus:
1616                 case GDK_KEY_underscore:
1617                 case GDK_KEY_KP_Subtract:
1618                     iareapanel->imageArea->zoomPanel->zoomOutClicked();
1619                     return true;
1620 
1621                 case GDK_KEY_z://GDK_1
1622                     iareapanel->imageArea->zoomPanel->zoom11Clicked();
1623                     return true;
1624 
1625                 /*
1626                 #ifndef __WIN32__
1627                                 case GDK_KEY_9: // toggle background color of the preview
1628                                     iareapanel->imageArea->previewModePanel->togglebackColor();
1629                                     return true;
1630                 #endif
1631                 */
1632                 case GDK_KEY_r: //preview mode Red
1633                     iareapanel->imageArea->previewModePanel->toggleR();
1634                     return true;
1635 
1636                 case GDK_KEY_g: //preview mode Green
1637                     iareapanel->imageArea->previewModePanel->toggleG();
1638                     return true;
1639 
1640                 case GDK_KEY_b: //preview mode Blue
1641                     iareapanel->imageArea->previewModePanel->toggleB();
1642                     return true;
1643 
1644                 case GDK_KEY_P: //preview mode Sharpening Contrast mask
1645                     iareapanel->imageArea->indClippedPanel->toggleSharpMask();
1646                     return true;
1647 
1648                 case GDK_KEY_v: //preview mode Luminosity
1649                     iareapanel->imageArea->previewModePanel->toggleL();
1650                     return true;
1651 
1652                 case GDK_KEY_F: //preview mode Focus Mask
1653                     iareapanel->imageArea->indClippedPanel->toggleFocusMask();
1654                     return true;
1655 
1656                 case GDK_KEY_e: // preview mode false colors
1657                     iareapanel->imageArea->indClippedPanel->toggleFalseColors();
1658                     return true;
1659 
1660                 case GDK_KEY_less:
1661                     iareapanel->imageArea->indClippedPanel->toggleClipped (false);
1662                     return true;
1663 
1664                 case GDK_KEY_greater:
1665                     iareapanel->imageArea->indClippedPanel->toggleClipped (true);
1666                     return true;
1667 
1668                 case GDK_KEY_f:
1669                     iareapanel->imageArea->zoomPanel->zoomFitClicked();
1670                     return true;
1671 
1672                 case GDK_KEY_y: // synchronize filebrowser with image in Editor
1673                     if (!simpleEditor && fPanel && !fname.empty()) {
1674                         fPanel->fileCatalog->selectImage (fname, false);
1675                         return true;
1676                     }
1677 
1678                     break; // to avoid gcc complain
1679 
1680                 case GDK_KEY_x: // clear filters and synchronize filebrowser with image in Editor
1681                     if (!simpleEditor && fPanel && !fname.empty()) {
1682                         fPanel->fileCatalog->selectImage (fname, true);
1683                         return true;
1684                     }
1685 
1686                     break; // to avoid gcc complain
1687             }
1688         } else {
1689             // With control
1690             switch (event->keyval) {
1691                 case GDK_KEY_S:
1692                     if (!gimpPlugin) {
1693                         do_save_image(true);
1694                     }
1695                     // saveProfile();
1696                     // setProgressStr (M ("PROGRESSBAR_PROCESSING_PROFILESAVED"));
1697                     return true;
1698 
1699                 case GDK_KEY_s:
1700                     if (!gimpPlugin) {
1701                         do_save_image(false);
1702                     }
1703 
1704                     return true;
1705 
1706                 case GDK_KEY_b:
1707                 case GDK_KEY_B:
1708                     if (!simpleEditor && catalogPane && catalogPane->is_visible() && fPanel->fileCatalog->isSelected(fname)) {
1709                         // propagate this to fPanel, so that if there is a
1710                         // multiple selection all the selected thumbs get
1711                         // enqueued
1712                     } else if (!gimpPlugin && !simpleEditor) {
1713                         do_queue_image(event->keyval == GDK_KEY_B);
1714                         return true;
1715                     }
1716                     break;
1717 
1718                 case GDK_KEY_e:
1719                     if (!gimpPlugin) {
1720                         sendToGimpPressed();
1721                     }
1722 
1723                     return true;
1724 
1725                 case GDK_KEY_z:
1726                     history->undo ();
1727                     return true;
1728 
1729                 case GDK_KEY_Z:
1730                 case GDK_KEY_y:
1731                     history->redo ();
1732                     return true;
1733             }
1734         } //if (!ctrl)
1735     } //if (!alt)
1736 
1737     if (alt) {
1738         switch (event->keyval) {
1739             case GDK_KEY_s:
1740                 history->addBookmarkPressed ();
1741                 setProgressStr (M ("PROGRESSBAR_SNAPSHOT_ADDED"));
1742                 return true;
1743 
1744             // case GDK_KEY_f:
1745             //     iareapanel->imageArea->zoomPanel->zoomFitClicked();
1746             //     return true;
1747         }
1748     }
1749 
1750     if (shift) {
1751         switch (event->keyval) {
1752             case GDK_KEY_F3: // open Previous image from Editor's perspective
1753                 if (!simpleEditor && fPanel && !fname.empty()) {
1754                     EditorPanel::openPreviousEditorImage();
1755                     return true;
1756                 }
1757 
1758                 break; // to avoid gcc complain
1759 
1760             case GDK_KEY_F4: // open next image from Editor's perspective
1761                 if (!simpleEditor && fPanel && !fname.empty()) {
1762                     EditorPanel::openNextEditorImage();
1763                     return true;
1764                 }
1765 
1766                 break; // to avoid gcc complain
1767         }
1768     }
1769 
1770     if (tpc->getToolBar() && tpc->getToolBar()->handleShortcutKey (event)) {
1771         return true;
1772     }
1773 
1774     if (tpc->handleShortcutKey (event)) {
1775         return true;
1776     }
1777 
1778     if (!simpleEditor && fPanel) {
1779         if (fPanel->handleShortcutKey (event)) {
1780             return true;
1781         }
1782     }
1783 
1784     return false;
1785 }
1786 
procParamsChanged(Thumbnail * thm,int whoChangedIt)1787 void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt)
1788 {
1789 
1790     if (whoChangedIt != EDITOR) {
1791         const auto &pp = openThm->getProcParams();
1792         rtengine::procparams::FullPartialProfile fp(pp);
1793         tpc->profileChange (&fp, rtengine::EvProfileChangeNotification, M ("PROGRESSDLG_PROFILECHANGEDINBROWSER"));
1794     }
1795 }
1796 
idle_saveImage(ProgressConnector<rtengine::IImagefloat * > * pc,Glib::ustring fname,SaveFormat sf,rtengine::procparams::ProcParams & pparams)1797 bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImagefloat*> *pc, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams)
1798 {
1799     rtengine::IImagefloat* img = pc->returnValue();
1800     delete pc;
1801 
1802     if (img) {
1803         setProgressStr (M ("GENERAL_SAVE"));
1804         setProgress (0.9f);
1805 
1806         ProgressConnector<int> *ld = new ProgressConnector<int>();
1807         img->setSaveProgressListener (parent->getProgressListener());
1808 
1809         if (sf.format == "tif") {
1810             ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fname, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed),
1811                            sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
1812         } else if (sf.format == "png") {
1813             ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsPNG), fname, sf.pngBits),
1814                            sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
1815         } else if (sf.format == "jpg") {
1816             ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsJPEG), fname, sf.jpegQuality, sf.jpegSubSamp),
1817                            sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
1818         } else {
1819             //delete ld;
1820             const auto do_save =
1821                 [=]() -> int
1822                 {
1823                     return rtengine::ImageIOManager::getInstance()->save(img, sf.format, fname, this) ? 0 : 1;
1824                 };
1825             ld->startFunc(sigc::slot0<int>(do_save),
1826                           sigc::bind(sigc::mem_fun(*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
1827         }
1828     } else {
1829         Glib::ustring msg_ = Glib::ustring ("<b>") + fname + ": Error during image processing\n</b>";
1830         Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
1831         msgd.run ();
1832 
1833         saveimgas->set_sensitive (true);
1834         sendtogimp->set_sensitive (true);
1835         isProcessing = false;
1836 
1837     }
1838 
1839     rtengine::ImageSource* imgsrc = isrc->getImageSource ();
1840     imgsrc->setProgressListener (this);
1841     return false;
1842 }
1843 
idle_imageSaved(ProgressConnector<int> * pc,rtengine::IImagefloat * img,Glib::ustring fname,SaveFormat sf,rtengine::procparams::ProcParams & pparams)1844 bool EditorPanel::idle_imageSaved (ProgressConnector<int> *pc, rtengine::IImagefloat* img, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams)
1845 {
1846     img->free ();
1847 
1848     if (! pc->returnValue() ) {
1849         openThm->imageDeveloped ();
1850 
1851         // save processing parameters, if needed
1852         if (sf.saveParams) {
1853             // We keep the extension to avoid overwriting the profile when we have
1854             // the same output filename with different extension
1855             auto sidecar = fname + ".out" + paramFileExtension;
1856             if (!options.params_out_embed) {
1857                 pparams.save(parent, sidecar);
1858             } else if (pparams.saveEmbedded(parent, fname) != 0) {
1859                 parent->error(Glib::ustring::compose(M("PROCPARAMS_EMBEDDED_SAVE_WARNING"), fname, sidecar));
1860                 pparams.save(parent, sidecar);
1861             }
1862         }
1863     } else {
1864         error (M ("MAIN_MSG_CANNOTSAVE"), fname);
1865     }
1866 
1867     saveimgas->set_sensitive (true);
1868     sendtogimp->set_sensitive (true);
1869 
1870     parent->setProgressStr ("");
1871     parent->setProgress (0.);
1872 
1873     setProgressState (false);
1874 
1875     delete pc;
1876     SoundManager::playSoundAsync (options.sndBatchQueueDone);
1877     isProcessing = false;
1878     return false;
1879 }
1880 
1881 
createBatchQueueEntry(bool fast_export)1882 BatchQueueEntry* EditorPanel::createBatchQueueEntry(bool fast_export)
1883 {
1884     rtengine::procparams::ProcParams pparams;
1885     ipc->getParams (&pparams);
1886     // rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (openThm->getFileName (), openThm->getType() == FT_Raw, pparams);
1887     rtengine::ProcessingJob* job = create_processing_job(openThm->getFileName(), openThm->getType() == FT_Raw, pparams, fast_export);
1888     int fullW = 0, fullH = 0;
1889     isrc->getImageSource()->getFullSize (fullW, fullH, pparams.coarse.rotate == 90 || pparams.coarse.rotate == 270 ? TR_R90 : TR_NONE);
1890     int prevh = BatchQueue::calcMaxThumbnailHeight();
1891     int prevw = int ((size_t)fullW * (size_t)prevh / (size_t)fullH);
1892     return new BatchQueueEntry (job, pparams, openThm->getFileName(), prevw, prevh, openThm);
1893 }
1894 
1895 
saveAsPressed(GdkEventButton * event)1896 void EditorPanel::saveAsPressed(GdkEventButton *event)
1897 {
1898     do_save_image(event->state & GDK_CONTROL_MASK);
1899 }
1900 
1901 
do_save_image(bool fast_export)1902 void EditorPanel::do_save_image(bool fast_export)
1903 {
1904     if (!ipc || !openThm) {
1905         return;
1906     }
1907 
1908     bool fnameOK = false;
1909     Glib::ustring fnameOut;
1910 
1911     SaveAsDialog* saveAsDialog;
1912     auto toplevel = static_cast<Gtk::Window*> (get_toplevel ());
1913 
1914     if (Glib::file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR)) {
1915         saveAsDialog = new SaveAsDialog (options.lastSaveAsPath, toplevel);
1916     } else {
1917         saveAsDialog = new SaveAsDialog (PlacesBrowser::userPicturesDir (), toplevel);
1918     }
1919 
1920     saveAsDialog->set_default_size (options.saveAsDialogWidth, options.saveAsDialogHeight);
1921     saveAsDialog->setInitialFileName (lastSaveAsFileName);
1922     saveAsDialog->setImagePath (fname);
1923 
1924     do {
1925         int result = saveAsDialog->run ();
1926 
1927         // The SaveAsDialog ensure that a filename has been specified
1928         fnameOut = saveAsDialog->getFileName ();
1929 
1930         options.lastSaveAsPath = saveAsDialog->getDirectory ();
1931         saveAsDialog->get_size (options.saveAsDialogWidth, options.saveAsDialogHeight);
1932         options.autoSuffix = saveAsDialog->getAutoSuffix ();
1933         options.saveMethodNum = saveAsDialog->getSaveMethodNum ();
1934         lastSaveAsFileName = Glib::path_get_basename (removeExtension (fnameOut));
1935         SaveFormat sf = saveAsDialog->getFormat ();
1936         options.saveFormat = sf;
1937         options.forceFormatOpts = saveAsDialog->getForceFormatOpts ();
1938 
1939         if (result != Gtk::RESPONSE_OK) {
1940             break;
1941         }
1942 
1943         if (saveAsDialog->getImmediately ()) {
1944             // separate filename and the path to the destination directory
1945             Glib::ustring dstdir = Glib::path_get_dirname (fnameOut);
1946             Glib::ustring dstfname = Glib::path_get_basename (removeExtension (fnameOut));
1947             Glib::ustring dstext = getExtension (fnameOut);
1948 
1949             if (saveAsDialog->getAutoSuffix()) {
1950 
1951                 Glib::ustring fnameTemp;
1952 
1953                 for (int tries = 0; tries < 100; tries++) {
1954                     if (tries == 0) {
1955                         fnameTemp = Glib::ustring::compose ("%1.%2", Glib::build_filename (dstdir,  dstfname), dstext);
1956                     } else {
1957                         fnameTemp = Glib::ustring::compose ("%1-%2.%3", Glib::build_filename (dstdir,  dstfname), tries, dstext);
1958                     }
1959 
1960                     if (!Glib::file_test (fnameTemp, Glib::FILE_TEST_EXISTS)) {
1961                         fnameOut = fnameTemp;
1962                         fnameOK = true;
1963                         break;
1964                     }
1965                 }
1966             }
1967 
1968             // check if it exists
1969             if (!fnameOK) {
1970                 fnameOK = confirmOverwrite (*saveAsDialog, fnameOut);
1971             }
1972 
1973             if (fnameOK) {
1974                 isProcessing = true;
1975                 // save image
1976                 rtengine::procparams::ProcParams pparams;
1977                 ipc->getParams (&pparams);
1978                 rtengine::ProcessingJob *job = create_processing_job(ipc->getInitialImage(), pparams, fast_export);
1979 
1980                 ProgressConnector<rtengine::IImagefloat*> *ld = new ProgressConnector<rtengine::IImagefloat*>();
1981                 ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
1982                                sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_saveImage ), ld, fnameOut, sf, pparams));
1983                 saveimgas->set_sensitive (false);
1984                 sendtogimp->set_sensitive (false);
1985             }
1986         } else {
1987             BatchQueueEntry* bqe = createBatchQueueEntry(fast_export);
1988             bqe->outFileName = fnameOut;
1989             bqe->saveFormat = saveAsDialog->getFormat ();
1990             bqe->forceFormatOpts = saveAsDialog->getForceFormatOpts ();
1991             parent->addBatchQueueJob (bqe, saveAsDialog->getToHeadOfQueue ());
1992             fnameOK = true;
1993         }
1994 
1995         // ask parent to redraw file browser
1996         // ... or does it automatically when the tab is switched to it
1997     } while (!fnameOK);
1998 
1999     saveAsDialog->hide();
2000 
2001     delete saveAsDialog;
2002 }
2003 
2004 
queueImgPressed(GdkEventButton * event)2005 void EditorPanel::queueImgPressed(GdkEventButton *event)
2006 {
2007     do_queue_image(event->state & GDK_CONTROL_MASK);
2008 }
2009 
2010 
do_queue_image(bool fast_export)2011 void EditorPanel::do_queue_image(bool fast_export)
2012 {
2013     if (!ipc || !openThm) {
2014         return;
2015     }
2016 
2017     saveProfile();
2018     parent->addBatchQueueJob(createBatchQueueEntry(fast_export));
2019 }
2020 
sendToGimpPressed()2021 void EditorPanel::sendToGimpPressed ()
2022 {
2023     if (!ipc || !openThm) {
2024         return;
2025     }
2026 
2027     // develop image
2028     rtengine::procparams::ProcParams pparams;
2029     ipc->getParams (&pparams);
2030     if (options.editor_bypass_output_profile) {
2031         pparams.icm.outputProfile = rtengine::procparams::ColorManagementParams::NoProfileString;
2032     }
2033     rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
2034     ProgressConnector<rtengine::IImagefloat*> *ld = new ProgressConnector<rtengine::IImagefloat*>();
2035     ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
2036                    sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_sendToGimp ), ld, openThm->getFileName() ));
2037     saveimgas->set_sensitive (false);
2038     sendtogimp->set_sensitive (false);
2039 }
2040 
2041 
saveImmediately(const Glib::ustring & filename,const SaveFormat & sf)2042 bool EditorPanel::saveImmediately (const Glib::ustring &filename, const SaveFormat &sf)
2043 {
2044     rtengine::procparams::ProcParams pparams;
2045     ipc->getParams (&pparams);
2046 
2047     rtengine::ProcessingJob *job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
2048 
2049     // save immediately
2050     rtengine::IImagefloat *img = rtengine::processImage (job, err, nullptr, false);
2051     if (img) {
2052         img->setSaveProgressListener(parent);
2053     }
2054 
2055     int err = 0;
2056 
2057     if (gimpPlugin) {
2058         err = img->saveAsTIFF (filename, 32, true, true);
2059     } else if (sf.format == "tif") {
2060         err = img->saveAsTIFF (filename, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed);
2061     } else if (sf.format == "png") {
2062         err = img->saveAsPNG (filename, sf.pngBits);
2063     } else if (sf.format == "jpg") {
2064         err = img->saveAsJPEG (filename, sf.jpegQuality, sf.jpegSubSamp);
2065     } else {
2066         err = rtengine::ImageIOManager::getInstance()->save(img, sf.format, filename, this) ? 0 : 1;
2067     }
2068 
2069     img->free();
2070     return !err;
2071 }
2072 
2073 
openPreviousEditorImage()2074 void EditorPanel::openPreviousEditorImage()
2075 {
2076     if (!simpleEditor && fPanel && !fname.empty()) {
2077         fPanel->fileCatalog->openNextPreviousEditorImage (fname, false, NAV_PREVIOUS);
2078     }
2079 }
2080 
openNextEditorImage()2081 void EditorPanel::openNextEditorImage()
2082 {
2083     if (!simpleEditor && fPanel && !fname.empty()) {
2084         fPanel->fileCatalog->openNextPreviousEditorImage (fname, false, NAV_NEXT);
2085     }
2086 }
2087 
syncFileBrowser()2088 void EditorPanel::syncFileBrowser()   // synchronize filebrowser with image in Editor
2089 {
2090     if (!simpleEditor && fPanel && !fname.empty()) {
2091         fPanel->fileCatalog->selectImage (fname, false);
2092     }
2093 }
2094 
histogramProfile_toggled()2095 void EditorPanel::histogramProfile_toggled()
2096 {
2097     options.rtSettings.HistogramWorking = toggleHistogramProfile->get_active();
2098     colorMgmtToolBar->updateHistogram();
2099 }
2100 
idle_sendToGimp(ProgressConnector<rtengine::IImagefloat * > * pc,Glib::ustring fname)2101 bool EditorPanel::idle_sendToGimp ( ProgressConnector<rtengine::IImagefloat*> *pc, Glib::ustring fname)
2102 {
2103 
2104     rtengine::IImagefloat* img = pc->returnValue();
2105     delete pc;
2106 
2107     if (img) {
2108         // get file name base
2109         Glib::ustring shortname = removeExtension(Glib::path_get_basename(fname));
2110         Glib::ustring dirname;
2111         switch (options.editor_out_dir) {
2112         case Options::EDITOR_OUT_DIR_CURRENT:
2113             dirname = Glib::path_get_dirname(fname);
2114             break;
2115         case Options::EDITOR_OUT_DIR_CUSTOM:
2116             dirname = options.editor_custom_out_dir;
2117             break;
2118         default: // Options::EDITOR_OUT_DIR_TEMP
2119             dirname = Glib::get_tmp_dir();
2120             break;
2121         }
2122         Glib::ustring fname = Glib::build_filename(dirname, shortname);
2123 
2124         SaveFormat sf;
2125         sf.format = "tif";
2126         if (options.editor_float32) {
2127             sf.tiffBits = 32;
2128             sf.tiffFloat = true;
2129         } else {
2130             sf.tiffBits = 16;
2131             sf.tiffFloat = false;
2132         }
2133         sf.tiffUncompressed = true;
2134         sf.saveParams = true;
2135 
2136         Glib::ustring fileName = Glib::ustring::compose ("%1.%2", fname, sf.format);
2137 
2138         // TODO: Just list all file with a suitable name instead of brute force...
2139         int tries = 1;
2140 
2141         while (Glib::file_test (fileName, Glib::FILE_TEST_EXISTS) && tries < 1000) {
2142             fileName = Glib::ustring::compose ("%1-%2.%3", fname, tries, sf.format);
2143             tries++;
2144         }
2145 
2146         if (tries == 1000) {
2147             img->free ();
2148             return false;
2149         }
2150 
2151         ProgressConnector<int> *ld = new ProgressConnector<int>();
2152         img->setSaveProgressListener (parent->getProgressListener());
2153         ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fileName, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed),
2154                        sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_sentToGimp), ld, img, fileName));
2155     } else {
2156         Glib::ustring msg_ = Glib::ustring ("<b> Error during image processing\n</b>");
2157         Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
2158         msgd.run ();
2159         saveimgas->set_sensitive (true);
2160         sendtogimp->set_sensitive (true);
2161     }
2162 
2163     return false;
2164 }
2165 
idle_sentToGimp(ProgressConnector<int> * pc,rtengine::IImagefloat * img,Glib::ustring filename)2166 bool EditorPanel::idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImagefloat* img, Glib::ustring filename)
2167 {
2168     img->free ();
2169     int errore = pc->returnValue();
2170     setProgressState(false);
2171     delete pc;
2172 
2173     if (!errore) {
2174         saveimgas->set_sensitive (true);
2175         sendtogimp->set_sensitive (true);
2176         parent->setProgressStr ("");
2177         parent->setProgress (0.);
2178         bool success = false;
2179 
2180         if (options.editorToSendTo == 1) {
2181             success = ExtProg::openInGimp (filename);
2182         } else if (options.editorToSendTo == 2) {
2183             success = ExtProg::openInPhotoshop (filename);
2184         } else if (options.editorToSendTo == 3) {
2185             success = ExtProg::openInCustomEditor (filename);
2186         }
2187 
2188         if (!success) {
2189             Gtk::MessageDialog msgd (*parent, M ("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
2190             msgd.set_secondary_text (M ("MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY"));
2191             msgd.set_title (M ("MAIN_BUTTON_SENDTOEDITOR"));
2192             msgd.run ();
2193         }
2194     }
2195 
2196     return false;
2197 }
2198 
historyBeforeAfterChanged(const rtengine::procparams::ProcParams & params)2199 void EditorPanel::historyBeforeAfterChanged(const rtengine::procparams::ProcParams& params)
2200 {
2201 
2202     if (beforeIpc) {
2203         ProcParams* pparams = beforeIpc->beginUpdateParams ();
2204         *pparams = params;
2205         beforeIpc->endUpdateParams (rtengine::EvProfileChanged);  // starts the IPC processing
2206     }
2207 }
2208 
beforeAfterToggled()2209 void EditorPanel::beforeAfterToggled ()
2210 {
2211 
2212     if (!ipc) {
2213         return;
2214     }
2215 
2216     removeIfThere (beforeAfterBox,  beforeBox, false);
2217     removeIfThere (afterBox,  afterHeaderBox, false);
2218 
2219     if (beforeIarea) {
2220         if (beforeIpc) {
2221             beforeIpc->stopProcessing ();
2222         }
2223 
2224         iareapanel->setBeforeAfterViews (nullptr, iareapanel);
2225         iareapanel->imageArea->iLinkedImageArea = nullptr;
2226         delete beforeIarea;
2227         beforeIarea = nullptr;
2228 
2229         if (beforeIpc) {
2230             beforeIpc->setPreviewImageListener (nullptr);
2231         }
2232 
2233         delete beforePreviewHandler;
2234         beforePreviewHandler = nullptr;
2235 
2236         if (beforeIpc) {
2237             rtengine::StagedImageProcessor::destroy (beforeIpc);
2238         }
2239 
2240         beforeIpc = nullptr;
2241     }
2242 
2243     if (beforeAfter->get_active ()) {
2244 
2245         int errorCode = 0;
2246         rtengine::InitialImage *beforeImg = rtengine::InitialImage::load ( isrc->getImageSource ()->getFileName(),  openThm->getType() == FT_Raw, &errorCode, nullptr);
2247 
2248         if ( !beforeImg || errorCode ) {
2249             return;
2250         }
2251 
2252         beforeIarea = new ImageAreaPanel ();
2253 
2254         int HeaderBoxHeight = 17;
2255 
2256         beforeLabel = Gtk::manage (new Gtk::Label ());
2257         beforeLabel->set_markup (Glib::ustring ("<b>") + M ("GENERAL_BEFORE") + "</b>");
2258         tbBeforeLock = Gtk::manage (new Gtk::ToggleButton ());
2259         tbBeforeLock->set_relief(Gtk::RELIEF_NONE);
2260         tbBeforeLock->set_tooltip_markup (M ("MAIN_TOOLTIP_BEFOREAFTERLOCK"));
2261         tbBeforeLock->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::tbBeforeLock_toggled) );
2262         beforeHeaderBox = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_HORIZONTAL));
2263         beforeHeaderBox->get_style_context()->add_class("smallbuttonbox");
2264         beforeHeaderBox->pack_end (*tbBeforeLock, Gtk::PACK_SHRINK, 2);
2265         beforeHeaderBox->pack_end (*beforeLabel, Gtk::PACK_SHRINK, 2);
2266         beforeHeaderBox->set_size_request (0, HeaderBoxHeight);
2267 
2268         history->blistenerLock ? tbBeforeLock->set_image (*iBeforeLockON) : tbBeforeLock->set_image (*iBeforeLockOFF);
2269         tbBeforeLock->set_active (history->blistenerLock);
2270 
2271         beforeBox = Gtk::manage (new Gtk::VBox ());
2272         beforeBox->pack_start (*beforeHeaderBox, Gtk::PACK_SHRINK, 2);
2273         beforeBox->pack_start (*beforeIarea);
2274 
2275         afterLabel = Gtk::manage (new Gtk::Label ());
2276         afterLabel->set_markup (Glib::ustring ("<b>") + M ("GENERAL_AFTER") + "</b>");
2277         afterHeaderBox = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_HORIZONTAL));
2278         afterHeaderBox->set_size_request (0, HeaderBoxHeight);
2279         afterHeaderBox->pack_end (*afterLabel, Gtk::PACK_SHRINK, 2);
2280         afterBox->pack_start (*afterHeaderBox, Gtk::PACK_SHRINK, 2);
2281         afterBox->reorder_child (*afterHeaderBox, 0);
2282 
2283         beforeAfterBox->pack_start (*beforeBox);
2284         beforeAfterBox->reorder_child (*beforeBox, 0);
2285         beforeAfterBox->show_all ();
2286 
2287         beforePreviewHandler = new PreviewHandler ();
2288 
2289         beforeIpc = rtengine::StagedImageProcessor::create (beforeImg);
2290         beforeIpc->setPreviewScale (10);
2291         beforeIpc->setPreviewImageListener (beforePreviewHandler);
2292         Glib::ustring monitorProfile;
2293         rtengine::RenderingIntent intent;
2294         ipc->getMonitorProfile(monitorProfile, intent);
2295         beforeIpc->setMonitorProfile(monitorProfile, intent);
2296 
2297         beforeIarea->imageArea->setPreviewHandler (beforePreviewHandler);
2298         beforeIarea->imageArea->setImProcCoordinator (beforeIpc);
2299 
2300         beforeIarea->imageArea->setPreviewModePanel (iareapanel->imageArea->previewModePanel);
2301         beforeIarea->imageArea->setIndicateClippedPanel (iareapanel->imageArea->indClippedPanel);
2302         iareapanel->imageArea->iLinkedImageArea = beforeIarea->imageArea;
2303 
2304         iareapanel->setBeforeAfterViews (beforeIarea, iareapanel);
2305         beforeIarea->setBeforeAfterViews (beforeIarea, iareapanel);
2306 
2307         {
2308             auto cw = new CropWindow(beforeIarea->imageArea, false, false);
2309             cw->setDecorated(false);
2310             cw->setFitZoomEnabled(true);
2311             cw->addCropWindowListener(beforeIarea->imageArea);
2312             cw->setPosition(0, 0);
2313             cw->enable();
2314             cw->cropHandler.cropParams = iareapanel->imageArea->mainCropWindow->cropHandler.cropParams;
2315             beforeIarea->imageArea->mainCropWindow = cw;
2316         }
2317 
2318         rtengine::procparams::ProcParams params;
2319 
2320         if (history->getBeforeAfterParams(params)) {
2321             historyBeforeAfterChanged(params);
2322         }
2323     }
2324 }
2325 
tbBeforeLock_toggled()2326 void EditorPanel::tbBeforeLock_toggled ()
2327 {
2328     history->blistenerLock = tbBeforeLock->get_active();
2329     tbBeforeLock->get_active() ? tbBeforeLock->set_image (*iBeforeLockON) : tbBeforeLock->set_image (*iBeforeLockOFF);
2330 }
2331 
histogramChanged(const LUTu & histRed,const LUTu & histGreen,const LUTu & histBlue,const LUTu & histLuma,const LUTu & histToneCurve,const LUTu & histLCurve,const LUTu & histCCurve,const LUTu & histLCAM,const LUTu & histCCAM,const LUTu & histRedRaw,const LUTu & histGreenRaw,const LUTu & histBlueRaw,const LUTu & histChroma,const LUTu & histLRETI,int vectorscopeScale,const array2D<int> & vectorscopeHC,const array2D<int> & vectorscopeHS,int waveformScale,const array2D<int> & waveformRed,const array2D<int> & waveformGreen,const array2D<int> & waveformBlue,const array2D<int> & waveformLuma)2332 void EditorPanel::histogramChanged(
2333     const LUTu& histRed,
2334     const LUTu& histGreen,
2335     const LUTu& histBlue,
2336     const LUTu& histLuma,
2337     const LUTu& histToneCurve,
2338     const LUTu& histLCurve,
2339     const LUTu& histCCurve,
2340     const LUTu& histLCAM,
2341     const LUTu& histCCAM,
2342     const LUTu& histRedRaw,
2343     const LUTu& histGreenRaw,
2344     const LUTu& histBlueRaw,
2345     const LUTu& histChroma,
2346     const LUTu& histLRETI,
2347     int vectorscopeScale,
2348     const array2D<int>& vectorscopeHC,
2349     const array2D<int>& vectorscopeHS,
2350     int waveformScale,
2351     const array2D<int>& waveformRed,
2352     const array2D<int>& waveformGreen,
2353     const array2D<int>& waveformBlue,
2354     const array2D<int>& waveformLuma
2355 )
2356 {
2357     if (histogramPanel) {
2358         histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscopeHC, vectorscopeHS, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma);
2359     }
2360 
2361     tpc->updateCurveBackgroundHistogram(histToneCurve, histLCurve, histCCurve, histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma, histLRETI);
2362 }
2363 
setObservable(rtengine::HistogramObservable * observable)2364 void EditorPanel::setObservable(rtengine::HistogramObservable* observable)
2365 {
2366     histogram_observable = observable;
2367 }
2368 
updateHistogram() const2369 bool EditorPanel::updateHistogram() const
2370 {
2371     return histogram_scope_type == ScopeType::HISTOGRAM
2372         || histogram_scope_type == ScopeType::NONE;
2373 }
2374 
updateHistogramRaw() const2375 bool EditorPanel::updateHistogramRaw() const
2376 {
2377     return histogram_scope_type == ScopeType::HISTOGRAM_RAW
2378         || histogram_scope_type == ScopeType::NONE;
2379 }
2380 
updateVectorscopeHC() const2381 bool EditorPanel::updateVectorscopeHC() const
2382 {
2383     return
2384         histogram_scope_type == ScopeType::VECTORSCOPE_HC
2385         || histogram_scope_type == ScopeType::NONE;
2386 }
2387 
updateVectorscopeHS() const2388 bool EditorPanel::updateVectorscopeHS() const
2389 {
2390     return
2391         histogram_scope_type == ScopeType::VECTORSCOPE_HS
2392         || histogram_scope_type == ScopeType::NONE;
2393 }
2394 
updateWaveform() const2395 bool EditorPanel::updateWaveform() const
2396 {
2397     return histogram_scope_type == ScopeType::WAVEFORM
2398         || histogram_scope_type == ScopeType::PARADE
2399         || histogram_scope_type == ScopeType::NONE;
2400 }
2401 
2402 
scopeTypeChanged(ScopeType new_type)2403 void EditorPanel::scopeTypeChanged(ScopeType new_type)
2404 {
2405     histogram_scope_type = new_type;
2406 
2407     if (!histogram_observable) {
2408         return;
2409     }
2410 
2411     // Make sure the new scope is updated since we only actively update the
2412     // current scope.
2413     switch (new_type) {
2414         case ScopeType::HISTOGRAM:
2415             histogram_observable->requestUpdateHistogram();
2416             break;
2417         case ScopeType::HISTOGRAM_RAW:
2418             histogram_observable->requestUpdateHistogramRaw();
2419             break;
2420         case ScopeType::VECTORSCOPE_HC:
2421             histogram_observable->requestUpdateVectorscopeHC();
2422             break;
2423         case ScopeType::VECTORSCOPE_HS:
2424             histogram_observable->requestUpdateVectorscopeHS();
2425             break;
2426         case ScopeType::PARADE:
2427         case ScopeType::WAVEFORM:
2428             histogram_observable->requestUpdateWaveform();
2429             break;
2430         case ScopeType::NONE:
2431             break;
2432     }
2433 }
2434 
2435 
CheckSidePanelsVisibility()2436 bool EditorPanel::CheckSidePanelsVisibility()
2437 {
2438     if (tbTopPanel_1) {
2439         return tbTopPanel_1->get_active() || tbRightPanel_1->get_active() || hidehp->get_active();
2440     }
2441 
2442     return tbRightPanel_1->get_active() || hidehp->get_active();
2443 }
2444 
toggleSidePanels()2445 void EditorPanel::toggleSidePanels()
2446 {
2447     // Maximize preview panel:
2448     // toggle top AND right AND history panels
2449 
2450     bool bAllSidePanelsVisible;
2451     bAllSidePanelsVisible = CheckSidePanelsVisibility();
2452 
2453     if (tbTopPanel_1) {
2454         tbTopPanel_1->set_active (!bAllSidePanelsVisible);
2455     }
2456 
2457     tbRightPanel_1->set_active (!bAllSidePanelsVisible);
2458     hidehp->set_active (!bAllSidePanelsVisible);
2459 
2460     if (!bAllSidePanelsVisible) {
2461         tbShowHideSidePanels->set_image (*iShowHideSidePanels);
2462     } else {
2463         tbShowHideSidePanels->set_image (*iShowHideSidePanels_exit);
2464     }
2465 }
2466 
toggleSidePanelsZoomFit()2467 void EditorPanel::toggleSidePanelsZoomFit()
2468 {
2469     toggleSidePanels();
2470 
2471     // fit image preview
2472     // !!! TODO this does not want to work... seems to have an effect on a subsequent key press
2473     // iarea->imageArea->zoomPanel->zoomFitClicked();
2474 }
2475 
tbShowHideSidePanels_managestate()2476 void EditorPanel::tbShowHideSidePanels_managestate()
2477 {
2478     bool bAllSidePanelsVisible;
2479     bAllSidePanelsVisible = CheckSidePanelsVisibility();
2480     ShowHideSidePanelsconn.block (true);
2481 
2482     tbShowHideSidePanels->set_active (!bAllSidePanelsVisible);
2483 
2484     ShowHideSidePanelsconn.block (false);
2485 }
2486 
updateProfiles(const Glib::ustring & printerProfile,rtengine::RenderingIntent printerIntent,bool printerBPC)2487 void EditorPanel::updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC)
2488 {
2489 }
2490 
updateTPVScrollbar(bool hide)2491 void EditorPanel::updateTPVScrollbar (bool hide)
2492 {
2493     tpc->updateTPVScrollbar (hide);
2494 }
2495 
updateHistogramPosition(int oldPosition,int newPosition)2496 void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition)
2497 {
2498 
2499     switch (newPosition) {
2500         case 0:
2501 
2502             // No histogram
2503             if (!oldPosition) {
2504                 // An histogram actually exist, we delete it
2505                 delete histogramPanel;
2506                 histogramPanel = nullptr;
2507             }
2508 
2509             // else no need to create it
2510             break;
2511 
2512         case 1:
2513 
2514             // Histogram on the left pane
2515             if (oldPosition == 0) {
2516                 // There was no Histogram before, so we create it
2517                 histogramPanel = Gtk::manage (new HistogramPanel ());
2518                 leftbox->pack1(*histogramPanel, false, false);
2519             } else if (oldPosition == 2) {
2520                 // The histogram was on the right side, so we move it to the left
2521                 histogramPanel->reference();
2522                 removeIfThere (vboxright, histogramPanel, false);
2523                 leftbox->pack1(*histogramPanel, false, false);
2524                 histogramPanel->unreference();
2525             }
2526 
2527             leftbox->set_position(options.histogramHeight);
2528             histogramPanel->reorder (Gtk::POS_LEFT);
2529             break;
2530 
2531         case 2:
2532         default:
2533 
2534             // Histogram on the right pane
2535             if (oldPosition == 0) {
2536                 // There was no Histogram before, so we create it
2537                 histogramPanel = Gtk::manage (new HistogramPanel ());
2538                 vboxright->pack1 (*histogramPanel, false, false);
2539             } else if (oldPosition == 1) {
2540                 // The histogram was on the left side, so we move it to the right
2541                 histogramPanel->reference();
2542                 removeIfThere (leftbox, histogramPanel, false);
2543                 vboxright->pack1 (*histogramPanel, false, false);
2544                 histogramPanel->unreference();
2545             }
2546 
2547             vboxright->set_position(options.histogramHeight);
2548             histogramPanel->reorder (Gtk::POS_RIGHT);
2549             break;
2550     }
2551 
2552     if (histogramPanel) {
2553         histogramPanel->setPanelListener(this);
2554     }
2555 
2556     iareapanel->imageArea->setPointerMotionHListener (histogramPanel);
2557 
2558 }
2559 
2560 
defaultMonitorProfileChanged(const Glib::ustring & profile_name,bool auto_monitor_profile)2561 void EditorPanel::defaultMonitorProfileChanged (const Glib::ustring &profile_name, bool auto_monitor_profile)
2562 {
2563     colorMgmtToolBar->defaultMonitorProfileChanged (profile_name, auto_monitor_profile);
2564 }
2565 
2566 
autosave()2567 bool EditorPanel::autosave()
2568 {
2569     MyProgressBar* const pl = progressLabel;
2570     auto prev = pl->get_text();
2571     pl->set_text(M("MAIN_MSG_AUTOSAVING"));
2572     const auto doit =
2573         [pl, prev]() -> bool
2574         {
2575             pl->set_text(prev);
2576             return false;
2577         };
2578     Glib::signal_timeout().connect(sigc::slot<bool>(doit), 1000);
2579     saveProfile();
2580     return false;
2581 }
2582 
2583 
sizeChanged(int w,int h,int ow,int oh)2584 void EditorPanel::sizeChanged(int w, int h, int ow, int oh)
2585 {
2586     if (ipc) {
2587         idle_register.add(
2588             [this]() -> bool
2589             {
2590                 info_toggled();
2591                 navigator->setInvalid(ipc->getFullWidth(), ipc->getFullHeight());
2592                 return false;
2593             });
2594     }
2595 }
2596