diff --git a/rtdata/languages/default b/rtdata/languages/default index e2152fb33..89bb6d2e3 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2539,9 +2539,11 @@ TP_FILMNEGATIVE_GUESS_TOOLTIP;Automatically set the red and blue ratios by picki TP_FILMNEGATIVE_LABEL;Film Negative TP_FILMNEGATIVE_OUT_LEVEL;Output level TP_FILMNEGATIVE_PICK;Pick neutral spots +TP_FILMNEGATIVE_PICK_SIZE;Size: TP_FILMNEGATIVE_RED;Red ratio TP_FILMNEGATIVE_REF_LABEL;Input RGB: %1 TP_FILMNEGATIVE_REF_PICK;Pick white balance spot +TP_FILMNEGATIVE_REF_SIZE;Size: TP_FILMNEGATIVE_REF_TOOLTIP;Pick a gray patch for white-balancing the output, positive image. TP_FILMSIMULATION_LABEL;Film Simulation TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now? diff --git a/rtgui/filmnegative.cc b/rtgui/filmnegative.cc index 39890babe..e9c9f4d4c 100644 --- a/rtgui/filmnegative.cc +++ b/rtgui/filmnegative.cc @@ -209,42 +209,18 @@ FilmNegative::FilmNegative() : greenExp(createExponentAdjuster(this, M("TP_FILMNEGATIVE_GREEN"), 0.3, 4, 0.01, 1.5)), // master exponent (green channel) redRatio(createExponentAdjuster(this, M("TP_FILMNEGATIVE_RED"), 0.3, 5, 0.01, (2.04 / 1.5))), // ratio of red exponent to master exponent blueRatio(createExponentAdjuster(this, M("TP_FILMNEGATIVE_BLUE"), 0.3, 5, 0.01, (1.29 / 1.5))), // ratio of blue exponent to master exponent - spotButton(Gtk::manage(new Gtk::ToggleButton(M("TP_FILMNEGATIVE_PICK")))), + picker(DEFAULT_SPOT_WIDTH, M("TP_FILMNEGATIVE_PICK"), M("TP_FILMNEGATIVE_GUESS_TOOLTIP"), M("TP_FILMNEGATIVE_PICK_SIZE")), refInputLabel(Gtk::manage(new Gtk::Label(Glib::ustring::compose(M("TP_FILMNEGATIVE_REF_LABEL"), "- - -")))), - refSpotButton(Gtk::manage(new Gtk::ToggleButton(M("TP_FILMNEGATIVE_REF_PICK")))), + refPicker(DEFAULT_SPOT_WIDTH, M("TP_FILMNEGATIVE_REF_PICK"), M("TP_FILMNEGATIVE_REF_TOOLTIP"), M("TP_FILMNEGATIVE_REF_SIZE")), + activePicker(&picker), outputLevel(createLevelAdjuster(this, M("TP_FILMNEGATIVE_OUT_LEVEL"))), // ref level greenBalance(createBalanceAdjuster(this, M("TP_FILMNEGATIVE_GREENBALANCE"), -3.0, 3.0, 0.0, "circle-magenta-small.png", "circle-green-small.png")), // green balance blueBalance(createBalanceAdjuster(this, M("TP_FILMNEGATIVE_BLUEBALANCE"), -3.0, 3.0, 0.0, "circle-blue-small.png", "circle-yellow-small.png")) // blue balance { - setExpandAlignProperties(spotButton, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - spotButton->get_style_context()->add_class("independent"); - spotButton->set_tooltip_text(M("TP_FILMNEGATIVE_GUESS_TOOLTIP")); - spotButton->set_image(*Gtk::manage(new RTImage("color-picker-small.png"))); - - refSpotButton->set_tooltip_text(M("TP_FILMNEGATIVE_REF_TOOLTIP")); - setExpandAlignProperties(refInputLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); // refInputLabel->set_justify(Gtk::Justification::JUSTIFY_CENTER); // refInputLabel->set_line_wrap(true); - // TODO make spot size configurable ? - - // Gtk::Label* slab = Gtk::manage (new Gtk::Label (M("TP_WBALANCE_SIZE"))); - // setExpandAlignProperties(slab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - - // Gtk::Grid* wbsizehelper = Gtk::manage(new Gtk::Grid()); - // wbsizehelper->set_name("WB-Size-Helper"); - // setExpandAlignProperties(wbsizehelper, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - - // spotsize = Gtk::manage (new MyComboBoxText ()); - // setExpandAlignProperties(spotsize, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - // spotsize->append ("2"); - // spotsize->set_active(0); - // spotsize->append ("4"); - - // spotgrid->attach(*spotButton, 0, 1, 1, 1); - // spotgrid->attach (*slab, 1, 0, 1, 1); - // spotgrid->attach (*wbsizehelper, 2, 0, 1, 1); colorSpace->append(M("TP_FILMNEGATIVE_COLORSPACE_INPUT")); colorSpace->append(M("TP_FILMNEGATIVE_COLORSPACE_WORKING")); @@ -265,9 +241,7 @@ FilmNegative::FilmNegative() : pack_start(*greenExp, Gtk::PACK_SHRINK, 0); pack_start(*redRatio, Gtk::PACK_SHRINK, 0); pack_start(*blueRatio, Gtk::PACK_SHRINK, 0); - pack_start(*spotButton, Gtk::PACK_SHRINK, 0); - -// pack_start(*oldMethod, Gtk::PACK_SHRINK, 0); + pack_start(picker, Gtk::PACK_SHRINK, 0); Gtk::Separator* const sep = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); sep->get_style_context()->add_class("grid-row-separator"); @@ -283,14 +257,13 @@ FilmNegative::FilmNegative() : pack_start(*blueBalance, Gtk::PACK_SHRINK, 0); pack_start(*greenBalance, Gtk::PACK_SHRINK, 0); - pack_start(*refSpotButton, Gtk::PACK_SHRINK, 0); + pack_start(refPicker, Gtk::PACK_SHRINK, 0); - spotButton->signal_toggled().connect(sigc::mem_fun(*this, &FilmNegative::editToggled)); - // spotsize->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::spotSizeChanged) ); - - refSpotButton->signal_toggled().connect(sigc::mem_fun(*this, &FilmNegative::refSpotToggled)); + picker.add_button_toggled_event(*this, &FilmNegative::editToggled); + refPicker.add_button_toggled_event(*this, &FilmNegative::refSpotToggled); // Editing geometry; create the spot rectangle + // TODO: Change behaviour to match that of the white balance spot picker (rectangle disappears behind right toolbar) EditRectangle* const spotRect = new EditRectangle(); spotRect->filled = false; @@ -455,8 +428,8 @@ void FilmNegative::setBatchMode(bool batchMode) ToolPanel::setBatchMode(batchMode); if (batchMode) { - removeIfThere(this, spotButton, false); - removeIfThere(this, refSpotButton, false); + picker.remove_if_there(this, false); + refPicker.remove_if_there(this, false); colorSpace->append(M("GENERAL_UNCHANGED")); colorSpace->set_active_text(M("GENERAL_UNCHANGED")); redRatio->showEditedCB(); @@ -565,7 +538,7 @@ bool FilmNegative::mouseOver(int modifierKey) { EditDataProvider* const provider = getEditProvider(); EditRectangle* const spotRect = static_cast(visibleGeometry.at(0)); - spotRect->setXYWH(provider->posImage.x - 16, provider->posImage.y - 16, 32, 32); + spotRect->setXYWH(provider->posImage.x - activePicker->get_spot_half_width(), provider->posImage.y - activePicker->get_spot_half_width() ,activePicker->get_spot_full_width(), activePicker->get_spot_full_width()); return true; } @@ -577,7 +550,7 @@ bool FilmNegative::button1Pressed(int modifierKey) EditSubscriber::action = EditSubscriber::Action::NONE; if (listener) { - if (spotButton->get_active()) { + if (picker.get_active()) { refSpotCoords.push_back(provider->posImage); @@ -587,8 +560,8 @@ bool FilmNegative::button1Pressed(int modifierKey) RGB ref1, ref2, dummy; - if (fnp->getFilmNegativeSpot(refSpotCoords[0], 32, ref1, dummy) && - fnp->getFilmNegativeSpot(refSpotCoords[1], 32, ref2, dummy)) { + if (fnp->getFilmNegativeSpot(refSpotCoords[0], picker.get_spot_full_width(), ref1, dummy) && + fnp->getFilmNegativeSpot(refSpotCoords[1], picker.get_spot_full_width(), ref2, dummy)) { disableListener(); @@ -620,7 +593,7 @@ bool FilmNegative::button1Pressed(int modifierKey) } - } else if (refSpotButton->get_active()) { + } else if (refPicker.get_active()) { disableListener(); @@ -634,7 +607,7 @@ bool FilmNegative::button1Pressed(int modifierKey) } RGB refOut; - fnp->getFilmNegativeSpot(provider->posImage, 32, refInputValues, refOut); + fnp->getFilmNegativeSpot(provider->posImage, refPicker.get_spot_full_width(), refInputValues, refOut); // Output luminance of the sampled spot float spotLum = rtengine::Color::rgbLuminance(refOut.r, refOut.g, refOut.b); @@ -698,16 +671,17 @@ void FilmNegative::switchOffEditMode() { refSpotCoords.clear(); unsubscribe(); - spotButton->set_active(false); - refSpotButton->set_active(false); + picker.set_active(false); + refPicker.set_active(false); } void FilmNegative::editToggled() { - if (spotButton->get_active()) { + if (picker.get_active()) { - refSpotButton->set_active(false); + refPicker.set_active(false); refSpotCoords.clear(); + activePicker = &picker; subscribe(); @@ -727,10 +701,11 @@ void FilmNegative::editToggled() void FilmNegative::refSpotToggled() { - if (refSpotButton->get_active()) { + if (refPicker.get_active()) { - spotButton->set_active(false); + picker.set_active(false); refSpotCoords.clear(); + activePicker = &refPicker; subscribe(); @@ -747,3 +722,4 @@ void FilmNegative::refSpotToggled() unsubscribe(); } } + diff --git a/rtgui/filmnegative.h b/rtgui/filmnegative.h index 722625fa2..87e91af8c 100644 --- a/rtgui/filmnegative.h +++ b/rtgui/filmnegative.h @@ -120,10 +120,14 @@ private: Adjuster* const redRatio; Adjuster* const blueRatio; - Gtk::ToggleButton* const spotButton; + static constexpr int DEFAULT_SPOT_WIDTH = 8; + + SpotPicker picker; Gtk::Label* const refInputLabel; - Gtk::ToggleButton* const refSpotButton; + SpotPicker refPicker; + + SpotPicker* activePicker; Adjuster* const outputLevel; Adjuster* const greenBalance; diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index 9234b1ee6..cb99b04a5 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -1964,3 +1964,78 @@ void BackBuffer::copySurface(Cairo::RefPtr crDest, Gdk::Rectangl crDest->fill(); } } + +SpotPicker::SpotPicker(int const defaultValue, Glib::ustring const &buttonKey, Glib::ustring const &buttonTooltip, Glib::ustring const &labelKey) : + Gtk::Grid(), + _spotHalfWidth(defaultValue), + _spotLabel(labelSetup(labelKey)), + _spotSizeSetter(MyComboBoxText(selecterSetup())), + _spotButton(spotButtonTemplate(buttonKey, buttonTooltip)) + +{ + this->get_style_context()->add_class("grid-spacing"); + setExpandAlignProperties(this, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + + this->attach (_spotButton, 0, 0, 1, 1); + this->attach (_spotLabel, 1, 0, 1, 1); + this->attach (_spotSizeSetter, 2, 0, 1, 1); + _spotSizeSetter.signal_changed().connect( sigc::mem_fun(*this, &SpotPicker::spotSizeChanged)); +} + +Gtk::Label SpotPicker::labelSetup(Glib::ustring const &key) const +{ + Gtk::Label label(key); + setExpandAlignProperties(&label, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + return label; +} + +MyComboBoxText SpotPicker::selecterSetup() const +{ + MyComboBoxText spotSize = MyComboBoxText(); + setExpandAlignProperties(&spotSize, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + + spotSize.append ("2"); + if (_spotHalfWidth == 2) { + spotSize.set_active(0); + } + + spotSize.append ("4"); + + if (_spotHalfWidth == 4) { + spotSize.set_active(1); + } + + spotSize.append ("8"); + + if (_spotHalfWidth == 8) { + spotSize.set_active(2); + } + + spotSize.append ("16"); + + if (_spotHalfWidth == 16) { + spotSize.set_active(3); + } + + spotSize.append ("32"); + + if (_spotHalfWidth == 32) { + spotSize.set_active(4); + } + return spotSize; +} + +Gtk::ToggleButton SpotPicker::spotButtonTemplate(Glib::ustring const &key, const Glib::ustring &tooltip) const +{ + Gtk::ToggleButton spotButton = Gtk::ToggleButton(key); + setExpandAlignProperties(&spotButton, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + spotButton.get_style_context()->add_class("independent"); + spotButton.set_tooltip_text(tooltip); + spotButton.set_image(*Gtk::manage(new RTImage("color-picker-small.png"))); + return spotButton; +} + +void SpotPicker::spotSizeChanged() +{ + _spotHalfWidth = atoi(_spotSizeSetter.get_active_text().c_str()); +} diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 8bc047bf7..02811e076 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -716,7 +716,51 @@ public: } }; -inline void setActiveTextOrIndex (Gtk::ComboBoxText& comboBox, const Glib::ustring& text, int index) +/** + * @brief A gui element for picking spots on an image + */ +class SpotPicker : public Gtk::Grid +{ + private: + int _spotHalfWidth; + Gtk::Label _spotLabel; + MyComboBoxText _spotSizeSetter; + Gtk::ToggleButton _spotButton; + public: + SpotPicker(int const defaultValue, Glib::ustring const &buttonKey, Glib::ustring const &buttonTooltip, Glib::ustring const &labelKey); + inline bool get_active() const + { + return _spotButton.get_active(); + } + void set_active(bool b) + { + _spotButton.set_active(b); + } + int get_spot_half_width() const + { + return _spotHalfWidth; + } + int get_spot_full_width() const + { + return _spotHalfWidth * 2; + } + template void add_button_toggled_event(T_return& returnv, const T_obj function) + { + _spotButton.signal_toggled().connect(sigc::mem_fun(returnv, function)); + } + bool remove_if_there(Gtk::Container* cont, bool increference = true) + { + return removeIfThere(cont, &_spotButton, increference); + } + + protected: + Gtk::Label labelSetup(Glib::ustring const &key) const; + MyComboBoxText selecterSetup() const; + Gtk::ToggleButton spotButtonTemplate(Glib::ustring const &key, const Glib::ustring &tooltip) const; + void spotSizeChanged(); +}; + +inline void setActiveTextOrIndex(Gtk::ComboBoxText &comboBox, const Glib::ustring &text, int index) { bool valueSet = false; if (!text.empty()) {