/*
 *  This file is part of RawTherapee.
 *
 *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
 *
 *  RawTherapee is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  RawTherapee is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details
 *
 *  You should have received a copy of the GNU General Public License
 *  along with RawTherapee.  If not, see <https://www.gnu.org/licenses/>.
 */
#include <iomanip>
#include <cmath>

#include "blackwhite.h"

#include "curveeditor.h"
#include "curveeditorgroup.h"
#include "guiutils.h"
#include "rtimage.h"
#include "options.h"

#include "../rtengine/color.h"
#include "../rtengine/procparams.h"
#include "../rtengine/utils.h"

using namespace rtengine;
using namespace rtengine::procparams;

const Glib::ustring BlackWhite::TOOL_NAME = "blackwhite";

BlackWhite::BlackWhite (): FoldableToolPanel(this, TOOL_NAME, M("TP_BWMIX_LABEL"), false, true)
{
    CurveListener::setMulti(true);

    nextredbw = 0.3333;
    nextgreenbw = 0.3333;
    nextbluebw = 0.3333;

    //----------- Method combobox ------------------------------

    Gtk::Box* metHBox = Gtk::manage (new Gtk::Box ());
    metHBox->set_spacing (2);
    Gtk::Label* metLabel = Gtk::manage (new Gtk::Label (M("TP_BWMIX_MET") + ":"));
    metHBox->pack_start (*metLabel, Gtk::PACK_SHRINK);
   
	method = Gtk::manage (new MyComboBoxText ());
    method->append (M("TP_BWMIX_MET_DESAT"));
    method->append (M("TP_BWMIX_MET_LUMEQUAL"));
    method->append (M("TP_BWMIX_MET_CHANMIX"));

    method->set_active (0);
    metHBox->pack_start (*method);
    pack_start (*metHBox);
    methodconn = method->signal_changed().connect ( sigc::mem_fun(*this, &BlackWhite::methodChanged) );


    //----------- Luminance equalizer ------------------------------

    luminanceSep = Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL));
    pack_start (*luminanceSep);

    std::vector<GradientMilestone> bottomMilestones;
    float R, G, B;

    // -0.1 rad < Hue < 1.6 rad
    for (int i = 0; i < 7; i++) {
        float x = float(i) * (1.0f / 6.f);
        Color::hsv2rgb01(x, 0.5f, 0.5f, R, G, B);
        bottomMilestones.push_back( GradientMilestone(double(x), double(R), double(G), double(B)) );
    }

    luminanceCEG = new CurveEditorGroup (options.lastBWCurvesDir, M("TP_BWMIX_CHANNEL"));
    luminanceCEG->setCurveListener (this);
    luminanceCurve = static_cast<FlatCurveEditor*>(luminanceCEG->addCurve(CT_Flat, M("TP_BWMIX_VAL")));
    luminanceCurve->setEditID(EUID_BlackWhiteLuminance, BT_SINGLEPLANE_FLOAT);
    luminanceCurve->setBottomBarBgGradient(bottomMilestones);
    luminanceCurve->setCurveColorProvider(this, 3);
    luminanceCurve->setTooltip(M("TP_BWMIX_CURVEEDITOR_LH_TOOLTIP"));

    luminanceCEG->curveListComplete();
    pack_start (*luminanceCEG, Gtk::PACK_SHRINK, 4);

    //----------- Auto and Reset buttons ------------------------------

    mixerFrame = Gtk::manage (new Gtk::Frame (M("TP_BWMIX_MET_CHANMIX")));
    mixerFrame->set_label_align(0.025, 0.5);
    pack_start (*mixerFrame, Gtk::PACK_SHRINK, 0);

    mixerVBox = Gtk::manage (new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
    mixerVBox->set_spacing(4);

    autoHBox = Gtk::manage (new Gtk::Box ());

    autoch = Gtk::manage (new Gtk::ToggleButton (M("TP_BWMIX_AUTOCH")));
    autoconn = autoch->signal_toggled().connect( sigc::mem_fun(*this, &BlackWhite::autoch_toggled) );

    neutral = Gtk::manage (new Gtk::Button (M("TP_BWMIX_NEUTRAL")));
    neutralconn = neutral->signal_pressed().connect( sigc::mem_fun(*this, &BlackWhite::neutral_pressed) );
    neutral->show();

    autoHBox->pack_start (*autoch);
    autoHBox->pack_end (*neutral);
    autoHBox->pack_end (*Gtk::manage (new Gtk::Label (" "))); //spacer
    mixerVBox->pack_start (*autoHBox);

    //----------- Presets combobox ------------------------------

    mixerVBox->pack_start (*Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)));

    settingHBox = Gtk::manage (new Gtk::Box ());
    settingHBox->set_spacing (2);
    settingHBox->set_tooltip_markup (M("TP_BWMIX_SETTING_TOOLTIP"));
    Gtk::Label *settingLabel = Gtk::manage (new Gtk::Label (M("TP_BWMIX_SETTING") + ":"));

    settingHBox->pack_start (*settingLabel, Gtk::PACK_SHRINK);
    setting = Gtk::manage (new MyComboBoxText ());
    setting->append (M("TP_BWMIX_SET_NORMCONTAST"));
    setting->append (M("TP_BWMIX_SET_HIGHCONTAST"));
    setting->append (M("TP_BWMIX_SET_LUMINANCE"));
    setting->append (M("TP_BWMIX_SET_LANDSCAPE"));
    setting->append (M("TP_BWMIX_SET_PORTRAIT"));
    setting->append (M("TP_BWMIX_SET_LOWSENSIT"));
    setting->append (M("TP_BWMIX_SET_HIGHSENSIT"));
    setting->append (M("TP_BWMIX_SET_PANCHRO"));
    setting->append (M("TP_BWMIX_SET_HYPERPANCHRO"));
    setting->append (M("TP_BWMIX_SET_ORTHOCHRO"));
    setting->append (M("TP_BWMIX_SET_RGBABS"));
    setting->append (M("TP_BWMIX_SET_RGBREL"));
    setting->append (M("TP_BWMIX_SET_ROYGCBPMABS"));
    setting->append (M("TP_BWMIX_SET_ROYGCBPMREL"));
    setting->append (M("TP_BWMIX_SET_INFRARED"));

    setting->set_active (11);
    settingHBox->pack_start (*setting);
    mixerVBox->pack_start (*settingHBox);
    settingconn = setting->signal_changed().connect ( sigc::mem_fun(*this, &BlackWhite::settingChanged) );

    RGBLabels = Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER));
    RGBLabels->set_tooltip_text(M("TP_BWMIX_RGBLABEL_HINT"));
    mixerVBox->pack_start (*RGBLabels);

    //----------- Complementary Color checkbox ------------------------------

    enabledccSep = Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL));
    mixerVBox->pack_start (*enabledccSep);

    enabledcc = Gtk::manage (new Gtk::CheckButton (M("TP_BWMIX_CC_ENABLED")));

    enabledcc->set_active (true);
    enabledcc->set_tooltip_markup (M("TP_BWMIX_CC_TOOLTIP"));

    mixerVBox->pack_start(*enabledcc, Gtk::PACK_SHRINK, 0);
    enabledcc->show ();
    enaccconn = enabledcc->signal_toggled().connect( sigc::mem_fun(*this, &BlackWhite::enabledcc_toggled) );

    //----------- Color Filters ------------------------------

    filterSep = Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL));
    mixerVBox->pack_start (*filterSep);

    filterHBox = Gtk::manage (new Gtk::Box ());
    filterHBox->set_spacing (2);
    filterHBox->set_tooltip_markup (M("TP_BWMIX_FILTER_TOOLTIP"));
    Gtk::Label *filterLabel = Gtk::manage (new Gtk::Label (M("TP_BWMIX_FILTER") + ":"));
    filterHBox->pack_start (*filterLabel, Gtk::PACK_SHRINK);
    filter = Gtk::manage (new MyComboBoxText ());
    filter->append (M("TP_BWMIX_FILTER_NONE"));
    filter->append (M("TP_BWMIX_FILTER_RED"));
    filter->append (M("TP_BWMIX_FILTER_REDYELLOW"));
    filter->append (M("TP_BWMIX_FILTER_YELLOW"));
    filter->append (M("TP_BWMIX_FILTER_GREENYELLOW"));
    filter->append (M("TP_BWMIX_FILTER_GREEN"));
    filter->append (M("TP_BWMIX_FILTER_BLUEGREEN"));
    filter->append (M("TP_BWMIX_FILTER_BLUE"));
    filter->append (M("TP_BWMIX_FILTER_PURPLE"));

    filter->set_active (0);
    filterHBox->pack_start (*filter);
    mixerVBox->pack_start (*filterHBox);
    filterconn = filter->signal_changed().connect ( sigc::mem_fun(*this, &BlackWhite::filterChanged) );

    //----------- RGB / ROYGCBPM Mixer ------------------------------

    imgIcon[0] = Gtk::manage (new RTImage ("circle-red-small"));
    imgIcon[1] = Gtk::manage (new RTImage ("circle-orange-small"));
    imgIcon[2] = Gtk::manage (new RTImage ("circle-yellow-small"));
    imgIcon[3] = Gtk::manage (new RTImage ("circle-green-small"));
    imgIcon[4] = Gtk::manage (new RTImage ("circle-cyan-small"));
    imgIcon[5] = Gtk::manage (new RTImage ("circle-blue-small"));
    imgIcon[6] = Gtk::manage (new RTImage ("circle-purple-small"));
    imgIcon[7] = Gtk::manage (new RTImage ("circle-magenta-small"));

    imgIcon[8]  = Gtk::manage (new RTImage ("circle-empty-red-small"));
    imgIcon[9]  = Gtk::manage (new RTImage ("circle-empty-green-small"));
    imgIcon[10] = Gtk::manage (new RTImage ("circle-empty-blue-small"));

    mixerVBox->pack_start (*Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)));

    mixerRed = Gtk::manage(new Adjuster (/*M("TP_BWMIX_RED")*/"", -100, 200, 1, 33, imgIcon[0]));

    mixerRed->setAdjusterListener (this);
    mixerRed->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP"));
    mixerRed->show();
    mixerVBox->pack_start( *mixerRed, Gtk::PACK_SHRINK, 0);

    mixerGreen = Gtk::manage(new Adjuster (/*M("TP_BWMIX_GREEN")*/"", -100, 200, 1, 33, imgIcon[3]));

    mixerGreen->setAdjusterListener (this);
    mixerGreen->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP"));
    mixerGreen->show();
    mixerVBox->pack_start( *mixerGreen, Gtk::PACK_SHRINK, 0);

    mixerBlue = Gtk::manage(new Adjuster (/*M("TP_BWMIX_BLUE")*/"", -100, 200, 1, 33, imgIcon[5]));

    mixerBlue->setAdjusterListener (this);
    mixerBlue->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP"));
    mixerBlue->show();
    mixerVBox->pack_start( *mixerBlue, Gtk::PACK_SHRINK, 0);

    filterSep2 = Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL));
    mixerVBox->pack_start (*filterSep2);

    algoHBox = Gtk::manage (new Gtk::Box ());
    algoHBox->set_spacing (2);
    algoHBox->set_tooltip_markup (M("TP_BWMIX_ALGO_TOOLTIP"));

    alLabel = Gtk::manage (new Gtk::Label (M("TP_BWMIX_ALGO") + ":"));
    algoHBox->pack_start (*alLabel, Gtk::PACK_SHRINK);

    algo = Gtk::manage (new MyComboBoxText ());
    algo->append (M("TP_BWMIX_ALGO_LI"));
    algo->append (M("TP_BWMIX_ALGO_SP"));
    algo->set_active (1);
    algoHBox->pack_start (*algo);
    mixerVBox->pack_start(*algoHBox);
    algoconn = algo->signal_changed().connect ( sigc::mem_fun(*this, &BlackWhite::algoChanged) );

    mixerOrange = Gtk::manage(new Adjuster (/*M("TP_BWMIX_ORANGE")*/"", -100, 200, 1, 33, imgIcon[1]));

    mixerOrange->setAdjusterListener (this);
    mixerOrange->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP"));
    mixerOrange->show();
    mixerVBox->pack_start( *mixerOrange, Gtk::PACK_SHRINK, 0);

    mixerYellow = Gtk::manage(new Adjuster (/*M("TP_BWMIX_YELLOW")*/"", -100, 200, 1, 33, imgIcon[2]));

    mixerYellow->setAdjusterListener (this);
    mixerYellow->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP"));
    mixerYellow->show();
    mixerVBox->pack_start( *mixerYellow, Gtk::PACK_SHRINK, 0);

    mixerCyan = Gtk::manage(new Adjuster (/*M("TP_BWMIX_CYAN")*/"", -100, 200, 1, 33, imgIcon[4]));

    mixerCyan->setAdjusterListener (this);
    mixerCyan->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP"));
    mixerCyan->show();
    mixerVBox->pack_start( *mixerCyan, Gtk::PACK_SHRINK, 0);

    mixerPurple = Gtk::manage(new Adjuster (/*M("TP_BWMIX_PURPLE")*/"", -100, 200, 1, 33, imgIcon[6]));

    mixerPurple->setAdjusterListener (this);
    mixerPurple->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP"));
    mixerPurple->show();
    mixerVBox->pack_start( *mixerPurple, Gtk::PACK_SHRINK, 0);

    mixerMagenta = Gtk::manage(new Adjuster (/*M("TP_BWMIX_MAGENTA")*/"", -100, 200, 1, 33, imgIcon[7]));

    mixerMagenta->setAdjusterListener (this);
    mixerMagenta->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP"));
    mixerMagenta->show();
    mixerVBox->pack_start( *mixerMagenta, Gtk::PACK_SHRINK, 0);

    mixerFrame->add(*mixerVBox);

    //----------- Gamma sliders ------------------------------

    gammaFrame = Gtk::manage (new Gtk::Frame (M("TP_BWMIX_GAMMA")));
    gammaFrame->set_label_align(0.025, 0.5);
    pack_start (*gammaFrame, Gtk::PACK_SHRINK, 0);

    Gtk::Box* gammaVBox = Gtk::manage (new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
    gammaVBox->set_spacing(4);


    gammaRed = Gtk::manage(new Adjuster (/*M("TP_BWMIX_GAM_RED")*/"", -100, 100, 1, 0, imgIcon[8]));

    gammaRed->setAdjusterListener (this);
    gammaRed->set_tooltip_markup (M("TP_BWMIX_GAM_TOOLTIP"));
    gammaRed->show();
    gammaVBox->pack_start( *gammaRed, Gtk::PACK_SHRINK, 0);

    gammaGreen = Gtk::manage(new Adjuster (/*M("TP_BWMIX_GAM_GREEN")*/"", -100, 100, 1, 0, imgIcon[9]));

    gammaGreen->setAdjusterListener (this);
    gammaGreen->set_tooltip_markup (M("TP_BWMIX_GAM_TOOLTIP"));
    gammaGreen->show();
    gammaVBox->pack_start( *gammaGreen, Gtk::PACK_SHRINK, 0);

    gammaBlue = Gtk::manage(new Adjuster (/*M("TP_BWMIX_GAM_BLUE")*/"", -100, 100, 1, 0, imgIcon[10]));

    gammaBlue->setAdjusterListener (this);
    gammaBlue->set_tooltip_markup (M("TP_BWMIX_GAM_TOOLTIP"));
    gammaBlue->show();
    gammaVBox->pack_start( *gammaBlue, Gtk::PACK_SHRINK, 0);

    gammaFrame->add(*gammaVBox);

    //----------- Curve 1 ------------------------------

    std::vector<GradientMilestone> bottomMilestonesbw;
    bottomMilestonesbw.push_back( GradientMilestone(0., 0., 0., 0.) );
    bottomMilestonesbw.push_back( GradientMilestone(1., 1., 1., 1.) );

    beforeCurveMode = Gtk::manage (new MyComboBoxText ());
    beforeCurveMode->append (M("TP_BWMIX_TCMODE_STANDARD"));
    beforeCurveMode->append (M("TP_BWMIX_TCMODE_WEIGHTEDSTD"));
    beforeCurveMode->append (M("TP_BWMIX_TCMODE_FILMLIKE"));
    beforeCurveMode->append (M("TP_BWMIX_TCMODE_SATANDVALBLENDING"));
    beforeCurveMode->set_active (0);

    beforeCurveCEG = new CurveEditorGroup (options.lastBWCurvesDir, M("TP_BWMIX_CURVEEDITOR1"));
    beforeCurveCEG->setCurveListener (this);

    beforeCurve = static_cast<DiagonalCurveEditor*>(beforeCurveCEG->addCurve(CT_Diagonal, "", beforeCurveMode));
    beforeCurve->setEditID(EUID_BlackWhiteBeforeCurve, BT_IMAGEFLOAT);
    beforeCurve->setBottomBarBgGradient(bottomMilestonesbw);
    beforeCurve->setLeftBarBgGradient(bottomMilestonesbw);
    beforeCurve->setTooltip(M("TP_BWMIX_CURVEEDITOR_BEFORE_TOOLTIP"));

    // This will add the reset button at the end of the curveType buttons
    beforeCurveCEG->curveListComplete();

    pack_start( *beforeCurveCEG, Gtk::PACK_SHRINK, 2);

    tcmodeconn = beforeCurveMode->signal_changed().connect( sigc::mem_fun(*this, &BlackWhite::curveMode1Changed), true );

    //----------- Curve 2 ------------------------------
    /*
        afterCurveMode = Gtk::manage (new MyComboBoxText ());
        afterCurveMode->append (M("TP_BWMIX_TCMODE_STANDARD"));
        //  afterCurveMode->append (M("TP_BWMIX_TCMODE_WEIGHTEDSTD"));
        afterCurveMode->set_active (0);
    */
    afterCurveCEG = new CurveEditorGroup (options.lastBWCurvesDir, M("TP_BWMIX_CURVEEDITOR2"));
    afterCurveCEG->setCurveListener (this);

//  afterCurve = static_cast<DiagonalCurveEditor*>(afterCurveCEG->addCurve(CT_Diagonal, "", afterCurveMode));
    afterCurve = static_cast<DiagonalCurveEditor*>(afterCurveCEG->addCurve(CT_Diagonal, ""));
    afterCurve->setEditID(EUID_BlackWhiteAfterCurve, BT_SINGLEPLANE_FLOAT);
    afterCurve->setBottomBarBgGradient(bottomMilestonesbw);
    afterCurve->setLeftBarBgGradient(bottomMilestonesbw);
    afterCurve->setTooltip(M("TP_BWMIX_CURVEEDITOR_AFTER_TOOLTIP"));

    afterCurveCEG->curveListComplete();

    pack_start( *afterCurveCEG, Gtk::PACK_SHRINK, 2);

//  tcmodeconn2 = afterCurveMode->signal_changed().connect( sigc::mem_fun(*this, &BlackWhite::curveMode1Changed2), true );

    show_all();

    disableListener();
    methodChanged();
    enableListener();
}
BlackWhite::~BlackWhite ()
{
    idle_register.destroy();

    delete luminanceCEG;
    delete beforeCurveCEG;
    delete afterCurveCEG;
}

void BlackWhite::BWChanged  (double redbw, double greenbw, double bluebw)
{
    nextredbw = redbw;
    nextgreenbw = greenbw;
    nextbluebw = bluebw;

    idle_register.add(
        [this]() -> bool
        {
            BWComputed_();
            return false;
        }
    );
}

bool BlackWhite::BWComputed_ ()
{

    disableListener ();
    mixerRed->setValue (nextredbw);
    adjusterChanged(mixerRed, mixerRed->getValue());
    mixerGreen->setValue (nextgreenbw);
    adjusterChanged(mixerGreen, mixerGreen->getValue());
    mixerBlue->setValue (nextbluebw);
    adjusterChanged(mixerBlue, mixerBlue->getValue());
    autoconn.block (true);
    autoch->set_active (true);
    autoconn.block (false);
    lastAuto = false;
    nextcount++;
    enableListener ();
    if (listener  && nextcount <= 1 ) {
        // activated only 1 time, but perhaps in some cases if we want that all is update pp3, auto, sliders : nextcount <= 2 but it cost time and result is identical
        listener->panelChanged (EvAutoch, M("GENERAL_ENABLED"));
    }

    updateRGBLabel();

    return false;
}

void BlackWhite::read (const ProcParams* pp, const ParamsEdited* pedited)
{

    disableListener ();
    methodconn.block(true);
    //autoconn.block (true);
    filterconn.block(true);
    settingconn.block(true);
    enaccconn.block (true);

    if (pedited && !pedited->blackwhite.setting) {
        setting->set_active (15);    // "Unchanged"
    } else if (pp->blackwhite.setting == "NormalContrast") {
        setting->set_active (0);
    } else if (pp->blackwhite.setting == "HighContrast") {
        setting->set_active (1);
    } else if (pp->blackwhite.setting == "Luminance") {
        setting->set_active (2);
    } else if (pp->blackwhite.setting == "Landscape") {
        setting->set_active (3);
    } else if (pp->blackwhite.setting == "Portrait") {
        setting->set_active (4);
    } else if (pp->blackwhite.setting == "LowSensitivity") {
        setting->set_active (5);
    } else if (pp->blackwhite.setting == "HighSensitivity") {
        setting->set_active (6);
    } else if (pp->blackwhite.setting == "Panchromatic") {
        setting->set_active (7);
    } else if (pp->blackwhite.setting == "HyperPanchromatic") {
        setting->set_active (8);
    } else if (pp->blackwhite.setting == "Orthochromatic") {
        setting->set_active (9);
    } else if (pp->blackwhite.setting == "RGB-Abs") {
        setting->set_active (10);
    } else if (pp->blackwhite.setting == "RGB-Rel") {
        setting->set_active (11);
    } else if (pp->blackwhite.setting == "ROYGCBPM-Abs") {
        setting->set_active (12);
    } else if (pp->blackwhite.setting == "ROYGCBPM-Rel") {
        setting->set_active (13);
    } else if (pp->blackwhite.setting == "InfraRed") {
        setting->set_active (14);
    }

    settingChanged();


    if (pedited && !pedited->blackwhite.method) {
        method->set_active (3);    // "Unchanged"
    } else if (pp->blackwhite.method == "Desaturation") {
        method->set_active (0);
    } else if (pp->blackwhite.method == "LumEqualizer") {
        method->set_active (1);
    } else if (pp->blackwhite.method == "ChannelMixer") {
        method->set_active (2);
    }

    methodChanged();


    if (pedited && !pedited->blackwhite.filter) {
        filter->set_active (9);    // "Unchanged"
    } else if (pp->blackwhite.filter == "None") {
        filter->set_active (0);
    } else if (pp->blackwhite.filter == "Red") {
        filter->set_active (1);
    } else if (pp->blackwhite.filter == "Orange") {
        filter->set_active (2);
    } else if (pp->blackwhite.filter == "Yellow") {
        filter->set_active (3);
    } else if (pp->blackwhite.filter == "YellowGreen") {
        filter->set_active (4);
    } else if (pp->blackwhite.filter == "Green") {
        filter->set_active (5);
    } else if (pp->blackwhite.filter == "Cyan") {
        filter->set_active (6);
    } else if (pp->blackwhite.filter == "Blue") {
        filter->set_active (7);
    } else if (pp->blackwhite.filter == "Purple") {
        filter->set_active (8);
    }

    filterChanged();

    enabledcc->set_active (pp->blackwhite.enabledcc);
    lastEnabledcc = pp->blackwhite.enabledcc;
    setEnabled (pp->blackwhite.enabled);

    mixerRed->setValue (pp->blackwhite.mixerRed);
    mixerGreen->setValue (pp->blackwhite.mixerGreen);
    mixerBlue->setValue (pp->blackwhite.mixerBlue);
    gammaRed->setValue (pp->blackwhite.gammaRed);
    gammaGreen->setValue (pp->blackwhite.gammaGreen);
    gammaBlue->setValue (pp->blackwhite.gammaBlue);
    mixerOrange->setValue (pp->blackwhite.mixerOrange);
    mixerYellow->setValue (pp->blackwhite.mixerYellow);
    mixerCyan->setValue (pp->blackwhite.mixerCyan);
    mixerMagenta->setValue (pp->blackwhite.mixerMagenta);
    mixerPurple->setValue (pp->blackwhite.mixerPurple);
    luminanceCurve->setCurve (pp->blackwhite.luminanceCurve);
    beforeCurve->setCurve (pp->blackwhite.beforeCurve);
    beforeCurveMode->set_active(toUnderlying(pp->blackwhite.beforeCurveMode));
    afterCurve->setCurve (pp->blackwhite.afterCurve);
//  afterCurveMode->set_active(pp->blackwhite.afterCurveMode);

    autoch->set_active (pp->blackwhite.autoc);
    lastAuto = pp->blackwhite.autoc;

    algoconn.block(true);

    if (pedited && !pedited->blackwhite.algo) {
        algo->set_active (2);
    } else if (pp->blackwhite.algo == "LI") {
        algo->set_active (0);
    } else if (pp->blackwhite.algo == "SP") {
        algo->set_active (1);
    }

    algoconn.block(false);
    algoChanged();


    if (pedited) {
        luminanceCurve->setUnChanged (!pedited->blackwhite.luminanceCurve);
        beforeCurve->setUnChanged (!pedited->blackwhite.beforeCurve);
        afterCurve->setUnChanged (!pedited->blackwhite.afterCurve);
        autoch->set_inconsistent (!pedited->blackwhite.autoc);
        set_inconsistent (multiImage && !pedited->blackwhite.enabled);
        enabledcc->set_inconsistent  (!pedited->blackwhite.enabledcc);
        mixerRed->setEditedState (pedited->blackwhite.mixerRed ? Edited : UnEdited);
        mixerGreen->setEditedState (pedited->blackwhite.mixerGreen ? Edited : UnEdited);
        mixerBlue->setEditedState (pedited->blackwhite.mixerBlue ? Edited : UnEdited);
        gammaRed->setEditedState (pedited->blackwhite.gammaRed ? Edited : UnEdited);
        gammaGreen->setEditedState (pedited->blackwhite.gammaGreen ? Edited : UnEdited);
        gammaBlue->setEditedState (pedited->blackwhite.gammaBlue ? Edited : UnEdited);
        mixerOrange->setEditedState (pedited->blackwhite.mixerOrange ? Edited : UnEdited);
        mixerYellow->setEditedState (pedited->blackwhite.mixerYellow ? Edited : UnEdited);
        mixerCyan->setEditedState (pedited->blackwhite.mixerCyan ? Edited : UnEdited);
        mixerMagenta->setEditedState (pedited->blackwhite.mixerMagenta ? Edited : UnEdited);
        mixerPurple->setEditedState (pedited->blackwhite.mixerPurple ? Edited : UnEdited);

        if (!pedited->blackwhite.beforeCurveMode) {
            beforeCurveMode->set_active(4); // "Unchanged"
        }

//      if (!pedited->blackwhite.afterCurveMode) {
//          afterCurveMode->set_active(1); // "Unchanged"
//      }
    }

    methodconn.block(false);
    filterconn.block(false);
    settingconn.block(false);
    //autoconn.block (false);
    enaccconn.block (false);

    updateRGBLabel();

    enableListener ();
}

void BlackWhite::write (ProcParams* pp, ParamsEdited* pedited)
{
    pp->blackwhite.enabled = getEnabled();
    pp->blackwhite.luminanceCurve = luminanceCurve->getCurve ();
    pp->blackwhite.autoc = autoch->get_active();
    pp->blackwhite.enabledcc = enabledcc->get_active ();
    pp->blackwhite.mixerRed = mixerRed->getValue ();
    pp->blackwhite.mixerGreen = mixerGreen->getValue ();
    pp->blackwhite.mixerBlue = mixerBlue->getValue ();
    pp->blackwhite.gammaRed = gammaRed->getValue ();
    pp->blackwhite.gammaGreen = gammaGreen->getValue ();
    pp->blackwhite.gammaBlue = gammaBlue->getValue ();
    pp->blackwhite.mixerOrange = mixerOrange->getValue ();
    pp->blackwhite.mixerYellow = mixerYellow->getValue ();
    pp->blackwhite.mixerCyan = mixerCyan->getValue ();
    pp->blackwhite.mixerMagenta = mixerMagenta->getValue ();
    pp->blackwhite.mixerPurple = mixerPurple->getValue ();
    pp->blackwhite.beforeCurve = beforeCurve->getCurve ();
    pp->blackwhite.afterCurve = afterCurve->getCurve ();

    int tcMode = beforeCurveMode->get_active_row_number();

    if      (tcMode == 0) {
        pp->blackwhite.beforeCurveMode = BlackWhiteParams::TcMode::STD_BW;
    } else if (tcMode == 1) {
        pp->blackwhite.beforeCurveMode = BlackWhiteParams::TcMode::WEIGHTEDSTD_BW;
    } else if (tcMode == 2) {
        pp->blackwhite.beforeCurveMode = BlackWhiteParams::TcMode::FILMLIKE_BW;
    } else if (tcMode == 3) {
        pp->blackwhite.beforeCurveMode = BlackWhiteParams::TcMode::SATANDVALBLENDING_BW;
    }

//  tcMode = afterCurveMode->get_active_row_number();
//  if      (tcMode == 0) pp->blackwhite.afterCurveMode = BlackWhiteParams::TCMode::STD_BW;
    //  else if (tcMode == 1) pp->blackwhite.afterCurveMode = BlackWhiteParams::TCMode::WEIGHTEDSTD;

    if (pedited) {
        pedited->blackwhite.enabled = !get_inconsistent();
        pedited->blackwhite.luminanceCurve = !luminanceCurve->isUnChanged ();
        pedited->blackwhite.autoc = !autoch->get_inconsistent();
        pedited->blackwhite.enabledcc = !enabledcc->get_inconsistent();
        pedited->blackwhite.mixerRed = mixerRed->getEditedState ();
        pedited->blackwhite.mixerGreen = mixerGreen->getEditedState ();
        pedited->blackwhite.mixerBlue = mixerBlue->getEditedState ();
        pedited->blackwhite.gammaRed = gammaRed->getEditedState ();
        pedited->blackwhite.gammaGreen = gammaGreen->getEditedState ();
        pedited->blackwhite.gammaBlue = gammaBlue->getEditedState ();
        pedited->blackwhite.filter = filter->get_active_text() != M("GENERAL_UNCHANGED");
        pedited->blackwhite.setting = setting->get_active_text() != M("GENERAL_UNCHANGED");
        pedited->blackwhite.method = method->get_active_text() != M("GENERAL_UNCHANGED");
        pedited->blackwhite.mixerOrange = mixerOrange->getEditedState ();
        pedited->blackwhite.mixerYellow = mixerYellow->getEditedState ();
        pedited->blackwhite.mixerCyan = mixerCyan->getEditedState ();
        pedited->blackwhite.mixerMagenta = mixerMagenta->getEditedState ();
        pedited->blackwhite.mixerPurple = mixerPurple->getEditedState ();
        pedited->blackwhite.beforeCurve = !beforeCurve->isUnChanged ();
        pedited->blackwhite.beforeCurveMode = beforeCurveMode->get_active_row_number() != 4;
        pedited->blackwhite.afterCurve = !afterCurve->isUnChanged ();
        pedited->blackwhite.algo          = algo->get_active_text() != M("GENERAL_UNCHANGED");

//      pedited->blackwhite.afterCurveMode = afterCurveMode->get_active_row_number() != 1;
    }

    if (method->get_active_row_number() == 0) {
        pp->blackwhite.method = "Desaturation";
    } else if (method->get_active_row_number() == 1) {
        pp->blackwhite.method = "LumEqualizer";
    } else if (method->get_active_row_number() == 2) {
        pp->blackwhite.method = "ChannelMixer";
    }

    if (algo->get_active_row_number() == 0) {
        pp->blackwhite.algo = "LI";
    } else if (algo->get_active_row_number() == 1) {
        pp->blackwhite.algo = "SP";
    }

    pp->blackwhite.setting = getSettingString();
    pp->blackwhite.filter = getFilterString();
}

void BlackWhite::algoChanged ()
{
    if (listener && (multiImage || getEnabled()) ) {
        listener->panelChanged (EvBWMethodalg, algo->get_active_text ());
    }
}

void BlackWhite::curveChanged (CurveEditor* ce)
{
    if (listener) {
        if (ce == beforeCurve) {
            listener->panelChanged (EvBWBeforeCurve, M("HISTORY_CUSTOMCURVE"));
        }

        if (ce == afterCurve) {
            listener->panelChanged (EvBWAfterCurve, M("HISTORY_CUSTOMCURVE"));
        }

        if (ce == luminanceCurve) {
            listener->panelChanged (EvBWLuminanceEqual, M("HISTORY_CUSTOMCURVE"));
        }
    }
}

void BlackWhite::curveMode1Changed ()
{
    if (listener) {
        Glib::signal_idle().connect (sigc::mem_fun(*this, &BlackWhite::curveMode1Changed_));
    }
}
bool BlackWhite::curveMode1Changed_ ()
{
    if (listener) {
        listener->panelChanged (EvBWBeforeCurveMode, escapeHtmlChars(beforeCurveMode->get_active_text()));
    }

    return false;
}
/*
void BlackWhite::curveMode1Changed2 () {
    if (listener)  Glib::signal_idle().connect (sigc::mem_fun(*this, &BlackWhite::curveMode1Changed2_));
}
bool BlackWhite::curveMode1Changed2_ () {
    if (listener) listener->panelChanged (EvBWAfterCurveMode, escapeHtmlChars(afterCurveMode->get_active_text()));
    return false;
}
*/
void BlackWhite::colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller)
{

    float r, g, b;

    if (elemType == ColorCaller::CCET_VERTICAL_BAR) {
        valY = 0.5f;
    }

    if (callerId == 1) {        // Hue = f(Hue)

        float h = float((valY - 0.5) * 2. + valX);

        if (h > 1.0f) {
            h -= 1.0f;
        } else if (h < 0.0f) {
            h += 1.0f;
        }

        Color::hsv2rgb01(h, 0.5f, 0.5f, r, g, b);
        caller->ccRed = double(r);
        caller->ccGreen = double(g);
        caller->ccBlue = double(b);
    } else if (callerId == 2) { // Saturation = f(Hue)
        Color::hsv2rgb01(float(valX), float(valY), 0.5f, r, g, b);
        caller->ccRed = double(r);
        caller->ccGreen = double(g);
        caller->ccBlue = double(b);
    } else if (callerId == 3) { // Value = f(Hue)
        Color::hsv2rgb01(float(valX), 0.5f, float(valY), r, g, b);
        caller->ccRed = double(r);
        caller->ccGreen = double(g);
        caller->ccBlue = double(b);
    } else {
        printf("Error: no curve displayed!\n");
    }
}


void BlackWhite::settingChanged ()
{

    if ( setting->get_active_row_number() == 10 || setting->get_active_row_number() == 11 ) {
        // RGB Channel Mixer
        showMixer(3);
        hideEnabledCC();
        showFilter();
    } else if ( setting->get_active_row_number() == 12 || setting->get_active_row_number() == 13 ) {
        // ROYGCBPM Channel Mixer
        showMixer(7);
        showEnabledCC();
        showFilter();
    } else if ( setting->get_active_row_number() == 14 ) {
        // Infrared
        filter->set_active (0);
        showMixer(3, false);
        hideEnabledCC();
        hideFilter();
    } else {
        // RGB Presets
        showMixer(3, false);
        hideEnabledCC();
        showFilter();
    }

    // Checking "listener" to avoid "autoch" getting toggled off because it has to change the sliders when toggling on
    if (listener) {
        if (multiImage && autoch->get_inconsistent()) {
            autoch->set_inconsistent (false);
        }

        autoconn.block(true);
        autoch->set_active (false);
        autoconn.block(false);
        lastAuto = false;
    }

    updateRGBLabel();

    if (listener && (multiImage || getEnabled())) {
        listener->panelChanged (EvBWsetting, setting->get_active_text ());
    }
}


void BlackWhite::filterChanged ()
{
    // Checking "listener" to avoid "autoch" getting toggled off because it has to change the sliders when toggling on
    if (listener) {
        if (multiImage && autoch->get_inconsistent()) {
            autoch->set_inconsistent (false);
        }

        autoconn.block(true);
        autoch->set_active (false);
        autoconn.block(false);
        lastAuto = false;
    }

    updateRGBLabel();

    if (listener && (multiImage || getEnabled())) {
        listener->panelChanged (EvBWfilter, filter->get_active_text ());
    }
}

void BlackWhite::methodChanged ()
{
    if(method->get_active_row_number() == 2) {
        // Channel Mixer
        hideLuminance();

        if(setting->get_active_row_number() == 10 || setting->get_active_row_number() == 11) {
            hideEnabledCC();
            showMixer(3);
        } else if(setting->get_active_row_number() == 12 || setting->get_active_row_number() == 13) {
            showEnabledCC();
            showMixer(7);
        } else {
            hideEnabledCC();
            showMixer(3, false);
        }

        beforeCurveCEG->show();
        afterCurveCEG->show();

        bool wasEnabled = disableListener();
        settingChanged();

        if (wasEnabled) {
            enableListener();
        }
    } else if(method->get_active_row_number() == 1) {
        // Luminance Equalizer
        showLuminance();
        hideMixer();
        beforeCurveCEG->show();
        afterCurveCEG->show();
    } else if(method->get_active_row_number() == 0) {
        // Desaturation
        hideLuminance();
        hideMixer();
        beforeCurveCEG->show();
        afterCurveCEG->show();
    }

    if (listener && (multiImage || getEnabled())) {
        listener->panelChanged (EvBWmethod, method->get_active_text ());
    }
}

void BlackWhite::enabledChanged ()
{
    if (listener) {
        if (get_inconsistent()) {
            listener->panelChanged (EvBWChmixEnabled, M("GENERAL_UNCHANGED"));
        } else if (getEnabled()) {
            listener->panelChanged (EvBWChmixEnabled, M("GENERAL_ENABLED"));
        } else {
            listener->panelChanged (EvBWChmixEnabled, M("GENERAL_DISABLED"));
        }
    }
}

void BlackWhite::neutral_pressed ()
{
    // This method deselects auto chmixer and sets "neutral" values to params
    disableListener();

    if (multiImage && autoch->get_inconsistent()) {
        autoch->set_inconsistent (false);
    }

    autoconn.block(true);
    autoch->set_active (false);
    autoconn.block(false);
    lastAuto = false;

    int activeSetting = setting->get_active_row_number();

    if (activeSetting < 10 || activeSetting > 13) {
        setting->set_active (11);
    }

    filter->set_active (0);
    mixerRed->resetValue(false);
    mixerGreen->resetValue(false);
    mixerBlue->resetValue(false);
    mixerOrange->resetValue(false);
    mixerYellow->resetValue(false);
    mixerMagenta->resetValue(false);
    mixerPurple->resetValue(false);
    mixerCyan->resetValue(false);

    enableListener();

    updateRGBLabel();

    nextcount = 0;
    if(listener) {
        listener->panelChanged (EvNeutralBW, M("GENERAL_RESET"));
    }
}

void BlackWhite::enabledcc_toggled ()
{

    // toggling off the Complementary Colors does switch off the Auto button
    if (multiImage) {
        // multiple image editing (batch)
        if (enabledcc->get_inconsistent()) {
            enabledcc->set_inconsistent (false);  // set consistent
            enaccconn.block (true);
            enabledcc->set_active (false);  // ... and deactivated
            enaccconn.block (false);
        } else if (lastEnabledcc) {
            enabledcc->set_inconsistent (true);
        }

        lastEnabledcc = enabledcc->get_active ();
    }

    if (multiImage && autoch->get_inconsistent()) {
        autoch->set_inconsistent (false);
    }

    autoconn.block(true);
    autoch->set_active (false);
    autoconn.block(false);
    lastAuto = false;

    updateRGBLabel();

    if (listener) {
        if (enabledcc->get_inconsistent()) {
            listener->panelChanged (EvBWChmixEnabledLm, M("GENERAL_UNCHANGED"));
        } else if (enabledcc->get_active ()) {
            listener->panelChanged (EvBWChmixEnabledLm, M("GENERAL_ENABLED"));
        } else {
            listener->panelChanged (EvBWChmixEnabledLm, M("GENERAL_DISABLED"));
        }
    }
}


void BlackWhite::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited)
{

    mixerRed->setDefault (defParams->blackwhite.mixerRed);
    mixerGreen->setDefault (defParams->blackwhite.mixerGreen);
    mixerBlue->setDefault (defParams->blackwhite.mixerBlue);
    gammaRed->setDefault (defParams->blackwhite.gammaRed);
    gammaGreen->setDefault (defParams->blackwhite.gammaGreen);
    gammaBlue->setDefault (defParams->blackwhite.gammaBlue);
    mixerOrange->setDefault (defParams->blackwhite.mixerOrange);
    mixerYellow->setDefault (defParams->blackwhite.mixerYellow);
    mixerCyan->setDefault (defParams->blackwhite.mixerCyan);
    mixerMagenta->setDefault (defParams->blackwhite.mixerMagenta);
    mixerPurple->setDefault (defParams->blackwhite.mixerPurple);

    if (pedited) {
        mixerRed->setDefaultEditedState (pedited->blackwhite.mixerRed ? Edited : UnEdited);
        mixerGreen->setDefaultEditedState (pedited->blackwhite.mixerGreen ? Edited : UnEdited);
        mixerBlue->setDefaultEditedState (pedited->blackwhite.mixerBlue ? Edited : UnEdited);
        gammaRed->setDefaultEditedState (pedited->blackwhite.gammaRed ? Edited : UnEdited);
        gammaGreen->setDefaultEditedState (pedited->blackwhite.gammaGreen ? Edited : UnEdited);
        gammaBlue->setDefaultEditedState (pedited->blackwhite.gammaBlue ? Edited : UnEdited);
        mixerOrange->setDefaultEditedState (pedited->blackwhite.mixerOrange ? Edited : UnEdited);
        mixerYellow->setDefaultEditedState (pedited->blackwhite.mixerYellow ? Edited : UnEdited);
        mixerCyan->setDefaultEditedState (pedited->blackwhite.mixerCyan ? Edited : UnEdited);
        mixerMagenta->setDefaultEditedState (pedited->blackwhite.mixerMagenta ? Edited : UnEdited);
        mixerPurple->setDefaultEditedState (pedited->blackwhite.mixerPurple ? Edited : UnEdited);
    } else {
        mixerRed->setDefaultEditedState (Irrelevant);
        mixerGreen->setDefaultEditedState (Irrelevant);
        mixerBlue->setDefaultEditedState (Irrelevant);
        gammaRed->setDefaultEditedState (Irrelevant);
        gammaGreen->setDefaultEditedState (Irrelevant);
        gammaBlue->setDefaultEditedState (Irrelevant);
        mixerOrange->setDefaultEditedState (Irrelevant);
        mixerYellow->setDefaultEditedState (Irrelevant);
        mixerCyan->setDefaultEditedState (Irrelevant);
        mixerMagenta->setDefaultEditedState (Irrelevant);
        mixerPurple->setDefaultEditedState (Irrelevant);
    }
}

void BlackWhite::autoch_toggled ()
{

    if (batchMode) {
        if (multiImage) {
            if (autoch->get_inconsistent()) {
                autoch->set_inconsistent (false);
                autoconn.block (true);
                autoch->set_active (false);
                autoconn.block (false);
            } else if (lastAuto) {
                autoch->set_inconsistent (true);
            }
        }

        lastAuto = autoch->get_active ();

        mixerRed->setEditedState (UnEdited);
        mixerGreen->setEditedState (UnEdited);
        mixerBlue->setEditedState (UnEdited);
        mixerOrange->setEditedState (UnEdited);
        mixerYellow->setEditedState (UnEdited);
        mixerPurple->setEditedState (UnEdited);
        mixerMagenta->setEditedState (UnEdited);
        mixerCyan->setEditedState (UnEdited);

        bool wasEnabled = disableListener();

        if (mixerRed->getAddMode()) {
            mixerRed->resetValue(true);
        }

        if (mixerGreen->getAddMode()) {
            mixerGreen->resetValue(true);
        }

        if (mixerBlue->getAddMode()) {
            mixerBlue->resetValue(true);
        }

        if (mixerOrange->getAddMode()) {
            mixerOrange->resetValue(true);
        }

        if (mixerYellow->getAddMode()) {
            mixerYellow->resetValue(true);
        }

        if (mixerMagenta->getAddMode()) {
            mixerMagenta->resetValue(true);
        }

        if (mixerPurple->getAddMode()) {
            mixerPurple->resetValue(true);
        }

        if (mixerCyan->getAddMode()) {
            mixerCyan->resetValue(true);
        }

        setting->set_active (11);
        filter->set_active (0);

        if (wasEnabled) {
            enableListener();
        }

        if (listener) {
            if (autoch->get_inconsistent()) {
                listener->panelChanged (EvAutoch, M("GENERAL_UNCHANGED"));
            } else if (autoch->get_active ()) {
                listener->panelChanged (EvAutoch, M("GENERAL_ENABLED"));
            } else {
                listener->panelChanged (EvAutoch, M("GENERAL_DISABLED"));
            }
        }
    } else {
        if (autoch->get_active()) {
            bool wasEnabled = disableListener();
            mixerRed->resetValue(false);
            mixerGreen->resetValue(false);
            mixerBlue->resetValue(false);
            mixerOrange->resetValue(false);
            mixerYellow->resetValue(false);
            mixerMagenta->resetValue(false);
            mixerPurple->resetValue(false);
            mixerCyan->resetValue(false);
            setting->set_active (11);
            filter->set_active (0);

            if (wasEnabled) {
                enableListener();
            }

            updateRGBLabel();

            if (listener) {
                listener->panelChanged (EvAutoch, M("GENERAL_ENABLED"));
            }
        } else {
            if (listener) {
                listener->panelChanged (EvAutoch, M("GENERAL_DISABLED"));
            }
        }
    }

}

void BlackWhite::adjusterChanged(Adjuster* a, double newval)
{
    // Checking "listener" to avoid "autoch" getting toggled off because it has to change the sliders when toggling on
    if (listener && (a == mixerRed || a == mixerGreen || a == mixerBlue || a == mixerOrange || a == mixerYellow || a == mixerMagenta || a == mixerPurple || a == mixerCyan) ) {
        if (multiImage && autoch->get_inconsistent()) {
            autoch->set_inconsistent (false);
        }

        nextcount = 0;
        autoconn.block(true);
        autoch->set_active (false);
        autoconn.block(false);
        lastAuto = false;
    }

    if (a == mixerRed || a == mixerGreen || a == mixerBlue
            || a == mixerOrange || a == mixerYellow || a == mixerCyan
            || a == mixerMagenta || a == mixerPurple)

    {
        updateRGBLabel();
    }

    if (listener  && (multiImage || getEnabled())) {
        Glib::ustring value = a->getTextValue();

        if (a == mixerRed) {
            listener->panelChanged (EvBWred, value );
        } else if (a == mixerGreen) {
            listener->panelChanged (EvBWgreen, value );
        } else if (a == mixerBlue) {
            listener->panelChanged (EvBWblue, value );
        } else if (a == gammaGreen) {
            listener->panelChanged (EvBWgreengam, value );
        } else if (a == gammaBlue) {
            listener->panelChanged (EvBWbluegam, value );
        } else if (a == gammaRed) {
            listener->panelChanged (EvBWredgam, value );
        } else if (a == mixerOrange) {
            listener->panelChanged (EvBWoran, value );
        } else if (a == mixerYellow) {
            listener->panelChanged (EvBWyell, value );
        } else if (a == mixerCyan) {
            listener->panelChanged (EvBWcyan, value );
        } else if (a == mixerMagenta) {
            listener->panelChanged (EvBWmag, value );
        } else if (a == mixerPurple) {
            listener->panelChanged (EvBWpur, value );
        }
    }
}

void BlackWhite::updateRGBLabel ()
{
    if (!batchMode) {
        float kcorrec = 1.f;
        float r, g, b;

        if (autoch->get_active()) {
            r = nextredbw;
            g = nextgreenbw;
            b = nextbluebw;
        } else {
            r = mixerRed->getValue();
            g = mixerGreen->getValue();
            b = mixerBlue->getValue();
        }

        double mixR, mixG, mixB;
        float filcor;
        Glib::ustring sSetting = getSettingString();
        Color::computeBWMixerConstants(sSetting, getFilterString(), getalgoString(), filcor, r, g, b,
                                       mixerOrange->getValue(), mixerYellow->getValue(), mixerCyan->getValue(), mixerPurple->getValue(), mixerMagenta->getValue(),
                                       autoch->get_active(), enabledcc->get_active(), kcorrec, mixR, mixG, mixB);

        if( filcor != 1.f) {
            r = kcorrec * r / (r + g + b);
            g = kcorrec * g / (r + g + b);
            b = kcorrec * b / (r + g + b);
        }

        RGBLabels->set_text(
            Glib::ustring::compose(M("TP_BWMIX_RGBLABEL"),
                                   Glib::ustring::format(std::fixed, std::setprecision(1), r * 100.f),
                                   Glib::ustring::format(std::fixed, std::setprecision(1), g * 100.f),
                                   Glib::ustring::format(std::fixed, std::setprecision(1), b * 100.f),
                                   Glib::ustring::format(std::fixed, std::setprecision(0), ceil(kcorrec * 100.f/*(r+g+b)*100.)*/)))
        );

        // We have to update the RGB sliders too if preset values has been chosen
        if (sSetting != "RGB-Abs" && sSetting != "RGB-Rel" && sSetting != "ROYGCBPM-Abs" && sSetting != "ROYGCBPM-Rel") {
            mixerRed->setValue(mixR);
            mixerGreen->setValue(mixG);
            mixerBlue->setValue(mixB);
        }
    }
}

void BlackWhite::setBatchMode (bool batchMode)
{
    removeIfThere (autoHBox, autoch, false);
    autoch = Gtk::manage (new Gtk::CheckButton (M("TP_BWMIX_AUTOCH")));
    autoconn = autoch->signal_toggled().connect( sigc::mem_fun(*this, &BlackWhite::autoch_toggled) );
    autoHBox->pack_start (*autoch);

    removeIfThere (mixerVBox, RGBLabels, false);
    delete RGBLabels;
    RGBLabels = nullptr;

    ToolPanel::setBatchMode (batchMode);
    mixerRed->showEditedCB ();
    mixerOrange->showEditedCB ();
    mixerYellow->showEditedCB ();
    mixerGreen->showEditedCB ();
    mixerCyan->showEditedCB ();
    mixerBlue->showEditedCB ();
    mixerMagenta->showEditedCB ();
    mixerPurple->showEditedCB ();
    gammaRed->showEditedCB ();
    gammaGreen->showEditedCB ();
    gammaBlue->showEditedCB ();
    method->append (M("GENERAL_UNCHANGED"));
    filter->append (M("GENERAL_UNCHANGED"));
    setting->append (M("GENERAL_UNCHANGED"));
    luminanceCEG->setBatchMode (batchMode);
    beforeCurveCEG->setBatchMode (batchMode);
    beforeCurveCEG->show();
    beforeCurveMode->append (M("GENERAL_UNCHANGED"));
    afterCurveCEG->setBatchMode (batchMode);
    afterCurveCEG->show();
//  afterCurveMode->append (M("GENERAL_UNCHANGED"));
    algo->append (M("GENERAL_UNCHANGED"));

    showLuminance();
    showFilter();
    showEnabledCC();
    showGamma();
    showMixer(7);
}

void BlackWhite::autoOpenCurve ()
{
    luminanceCurve->openIfNonlinear();
    beforeCurve->openIfNonlinear();
    afterCurve->openIfNonlinear();
}
void BlackWhite::setEditProvider (EditDataProvider *provider)
{
    luminanceCurve->setEditProvider(provider);
    beforeCurve->setEditProvider(provider);
    afterCurve->setEditProvider(provider);
}

void BlackWhite::setAdjusterBehavior (bool bwadd, bool bwgadd)
{

    mixerRed->setAddMode(bwadd);
    mixerOrange->setAddMode(bwadd);
    mixerYellow->setAddMode(bwadd);
    mixerGreen->setAddMode(bwadd);
    mixerCyan->setAddMode(bwadd);
    mixerBlue->setAddMode(bwadd);
    mixerMagenta->setAddMode(bwadd);
    mixerPurple->setAddMode(bwadd);

    gammaRed->setAddMode(bwgadd);
    gammaGreen->setAddMode(bwgadd);
    gammaBlue->setAddMode(bwgadd);
}

void BlackWhite::trimValues (rtengine::procparams::ProcParams* pp)
{

    mixerRed->trimValue (pp->blackwhite.mixerRed);
    mixerGreen->trimValue (pp->blackwhite.mixerGreen);
    mixerBlue->trimValue (pp->blackwhite.mixerBlue);
    gammaRed->trimValue (pp->blackwhite.gammaRed);
    gammaGreen->trimValue (pp->blackwhite.gammaGreen);
    gammaBlue->trimValue (pp->blackwhite.gammaBlue);
    mixerOrange->trimValue (pp->blackwhite.mixerOrange);
    mixerYellow->trimValue (pp->blackwhite.mixerYellow);
    mixerCyan->trimValue (pp->blackwhite.mixerCyan);
    mixerMagenta->trimValue (pp->blackwhite.mixerMagenta);
    mixerPurple->trimValue (pp->blackwhite.mixerPurple);
}

void BlackWhite::showLuminance()
{
    luminanceCEG->show();
    luminanceSep->show();
}

void BlackWhite::hideLuminance()
{
    if (!batchMode) {
        luminanceCEG->hide();
        luminanceSep->hide();
    }
}

void BlackWhite::showFilter()
{
    filterHBox->show();
    filterSep->show();
}

void BlackWhite::hideFilter()
{
    if (!batchMode) {
        filterHBox->hide();
        filterSep->hide();
    }
}

void BlackWhite::showEnabledCC()
{
    enabledcc->show();
    enabledccSep->show();
}

void BlackWhite::hideEnabledCC()
{
    if (!batchMode) {
        enabledcc->hide();
        enabledccSep->hide();
    }
}

void BlackWhite::showMixer(int nChannels, bool RGBIsSensitive)
{
    if (!batchMode) {
        RGBLabels->show();
    }

    if (!batchMode && nChannels == 3) {
        mixerRed->show();
        mixerRed->set_sensitive (RGBIsSensitive);
        mixerGreen->show();
        mixerGreen->set_sensitive (RGBIsSensitive);
        mixerBlue->show();
        mixerBlue->set_sensitive (RGBIsSensitive);
        filterSep2->hide();
        algo->hide();
        alLabel->hide();
        mixerOrange->hide();
        mixerYellow->hide();
        mixerCyan->hide();
        mixerMagenta->hide();
        mixerPurple->hide();
    } else {
        mixerRed->show();
        mixerRed->set_sensitive (true);
        mixerGreen->show();
        mixerGreen->set_sensitive (true);
        mixerBlue->show();
        mixerBlue->set_sensitive (true);
        filterSep2->show();
        mixerOrange->show();
        algo->show();
        alLabel->show();
        mixerYellow->show();
        mixerCyan->show();
        mixerMagenta->show();
        mixerPurple->show();
    }

    mixerFrame->show();
}

void BlackWhite::hideMixer()
{
    if (!batchMode) {
        mixerFrame->hide();
    }
}

void BlackWhite::showGamma()
{
    gammaFrame->show();
}

void BlackWhite::hideGamma()
{
    if (!batchMode) {
        gammaFrame->hide();
    }
}

Glib::ustring BlackWhite::getalgoString()
{
    Glib::ustring retVal;

    if (algo->get_active_row_number() == 0) {
        retVal = "LI";
    } else if (algo->get_active_row_number() == 1) {
        retVal = "SP";
    }

    return retVal;
}

Glib::ustring BlackWhite::getSettingString()
{
    Glib::ustring retVal;

    if (setting->get_active_row_number() == 0) {
        retVal = "NormalContrast";
    } else if (setting->get_active_row_number() == 1) {
        retVal = "HighContrast";
    } else if (setting->get_active_row_number() == 2) {
        retVal = "Luminance";
    } else if (setting->get_active_row_number() == 3) {
        retVal = "Landscape";
    } else if (setting->get_active_row_number() == 4) {
        retVal = "Portrait";
    } else if (setting->get_active_row_number() == 5) {
        retVal = "LowSensitivity";
    } else if (setting->get_active_row_number() == 6) {
        retVal = "HighSensitivity";
    } else if (setting->get_active_row_number() == 7) {
        retVal = "Panchromatic";
    } else if (setting->get_active_row_number() == 8) {
        retVal = "HyperPanchromatic";
    } else if (setting->get_active_row_number() == 9) {
        retVal = "Orthochromatic";
    } else if (setting->get_active_row_number() == 10) {
        retVal = "RGB-Abs";
    } else if (setting->get_active_row_number() == 11) {
        retVal = "RGB-Rel";
    } else if (setting->get_active_row_number() == 12) {
        retVal = "ROYGCBPM-Abs";
    } else if (setting->get_active_row_number() == 13) {
        retVal = "ROYGCBPM-Rel";
    } else if (setting->get_active_row_number() == 14) {
        retVal = "InfraRed";
    }

    return retVal;
}

Glib::ustring BlackWhite::getFilterString()
{
    Glib::ustring retVal;

    if (filter->get_active_row_number() == 0) {
        retVal = "None";
    } else if (filter->get_active_row_number() == 1) {
        retVal = "Red";
    } else if (filter->get_active_row_number() == 2) {
        retVal = "Orange";
    } else if (filter->get_active_row_number() == 3) {
        retVal = "Yellow";
    } else if (filter->get_active_row_number() == 4) {
        retVal = "YellowGreen";
    } else if (filter->get_active_row_number() == 5) {
        retVal = "Green";
    } else if (filter->get_active_row_number() == 6) {
        retVal = "Cyan";
    } else if (filter->get_active_row_number() == 7) {
        retVal = "Blue";
    } else if (filter->get_active_row_number() == 8) {
        retVal = "Purple";
    }

    return retVal;
}
