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 (¶ms);
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