/*
 *  This file is part of RawTherapee.
 *
 *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>, Oliver Duis
 * <www.oliverduis.de>
 *
 *  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 <http://www.gnu.org/licenses/>.
 */
#include "preferences.h"
#include "../rtengine/dfmanager.h"
#include "../rtengine/ffmanager.h"
#include "addsetids.h"
#include "cachemanager.h"
#include "guiutils.h"
#include "multilangmgr.h"
#include "rtimage.h"
#include "splash.h"
#include <sigc++/slot.h>
#include <sstream>
#ifdef _OPENMP
#include <omp.h>
#endif

#include <gdk/gdkconfig.h>
#ifdef GDK_WINDOWING_QUARTZ
#include <gdk/gdkquartz.h>
#endif

extern Options options;
Glib::RefPtr<Gtk::CssProvider> themecss;
Glib::RefPtr<Gtk::CssProvider> fontcss;

namespace {

std::vector<int> get_theme_color(Gtk::ColorButton *c)
{
    const auto getcol = [](double v) -> int {
        return rtengine::LIM(v * 255, 0., 255.);
    };

    Gdk::RGBA col = c->get_rgba();
    std::vector<int> ret(3);
    ret[0] = getcol(col.get_red());
    ret[1] = getcol(col.get_green());
    ret[2] = getcol(col.get_blue());
    return ret;
}

Glib::ustring getFontFamily(const Pango::FontDescription &fd)
{
    auto res = fd.get_family();
#ifdef __APPLE__
    if (res == ".AppleSystemUIFont") {
        res = "system-ui";
    }
#endif
    return res;
}

} // namespace

Preferences::Preferences(RTWindow *rtwindow)
    : Gtk::Dialog(M("MAIN_BUTTON_PREFERENCES"), *rtwindow, true),
      splash(nullptr), rprofiles(nullptr), iprofiles(nullptr), parent(rtwindow),
      newFont(false), newCPFont(false)
{
    regex = Glib::Regex::create(Options::THEMEREGEXSTR,
                                Glib::RegexCompileFlags::REGEX_CASELESS);

    moptions.copyFrom(&options);

    set_size_request(650, -1);
    set_default_size(options.preferencesWidth, options.preferencesHeight);

    Pango::FontDescription defaultFont = get_style_context()->get_font();
    initialFontFamily = getFontFamily(defaultFont);
    initialFontSize = defaultFont.get_size() / Pango::SCALE;

    Gtk::Box *mainBox = get_content_area();
// GTK318
#if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 20
    mainBox->set_spacing(8);
#endif
    // GTK318

    Gtk::Notebook *nb = Gtk::manage(new Gtk::Notebook());
    nb->set_scrollable(true);
    nb->set_name("PrefNotebook");
    mainBox->pack_start(*nb);

    Gtk::Button *about = Gtk::manage(new Gtk::Button(M("GENERAL_ABOUT")));
    Gtk::Button *ok = Gtk::manage(new Gtk::Button(M("GENERAL_OK")));
    Gtk::Button *cancel = Gtk::manage(new Gtk::Button(M("GENERAL_CANCEL")));

    about->signal_clicked().connect(
        sigc::mem_fun(*this, &Preferences::aboutPressed));
    ok->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::okPressed));
    cancel->signal_clicked().connect(
        sigc::mem_fun(*this, &Preferences::cancelPressed));

    get_action_area()->pack_start(*about);
    get_action_area()->pack_end(*ok);
    get_action_area()->pack_end(*cancel);

    nb->append_page(*getGeneralPanel(), M("PREFERENCES_TAB_GENERAL"));
    nb->append_page(*getImageProcessingPanel(), M("PREFERENCES_TAB_IMPROC"));
    nb->append_page(*getDynamicProfilePanel(),
                    M("PREFERENCES_TAB_DYNAMICPROFILE"));
    nb->append_page(*getFileBrowserPanel(), M("PREFERENCES_TAB_BROWSER"));
    nb->append_page(*getColorManPanel(), M("PREFERENCES_TAB_COLORMGR"));
    nb->append_page(*getPerformancePanel(), M("PREFERENCES_TAB_PERFORMANCE"));
    // Sounds only on Windows and Linux
#if defined(WIN32) || defined(__linux__)
    nb->append_page(*getSoundsPanel(), M("PREFERENCES_TAB_SOUND"));
#endif
    nb->set_current_page(0);

    ProfileStore::getInstance()->addListener(this);

    show_all_children();
    fillPreferences();
}

Preferences::~Preferences()
{

    ProfileStore::getInstance()->removeListener(this);
    get_size(options.preferencesWidth, options.preferencesHeight);
}

int Preferences::getThemeRowNumber(Glib::ustring &longThemeFName)
{

    if (regex->match(longThemeFName + ".css", matchInfo)) {
        for (size_t i = 0; i < themeFNames.size(); ++i) {
            if (themeFNames.at(i).longFName == longThemeFName) {
                return (int)i;
            }
        }
    }

    return -1;
}

Gtk::Widget *Preferences::getDynamicProfilePanel()
{
    swDynamicProfile = Gtk::manage(new Gtk::ScrolledWindow());
    swDynamicProfile->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

    dynProfilePanel = Gtk::manage(new DynamicProfilePanel());

    swDynamicProfile->add(*dynProfilePanel);
    return swDynamicProfile;
}

Gtk::Widget *Preferences::getImageProcessingPanel()
{
    swImageProcessing = Gtk::manage(new Gtk::ScrolledWindow());
    swImageProcessing->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

    Gtk::VBox *vbImageProcessing = Gtk::manage(new Gtk::VBox());

    Gtk::Frame *fpp =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_IMPROCPARAMS")));
    Gtk::VBox *vbpp = Gtk::manage(new Gtk::VBox());
    Gtk::Label *drlab = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_FORRAW") + ":", Gtk::ALIGN_START));
    rprofiles = Gtk::manage(new ProfileStoreComboBox());
    const ProfileStoreEntry *dynpse =
        ProfileStore::getInstance()->getInternalDynamicPSE();
    rprofiles->addRow(dynpse);
    setExpandAlignProperties(rprofiles, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    rprofiles->set_size_request(50, -1);
    rpconn = rprofiles->signal_changed().connect(
        sigc::mem_fun(*this, &Preferences::forRAWComboChanged));
    Gtk::Label *drimg = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_FORIMAGE") + ":", Gtk::ALIGN_START));
    iprofiles = Gtk::manage(new ProfileStoreComboBox());
    iprofiles->addRow(dynpse);
    iprofiles->set_size_request(50, -1);
    setExpandAlignProperties(iprofiles, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_FILL);
    ipconn = iprofiles->signal_changed().connect(
        sigc::mem_fun(*this, &Preferences::forImageComboChanged));
    Gtk::Table *defpt = Gtk::manage(new Gtk::Table(2, 2));
    defpt->attach(*drlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2);
    defpt->attach(*rprofiles, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK,
                  Gtk::SHRINK, 2, 2);
    defpt->attach(*drimg, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2);
    defpt->attach(*iprofiles, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK,
                  Gtk::SHRINK, 2, 2);
    vbpp->pack_start(*defpt, Gtk::PACK_SHRINK, 4);
    useBundledProfiles =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_USEBUNDLEDPROFILES")));
    bpconn = useBundledProfiles->signal_clicked().connect(
        sigc::mem_fun(*this, &Preferences::bundledProfilesChanged));
    vbpp->pack_start(*useBundledProfiles, Gtk::PACK_SHRINK, 4);
    fpp->add(*vbpp);
    vbImageProcessing->pack_start(*fpp, Gtk::PACK_SHRINK, 4);

    // Custom profile builder box
    Gtk::Frame *cpfrm =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_CUSTPROFBUILD")));
    Gtk::Label *cplab = Gtk::manage(new Gtk::Label(
        M("PREFERENCES_CUSTPROFBUILDPATH") + ":", Gtk::ALIGN_START));
    txtCustProfBuilderPath = Gtk::manage(new Gtk::Entry());
    txtCustProfBuilderPath->set_tooltip_markup(
        M("PREFERENCES_CUSTPROFBUILDHINT"));
    Gtk::Label *cpltypelab = Gtk::manage(new Gtk::Label(
        M("PREFERENCES_CUSTPROFBUILDKEYFORMAT") + ":", Gtk::ALIGN_START));
    custProfBuilderLabelType = Gtk::manage(new Gtk::ComboBoxText());
    custProfBuilderLabelType->append(
        M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_TID"));
    custProfBuilderLabelType->append(
        M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_NAME"));
    custProfBuilderLabelType->append(
        M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_TID") + "_" +
        M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_NAME"));
    Gtk::Table *cpbt = Gtk::manage(new Gtk::Table(2, 2));
    cpbt->attach(*cplab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2);
    cpbt->attach(*txtCustProfBuilderPath, 1, 2, 0, 1,
                 Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2);
    cpbt->attach(*cpltypelab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2);
    cpbt->attach(*custProfBuilderLabelType, 1, 2, 1, 2,
                 Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2);
    cpfrm->add(*cpbt);
    vbImageProcessing->pack_start(*cpfrm, Gtk::PACK_SHRINK, 4);

    Gtk::Frame *fdp =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_PROFILEHANDLING")));
    Gtk::Table *vbdp = Gtk::manage(new Gtk::Table(2, 2));
    saveParamsPreference = Gtk::manage(new Gtk::ComboBoxText());
    saveParamsPreference->append(M("PREFERENCES_PROFILESAVEINPUT"));
    saveParamsPreference->append(M("PREFERENCES_PROFILESAVECACHE"));
    saveParamsPreference->append(M("PREFERENCES_PROFILESAVEBOTH"));
    Gtk::Label *splab =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_PROFILESAVELOCATION") + ":"));
    setExpandAlignProperties(splab, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    vbdp->attach(*splab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2);
    vbdp->attach(*saveParamsPreference, 1, 2, 0, 1,
                 Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2);
    Gtk::Label *lplab =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_PROFILELOADPR") + ":"));
    loadParamsPreference = Gtk::manage(new Gtk::ComboBoxText());
    loadParamsPreference->append(M("PREFERENCES_PROFILEPRCACHE"));
    loadParamsPreference->append(M("PREFERENCES_PROFILEPRFILE"));
    vbdp->attach(*lplab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2);
    setExpandAlignProperties(lplab, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    vbdp->attach(*loadParamsPreference, 1, 2, 1, 2,
                 Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2);

    lplab =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_PROFILE_SAVE_OUTPUT") + ":"));
    saveOutParamsPreference = Gtk::manage(new Gtk::ComboBoxText());
    saveOutParamsPreference->append(
        M("PREFERENCES_PROFILE_SAVE_OUTPUT_SIDECAR"));
    saveOutParamsPreference->append(
        M("PREFERENCES_PROFILE_SAVE_OUTPUT_EMBEDDED"));
    vbdp->attach(*lplab, 0, 1, 2, 3, Gtk::FILL, Gtk::SHRINK, 2, 2);
    setExpandAlignProperties(lplab, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    vbdp->attach(*saveOutParamsPreference, 1, 2, 2, 3,
                 Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2);

    lplab = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_PARAMS_SIDECAR_STYLE") + ":"));
    paramsSidecarStripExtension = Gtk::manage(new Gtk::ComboBoxText());
    paramsSidecarStripExtension->append(M("PREFERENCES_PARAMS_SIDECAR_FULL"));
    paramsSidecarStripExtension->append(
        M("PREFERENCES_PARAMS_SIDECAR_STRIP_EXT"));
    vbdp->attach(*lplab, 0, 1, 3, 4, Gtk::FILL, Gtk::SHRINK, 2, 2);
    setExpandAlignProperties(lplab, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    vbdp->attach(*paramsSidecarStripExtension, 1, 2, 3, 4,
                 Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2);

    fdp->add(*vbdp);
    vbImageProcessing->pack_start(*fdp, Gtk::PACK_SHRINK, 4);

    // Metadata
    Gtk::Frame *mf = Gtk::manage(new Gtk::Frame(M("PREFERENCES_METADATA")));
    Gtk::Grid *mtbl = Gtk::manage(new Gtk::Grid());
    setExpandAlignProperties(mtbl, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);

    metadataSyncCombo = Gtk::manage(new Gtk::ComboBoxText());
    metadataSyncCombo->set_active(0);
    metadataSyncCombo->append(M("PREFERENCES_METADATA_SYNC_NONE"));
    metadataSyncCombo->append(M("PREFERENCES_METADATA_SYNC_READ"));
    metadataSyncCombo->append(M("PREFERENCES_METADATA_SYNC_READWRITE"));
    Gtk::Label *mlbl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_METADATA_SYNC") + ": "));
    mtbl->attach(*mlbl, 0, 0, 1, 1);
    mtbl->attach_next_to(*metadataSyncCombo, *mlbl, Gtk::POS_RIGHT, 1, 1);
    setExpandAlignProperties(mlbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    setExpandAlignProperties(metadataSyncCombo, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);

    xmpSidecarCombo = Gtk::manage(new Gtk::ComboBoxText());
    xmpSidecarCombo->set_active(0);
    xmpSidecarCombo->append(M("PREFERENCES_XMP_SIDECAR_MODE_STD"));
    xmpSidecarCombo->append(M("PREFERENCES_XMP_SIDECAR_MODE_EXT"));

    mlbl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_XMP_SIDECAR_MODE") + ": "));
    mtbl->attach(*mlbl, 0, 2, 1, 1);
    mtbl->attach_next_to(*xmpSidecarCombo, *mlbl, Gtk::POS_RIGHT, 1, 1);
    setExpandAlignProperties(mlbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    setExpandAlignProperties(xmpSidecarCombo, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);

    mlbl = Gtk::manage(new Gtk::Label(M("PREFERENCES_EXIFTOOL_PATH") + ": "));
    mtbl->attach(*mlbl, 0, 3, 1, 1);
    exiftoolPath = Gtk::manage(new Gtk::Entry());
    exiftoolPath->set_tooltip_text(M("PREFERENCES_EXIFTOOL_PATH_TOOLTIP"));
    {
        Gtk::HBox *hb = Gtk::manage(new Gtk::HBox());
        hb->pack_start(*exiftoolPath, Gtk::PACK_EXPAND_WIDGET);
        // mtbl->attach_next_to(*exiftoolPath, *mlbl, Gtk::POS_RIGHT, 1, 1);
        mtbl->attach_next_to(*hb, *mlbl, Gtk::POS_RIGHT, 1, 1);
        show_exiftool_makernotes = Gtk::manage(
            new Gtk::CheckButton(M("PREFERENCES_SHOW_EXIFTOOL_MAKERNOTES")));
        hb->pack_start(*show_exiftool_makernotes, Gtk::PACK_SHRINK, 4);
    }
    setExpandAlignProperties(mlbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    setExpandAlignProperties(exiftoolPath, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);

    mf->add(*mtbl);
    vbImageProcessing->pack_start(*mf, Gtk::PACK_SHRINK, 4);

    // Directories
    Gtk::Frame *cdf = Gtk::manage(new Gtk::Frame(M("PREFERENCES_DIRECTORIES")));
    Gtk::Grid *dirgrid = Gtk::manage(new Gtk::Grid());
    setExpandAlignProperties(dirgrid, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);

    Gtk::Label *dfLab =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_DIRDARKFRAMES") + ":"));
    setExpandAlignProperties(dfLab, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    darkFrameDir = Gtk::manage(
        new MyFileChooserButton(M("PREFERENCES_DIRDARKFRAMES"),
                                Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
    setExpandAlignProperties(darkFrameDir, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    dfLabel = Gtk::manage(new Gtk::Label("Found:"));
    setExpandAlignProperties(dfLabel, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    dirgrid->attach_next_to(*dfLab, Gtk::POS_TOP, 1, 1);
    dirgrid->attach_next_to(*darkFrameDir, *dfLab, Gtk::POS_RIGHT, 1, 1);
    dirgrid->attach_next_to(*dfLabel, *darkFrameDir, Gtk::POS_RIGHT, 1, 1);

    dfconn = darkFrameDir->signal_selection_changed().connect(
        sigc::mem_fun(*this, &Preferences::darkFrameChanged));

    // FLATFIELD
    Gtk::Label *ffLab =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_FLATFIELDSDIR") + ":"));
    setExpandAlignProperties(ffLab, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    flatFieldDir = Gtk::manage(
        new MyFileChooserButton(M("PREFERENCES_FLATFIELDSDIR"),
                                Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
    setExpandAlignProperties(flatFieldDir, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    ffLabel = Gtk::manage(new Gtk::Label("Found:"));
    setExpandAlignProperties(ffLabel, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    dirgrid->attach_next_to(*ffLab, *dfLab, Gtk::POS_BOTTOM, 1, 1);
    dirgrid->attach_next_to(*flatFieldDir, *ffLab, Gtk::POS_RIGHT, 1, 1);
    dirgrid->attach_next_to(*ffLabel, *flatFieldDir, Gtk::POS_RIGHT, 1, 1);

    ffconn = flatFieldDir->signal_selection_changed().connect(
        sigc::mem_fun(*this, &Preferences::flatFieldChanged));

    // Cluts Dir
    Gtk::Label *clutsDirLabel =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_CLUTSDIR") + ":"));
    setExpandAlignProperties(clutsDirLabel, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    clutsDir = Gtk::manage(new MyFileChooserButton(
        M("PREFERENCES_CLUTSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
    setExpandAlignProperties(clutsDir, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    Gtk::Label *clutsRestartNeeded = Gtk::manage(new Gtk::Label(
        Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    setExpandAlignProperties(clutsRestartNeeded, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    dirgrid->attach_next_to(*clutsDirLabel, *ffLab, Gtk::POS_BOTTOM, 1, 1);
    dirgrid->attach_next_to(*clutsDir, *clutsDirLabel, Gtk::POS_RIGHT, 1, 1);
    dirgrid->attach_next_to(*clutsRestartNeeded, *clutsDir, Gtk::POS_RIGHT, 1,
                            1);

    cdf->add(*dirgrid);
    vbImageProcessing->pack_start(*cdf, Gtk::PACK_SHRINK, 4);

    Gtk::Frame *owf =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_BATCH_PROCESSING")));
    chOverwriteOutputFile =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_OVERWRITEOUTPUTFILE")));
    owf->add(*chOverwriteOutputFile);

    Gtk::HBox *hb = Gtk::manage(new Gtk::HBox());
    hb->pack_start(*owf, Gtk::PACK_EXPAND_WIDGET);
    hb->pack_start(*Gtk::manage(new Gtk::Label("  ")), Gtk::PACK_SHRINK);

    owf = Gtk::manage(new Gtk::Frame(M("PREFERENCES_AUTOSAVE")));
    autosaveInterval = Gtk::manage(new Gtk::SpinButton());
    autosaveInterval->set_digits(0);
    autosaveInterval->set_max_length(2);
    autosaveInterval->set_range(0, 60);
    autosaveInterval->set_increments(1, 1);
    {
        Gtk::HBox *hb2 = Gtk::manage(new Gtk::HBox());
        auto lbl =
            Gtk::manage(new Gtk::Label(M("PREFERENCES_AUTOSAVE_INTERVAL")));
        hb2->pack_start(*lbl, Gtk::PACK_EXPAND_WIDGET, 4);
        setExpandAlignProperties(lbl, false, false, Gtk::ALIGN_START,
                                 Gtk::ALIGN_CENTER);
        hb2->pack_start(*autosaveInterval, Gtk::PACK_SHRINK);
        hb2->pack_start(*Gtk::manage(new Gtk::Label(
                            " (" + M("PREFERENCES_APPLNEXTSTARTUP") + ")")),
                        Gtk::PACK_SHRINK, 4);
        owf->add(*hb2);
    }
    hb->pack_start(*owf, Gtk::PACK_EXPAND_WIDGET);

    vbImageProcessing->pack_start(*hb, Gtk::PACK_SHRINK, 4);

    swImageProcessing->add(*vbImageProcessing);

    return swImageProcessing;
}

Gtk::Widget *Preferences::getPerformancePanel()
{
    swPerformance = Gtk::manage(new Gtk::ScrolledWindow());
    swPerformance->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

    Gtk::VBox *vbPerformance = Gtk::manage(new Gtk::VBox());
    vbPerformance->set_spacing(4);

    Gtk::Frame *fprevdemo =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_PREVDEMO")));
    Gtk::HBox *hbprevdemo = Gtk::manage(new Gtk::HBox(false, 4));

    Gtk::Label *lprevdemo = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_PREVIEW_RESAMPLING_QUALITY")));

    preview_resampling_quality = Gtk::manage(new Gtk::ComboBoxText());
    preview_resampling_quality->append(M("GENERAL_LOW"));
    preview_resampling_quality->append(M("GENERAL_MEDIUM"));
    preview_resampling_quality->append(M("GENERAL_HIGH"));
    preview_resampling_quality->set_active(1);
    hbprevdemo->pack_start(*lprevdemo, Gtk::PACK_SHRINK);
    hbprevdemo->pack_start(*preview_resampling_quality);
    Gtk::VBox *vb = Gtk::manage(new Gtk::VBox());
    vb->pack_start(*hbprevdemo);

    hbprevdemo = Gtk::manage(new Gtk::HBox(false, 4));
    lprevdemo = Gtk::manage(new Gtk::Label(M("PREFERENCES_PREVDEMO_LABEL")));
    cprevdemo = Gtk::manage(new Gtk::ComboBoxText());
    cprevdemo->append(M("PREFERENCES_PREVDEMO_FAST"));
    cprevdemo->append(M("PREFERENCES_PREVDEMO_SIDECAR"));
    cprevdemo->set_active(1);
    hbprevdemo->pack_start(*lprevdemo, Gtk::PACK_SHRINK);
    hbprevdemo->pack_start(*cprevdemo);
    // fprevdemo->add (*hbprevdemo);
    // vb = Gtk::manage(new Gtk::VBox());
    vb->pack_start(*hbprevdemo);

    hbprevdemo = Gtk::manage(new Gtk::HBox(false, 4));
    hbprevdemo->pack_start(
        *Gtk::manage(new Gtk::Label(M("PREFERENCES_WBPREVIEW_LABEL"))),
        Gtk::PACK_SHRINK);
    wbpreview = Gtk::manage(new Gtk::ComboBoxText());
    wbpreview->append(M("PREFERENCES_WBPREVIEW_AFTER"));
    wbpreview->append(M("PREFERENCES_WBPREVIEW_BEFORE"));
    wbpreview->append(M("PREFERENCES_WBPREVIEW_BEFORE_HIGH_DETAIL"));
    hbprevdemo->pack_start(*wbpreview);
    vb->pack_start(*hbprevdemo);

    denoiseZoomedOut =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_DENOISE_ZOOM_OUT")));
    denoiseZoomedOut->set_tooltip_text(
        M("PREFERENCES_DENOISE_ZOOM_OUT_TOOLTIP"));
    vb->pack_start(*denoiseZoomedOut);
    ctl_scripts_fast_preview_ = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_CTL_SCRIPTS_FAST_PREVIEW")));
#ifdef ART_USE_CTL
    vb->pack_start(*ctl_scripts_fast_preview_);
#endif
    fprevdemo->add(*vb);
    vbPerformance->pack_start(*fprevdemo, Gtk::PACK_SHRINK, 4);

    Gtk::Frame *ftiffserialize =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_SERIALIZE_TIFF_READ")));
    Gtk::HBox *htiffserialize = Gtk::manage(new Gtk::HBox(false, 4));
    ctiffserialize = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_SERIALIZE_TIFF_READ_LABEL")));
    ctiffserialize->set_tooltip_text(
        M("PREFERENCES_SERIALIZE_TIFF_READ_TOOLTIP"));
    htiffserialize->pack_start(*ctiffserialize);
    ftiffserialize->add(*htiffserialize);
    vbPerformance->pack_start(*ftiffserialize, Gtk::PACK_SHRINK, 4);

    Gtk::Frame *fclut =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_CLUTSCACHE")));
    Gtk::HBox *clutCacheSizeHB = Gtk::manage(new Gtk::HBox());
    clutCacheSizeHB->set_spacing(4);
    Gtk::Label *CLUTLl = Gtk::manage(new Gtk::Label(
        M("PREFERENCES_CLUTSCACHE_LABEL") + ":", Gtk::ALIGN_START));
    clutCacheSizeSB = Gtk::manage(new Gtk::SpinButton());
    clutCacheSizeSB->set_digits(0);
    clutCacheSizeSB->set_increments(1, 5);
    clutCacheSizeSB->set_max_length(2);
    clutCacheSizeSB->set_range(1, 50);
    clutCacheSizeHB->pack_start(*CLUTLl, Gtk::PACK_SHRINK, 0);
    clutCacheSizeHB->pack_end(*clutCacheSizeSB, Gtk::PACK_SHRINK, 0);
    fclut->add(*clutCacheSizeHB);
    vbPerformance->pack_start(*fclut, Gtk::PACK_SHRINK, 4);

    Gtk::Frame *finspect =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_INSPECT_LABEL")));
    Gtk::HBox *maxIBuffersHB = Gtk::manage(new Gtk::HBox());
    maxIBuffersHB->set_spacing(4);
    maxIBuffersHB->set_tooltip_text(
        M("PREFERENCES_INSPECT_MAXBUFFERS_TOOLTIP"));
    Gtk::Label *maxIBufferLbl = Gtk::manage(new Gtk::Label(
        M("PREFERENCES_INSPECT_MAXBUFFERS_LABEL") + ":", Gtk::ALIGN_START));
    maxInspectorBuffersSB = Gtk::manage(new Gtk::SpinButton());
    maxInspectorBuffersSB->set_digits(0);
    maxInspectorBuffersSB->set_increments(1, 5);
    maxInspectorBuffersSB->set_max_length(2);
    maxInspectorBuffersSB->set_range(
        1, 12); // ... we have to set a limit, 12 seem to be enough even for
                // systems with tons of RAM
    maxIBuffersHB->pack_start(*maxIBufferLbl, Gtk::PACK_SHRINK, 0);
    maxIBuffersHB->pack_end(*maxInspectorBuffersSB, Gtk::PACK_SHRINK, 0);

    Gtk::VBox *inspectorvb = Gtk::manage(new Gtk::VBox());
    inspectorvb->add(*maxIBuffersHB);

    finspect->add(*inspectorvb);
    vbPerformance->pack_start(*finspect, Gtk::PACK_SHRINK, 4);

    Gtk::Frame *threadsFrame =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_PERFORMANCE_THREADS")));
    Gtk::VBox *threadsVBox = Gtk::manage(new Gtk::VBox(Gtk::PACK_SHRINK, 4));

    Gtk::HBox *threadsHBox = Gtk::manage(new Gtk::HBox(Gtk::PACK_SHRINK, 4));
    Gtk::Label *threadsLbl = Gtk::manage(new Gtk::Label(
        M("PREFERENCES_PERFORMANCE_THREADS_LABEL") + ":", Gtk::ALIGN_START));
    threadsSpinBtn = Gtk::manage(new Gtk::SpinButton());
    threadsSpinBtn->set_digits(0);
    threadsSpinBtn->set_increments(1, 5);
    threadsSpinBtn->set_max_length(2); // Will this be sufficient? :)
#ifdef _OPENMP
    int maxThreadNumber = omp_get_num_procs();
#else
    int maxThreadNumber = 10;
#endif
    threadsSpinBtn->set_range(0, maxThreadNumber);

    threadsHBox->pack_start(*threadsLbl, Gtk::PACK_SHRINK, 2);
    threadsHBox->pack_end(*threadsSpinBtn, Gtk::PACK_SHRINK, 2);

    threadsVBox->pack_start(*threadsHBox, Gtk::PACK_SHRINK);

    threadsHBox = Gtk::manage(new Gtk::HBox(Gtk::PACK_SHRINK, 4));
    threadsLbl = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_PERFORMANCE_THREADS_THUMB_UPDATE") +
                           " (" + M("PREFERENCES_APPLNEXTSTARTUP") + ")" + ":",
                       Gtk::ALIGN_START));
    thumbUpdateThreadLimit = Gtk::manage(new Gtk::SpinButton());
    thumbUpdateThreadLimit->set_digits(0);
    thumbUpdateThreadLimit->set_increments(1, 5);
    thumbUpdateThreadLimit->set_max_length(2); // Will this be sufficient? :)
    thumbUpdateThreadLimit->set_range(0, maxThreadNumber);
    threadsHBox->pack_start(*threadsLbl, Gtk::PACK_SHRINK, 2);
    threadsHBox->pack_end(*thumbUpdateThreadLimit, Gtk::PACK_SHRINK, 2);
    threadsVBox->pack_start(*threadsHBox, Gtk::PACK_SHRINK);

    threadsFrame->add(*threadsVBox);

    vbPerformance->pack_start(*threadsFrame, Gtk::PACK_SHRINK, 4);

    Gtk::Frame *thumbFrame =
        Gtk::manage(new Gtk::Frame(M("MAIN_FRAME_FILEBROWSER")));
    thumbDelayUpdate = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_THUMBNAIL_DELAY_UPDATE")));
    thumbLazyCaching = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_THUMBNAIL_LAZY_CACHING")));
    thumb_cache_processed_ = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_THUMBNAIL_CACHE_PROCESSED")));
    {
        Gtk::VBox *vb = Gtk::manage(new Gtk::VBox());
        vb->pack_start(*thumb_cache_processed_);
        vb->pack_start(*thumbLazyCaching);
        vb->pack_start(*thumbDelayUpdate);
        thumbFrame->add(*vb);
    }
    vbPerformance->pack_start(*thumbFrame, Gtk::PACK_SHRINK, 4);

    Gtk::Frame *fe_frame =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_TAB_FASTEXPORT")));
    {
        Gtk::HBox *hbox = Gtk::manage(new Gtk::HBox());
        fastexport_max_width = Gtk::manage(new MySpinButton());
        fastexport_max_height = Gtk::manage(new MySpinButton());
        hbox->pack_start(*Gtk::manage(new Gtk::Label(M("EXPORT_MAXWIDTH"))),
                         Gtk::PACK_SHRINK, 4);
        hbox->pack_start(*fastexport_max_width);
        hbox->pack_start(*Gtk::manage(new Gtk::Label(M("EXPORT_MAXHEIGHT"))),
                         Gtk::PACK_SHRINK, 4);
        hbox->pack_start(*fastexport_max_height);
        fe_frame->add(*hbox);

        fastexport_max_width->set_digits(0);
        fastexport_max_width->set_width_chars(5);
        fastexport_max_width->set_max_width_chars(5);
        fastexport_max_width->set_increments(1, 100);
        fastexport_max_width->set_range(32, 10000);

        fastexport_max_height->set_digits(0);
        fastexport_max_height->set_width_chars(5);
        fastexport_max_height->set_max_width_chars(5);
        fastexport_max_height->set_increments(1, 100);
        fastexport_max_height->set_range(32, 10000);
    }
    vbPerformance->pack_start(*fe_frame, Gtk::PACK_SHRINK, 4);

    swPerformance->add(*vbPerformance);

    return swPerformance;
}

Gtk::Widget *Preferences::getColorManPanel()
{
    swColorMan = Gtk::manage(new Gtk::ScrolledWindow());
    swColorMan->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

    Gtk::VBox *vbColorMan = Gtk::manage(new Gtk::VBox());
    vbColorMan->set_spacing(4);

    iccDir = Gtk::manage(new MyFileChooserButton(
        M("PREFERENCES_ICCDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
    setExpandAlignProperties(iccDir, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    Gtk::Label *pdlabel = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_ICCDIR") + ":", Gtk::ALIGN_START));
    setExpandAlignProperties(pdlabel, false, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);

    Gtk::Grid *iccdgrid = Gtk::manage(new Gtk::Grid());
    setExpandAlignProperties(iccdgrid, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_FILL);
    iccdgrid->set_column_spacing(4);

    Gtk::Label *monProfileRestartNeeded = Gtk::manage(new Gtk::Label(
        Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    setExpandAlignProperties(monProfileRestartNeeded, false, false,
                             Gtk::ALIGN_START, Gtk::ALIGN_BASELINE);

    iccdgrid->attach(*pdlabel, 0, 0, 1, 1);
    iccdgrid->attach(*iccDir, 1, 0, 1, 1);

    iccdgrid->attach(*monProfileRestartNeeded, 2, 0, 1, 1);

    // iccDir->signal_selection_changed ().connect (sigc::mem_fun (this,
    // &Preferences::iccDirChanged));

    vbColorMan->pack_start(*iccdgrid, Gtk::PACK_SHRINK);

    monitorIccDir = Gtk::manage(
        new MyFileChooserButton(M("PREFERENCES_MONITORICCDIR"),
                                Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
    setExpandAlignProperties(monitorIccDir, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    pdlabel = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_MONITORICCDIR") + ":", Gtk::ALIGN_START));
    setExpandAlignProperties(pdlabel, false, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);

    iccdgrid = Gtk::manage(new Gtk::Grid());
    setExpandAlignProperties(iccdgrid, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_FILL);
    iccdgrid->set_column_spacing(4);

    monProfileRestartNeeded = Gtk::manage(new Gtk::Label(
        Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    setExpandAlignProperties(monProfileRestartNeeded, false, false,
                             Gtk::ALIGN_START, Gtk::ALIGN_BASELINE);

    iccdgrid->attach(*pdlabel, 0, 0, 1, 1);
    iccdgrid->attach(*monitorIccDir, 1, 0, 1, 1);
    iccdgrid->attach(*monProfileRestartNeeded, 2, 0, 1, 1);

    monitorIccDir->signal_selection_changed().connect(
        sigc::mem_fun(this, &Preferences::iccDirChanged));

    if (rtengine::Settings::color_mgmt_mode ==
        rtengine::Settings::ColorManagementMode::APPLICATION) {
        vbColorMan->pack_start(*iccdgrid, Gtk::PACK_SHRINK);
    }

    //------------------------- MONITOR ----------------------

    Gtk::Frame *fmonitor =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_MONITOR")));
    Gtk::Grid *gmonitor = Gtk::manage(new Gtk::Grid());
    gmonitor->set_column_spacing(4);

    monProfile = Gtk::manage(new Gtk::ComboBoxText());
    setExpandAlignProperties(monProfile, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    Gtk::Label *mplabel = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_MONPROFILE") + ":", Gtk::ALIGN_START));
    setExpandAlignProperties(mplabel, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    monIntent = Gtk::manage(new Gtk::ComboBoxText());
    setExpandAlignProperties(monIntent, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    Gtk::Label *milabel = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_MONINTENT") + ":", Gtk::ALIGN_START));
    setExpandAlignProperties(milabel, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    if (rtengine::Settings::color_mgmt_mode ==
        rtengine::Settings::ColorManagementMode::APPLICATION) {
        monProfile->append(M("PREFERENCES_PROFILE_NONE"));
        monProfile->set_active(0);

        const std::vector<Glib::ustring> profiles =
            rtengine::ICCStore::getInstance()->getProfilesFromDir(
                options.rtSettings.monitorIccDirectory);

        for (const auto &profile : profiles) {
            if (profile.find("file:") != 0) {
                monProfile->append(profile);
            }
        }
    }

    // same order as the enum
    monIntent->append(M("PREFERENCES_INTENT_PERCEPTUAL"));
    monIntent->append(M("PREFERENCES_INTENT_RELATIVE"));
    monIntent->append(M("PREFERENCES_INTENT_ABSOLUTE"));
    monIntent->set_active(1);
    monIntent->set_size_request(120, -1);

    monBPC = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_CMMBPC")));
    setExpandAlignProperties(monBPC, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    monBPC->set_active(true);

    cbAutoMonProfile =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_AUTOMONPROFILE")));
    setExpandAlignProperties(cbAutoMonProfile, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    autoMonProfileConn = cbAutoMonProfile->signal_toggled().connect(
        sigc::mem_fun(*this, &Preferences::autoMonProfileToggled));

    int row = 0;
    gmonitor->attach(*mplabel, 0, row, 1, 1);
    if (rtengine::Settings::color_mgmt_mode !=
        rtengine::Settings::ColorManagementMode::APPLICATION) {
        for (int j = 0; j < 3; ++j) {
            auto p = rtengine::ICCStore::getInstance()->getStdMonitorProfile(
                rtengine::Settings::StdMonitorProfile(j));
            if (p) {
                auto lbl = rtengine::ICCStore::getProfileTag(
                    p, cmsSigProfileDescriptionTag);
                if (lbl.size() > 9 &&
                    lbl.substr(lbl.size() - 9) == " (ICC V4)") {
                    lbl = lbl.substr(0, lbl.size() - 9);
                }
                monProfile->append(lbl);
            }
        }
        if (rtengine::Settings::color_mgmt_mode ==
            rtengine::Settings::ColorManagementMode::OS_SRGB) {
            Gtk::Label *oswarn = Gtk::manage(new Gtk::Label(
                M("PREFERENCES_MONPROFILE_WARN_SRGB"), Gtk::ALIGN_START));
            setExpandAlignProperties(oswarn, false, false, Gtk::ALIGN_CENTER,
                                     Gtk::ALIGN_CENTER);
            gmonitor->attach(*oswarn, 1, row, 1, 1);
        } else {
            mplabel->set_text(M("PREFERENCES_MONITOR_GAMUT") + ":");
            gmonitor->attach(*monProfile, 1, row, 1, 1);
            auto rst = Gtk::manage(new Gtk::Label(
                Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
            setExpandAlignProperties(rst, false, false, Gtk::ALIGN_START,
                                     Gtk::ALIGN_BASELINE);
            gmonitor->attach(*rst, 2, row, 1, 1);
            ++row;
            auto infolbl = Gtk::manage(new Gtk::Label(
                M("PREFERENCES_OSCOLORMGMT_INFO"), Gtk::ALIGN_START));
            gmonitor->attach(*infolbl, 0, row, 3, 1);
            ++row;
        }
    } else {
        gmonitor->attach(*mplabel, 0, row, 1, 1);
        gmonitor->attach(*monProfile, 1, row, 1, 1);
        ++row;
        gmonitor->attach(*cbAutoMonProfile, 1, row, 1, 1);
        ++row;
        gmonitor->attach(*milabel, 0, row, 1, 1);
        gmonitor->attach(*monIntent, 1, row, 1, 1);
        ++row;
        gmonitor->attach(*monBPC, 0, row, 2, 1);

        autoMonProfileToggled();
    }

    fmonitor->add(*gmonitor);

    vbColorMan->pack_start(*fmonitor, Gtk::PACK_SHRINK);

    //------------------------- PRINTER ----------------------

    Gtk::Frame *fprinter =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_PRINTER")));
    Gtk::Grid *gprinter = Gtk::manage(new Gtk::Grid());
    gprinter->set_column_spacing(4);
    prtProfile = Gtk::manage(new MyFileChooserButton(
        M("PREFERENCES_PRTPROFILE"), Gtk::FILE_CHOOSER_ACTION_OPEN));
    {
        auto filter_icc = Gtk::FileFilter::create();
        filter_icc->set_name(M("FILECHOOSER_FILTER_COLPROF"));
        filter_icc->add_pattern("*.icc");
        filter_icc->add_pattern("*.icm");
        filter_icc->add_pattern("*.ICC");
        filter_icc->add_pattern("*.ICM");
        prtProfile->set_filter(filter_icc);
    }
    setExpandAlignProperties(prtProfile, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    Gtk::Label *pplabel =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_PRTPROFILE") + ":"));
    setExpandAlignProperties(pplabel, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    prtIntent = Gtk::manage(new Gtk::ComboBoxText());
    setExpandAlignProperties(prtIntent, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    Gtk::Label *pilabel =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_PRTINTENT") + ":"));
    setExpandAlignProperties(pilabel, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    // prtProfile->append (M ("PREFERENCES_PROFILE_NONE"));
    // prtProfile->set_active (0);

    // const std::vector<Glib::ustring> prtprofiles =
    // rtengine::ICCStore::getInstance ()->getProfiles
    // (rtengine::ICCStore::ProfileType::PRINTER);

    // for (const auto &prtprofile : prtprofiles) {
    //     prtProfile->append (prtprofile);
    // }

    // same order as the enum
    prtIntent->append(M("PREFERENCES_INTENT_PERCEPTUAL"));
    prtIntent->append(M("PREFERENCES_INTENT_RELATIVE"));
    prtIntent->append(M("PREFERENCES_INTENT_ABSOLUTE"));
    prtIntent->set_active(1);

    prtBPC = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_CMMBPC")));
    setExpandAlignProperties(prtBPC, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    prtBPC->set_active(true);

    row = 0;
    gprinter->attach(*pplabel, 0, row, 1, 1);
    gprinter->attach(*prtProfile, 1, row, 1, 1);
    ++row;
    gprinter->attach(*pilabel, 0, row, 1, 1);
    gprinter->attach(*prtIntent, 1, row, 1, 1);
    ++row;
    gprinter->attach(*prtBPC, 0, row, 2, 1);

    autoMonProfileToggled();

    fprinter->add(*gprinter);

    vbColorMan->pack_start(*fprinter, Gtk::PACK_SHRINK);

    swColorMan->add(*vbColorMan);
    return swColorMan;
}

Gtk::Widget *Preferences::getGeneralPanel()
{
    swGeneral = Gtk::manage(new Gtk::ScrolledWindow());
    swGeneral->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

    Gtk::Grid *vbGeneral = Gtk::manage(new Gtk::Grid());
    vbGeneral->set_column_spacing(4);
    vbGeneral->set_row_spacing(4);

    Gtk::Frame *fworklflow =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_WORKFLOW")));
    setExpandAlignProperties(fworklflow, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_START);
    Gtk::Grid *workflowGrid = Gtk::manage(new Gtk::Grid());
    workflowGrid->set_column_spacing(4);
    workflowGrid->set_row_spacing(4);
    setExpandAlignProperties(workflowGrid, false, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_FILL);

    Gtk::Label *flayoutlab =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_EDITORLAYOUT") + ":"));
    setExpandAlignProperties(flayoutlab, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    editorLayout = Gtk::manage(new MyComboBoxText());
    setExpandAlignProperties(editorLayout, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_BASELINE);
    editorLayout->append(M("PREFERENCES_SINGLETAB"));
    editorLayout->append(M("PREFERENCES_SINGLETABBOTTOM"));
    editorLayout->append(M("PREFERENCES_MULTITAB"));
    editorLayout->append(M("PREFERENCES_MULTITABDUALMON"));
    editorLayout->set_active(2);
    Gtk::CellRendererText *cellRenderer =
        dynamic_cast<Gtk::CellRendererText *>(editorLayout->get_first_cell());
    cellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE;
    cellRenderer->property_ellipsize_set() = true;
    editorLayout->signal_changed().connect(
        sigc::mem_fun(*this, &Preferences::layoutComboChanged));
    layoutComboChanged(); // update the tooltip
    Gtk::Label *lNextStart = Gtk::manage(new Gtk::Label(
        Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    setExpandAlignProperties(lNextStart, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    workflowGrid->attach_next_to(*flayoutlab, Gtk::POS_LEFT, 1, 1);
    workflowGrid->attach_next_to(*editorLayout, *flayoutlab, Gtk::POS_RIGHT, 1,
                                 1);
    workflowGrid->attach_next_to(*lNextStart, *editorLayout, Gtk::POS_RIGHT, 1,
                                 1);

    Gtk::Label *curveBBoxPosL =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_CURVEBBOXPOS") + ":"));
    setExpandAlignProperties(curveBBoxPosL, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    curveBBoxPosC = Gtk::manage(new Gtk::ComboBoxText());
    setExpandAlignProperties(curveBBoxPosC, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_BASELINE);
    curveBBoxPosC->append(M("PREFERENCES_CURVEBBOXPOS_ABOVE"));
    curveBBoxPosC->append(M("PREFERENCES_CURVEBBOXPOS_RIGHT"));
    curveBBoxPosC->append(M("PREFERENCES_CURVEBBOXPOS_BELOW"));
    curveBBoxPosC->append(M("PREFERENCES_CURVEBBOXPOS_LEFT"));
    curveBBoxPosC->set_active(1);
    Gtk::Label *curveBBoxPosRestartL = Gtk::manage(new Gtk::Label(
        Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    setExpandAlignProperties(curveBBoxPosRestartL, false, false,
                             Gtk::ALIGN_START, Gtk::ALIGN_BASELINE);
    workflowGrid->attach_next_to(*curveBBoxPosL, *flayoutlab, Gtk::POS_BOTTOM,
                                 1, 1);
    workflowGrid->attach_next_to(*curveBBoxPosC, *editorLayout, Gtk::POS_BOTTOM,
                                 1, 1);
    workflowGrid->attach_next_to(*curveBBoxPosRestartL, *lNextStart,
                                 Gtk::POS_BOTTOM, 1, 1);

    ckbHistogramPositionLeft = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_HISTOGRAMPOSITIONLEFT")));
    setExpandAlignProperties(ckbHistogramPositionLeft, false, false,
                             Gtk::ALIGN_START, Gtk::ALIGN_BASELINE);
    workflowGrid->attach_next_to(*ckbHistogramPositionLeft, *curveBBoxPosL,
                                 Gtk::POS_BOTTOM, 1, 1);

    ckbFileBrowserToolbarSingleRow = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_FILEBROWSERTOOLBARSINGLEROW")));
    setExpandAlignProperties(ckbFileBrowserToolbarSingleRow, false, false,
                             Gtk::ALIGN_START, Gtk::ALIGN_START);
    ckbShowFilmStripToolBar = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_SHOWFILMSTRIPTOOLBAR")));
    setExpandAlignProperties(ckbShowFilmStripToolBar, false, false,
                             Gtk::ALIGN_START, Gtk::ALIGN_START);
    workflowGrid->attach_next_to(*ckbFileBrowserToolbarSingleRow,
                                 *ckbHistogramPositionLeft, Gtk::POS_BOTTOM, 1,
                                 1);
    workflowGrid->attach_next_to(*ckbShowFilmStripToolBar, *curveBBoxPosC,
                                 Gtk::POS_BOTTOM, 2, 1);

    adjuster_force_linear = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_ADJUSTER_FORCE_LINEAR") + " (" +
                             M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    setExpandAlignProperties(adjuster_force_linear, false, false,
                             Gtk::ALIGN_START, Gtk::ALIGN_START);
    workflowGrid->attach_next_to(*adjuster_force_linear,
                                 *ckbShowFilmStripToolBar, Gtk::POS_BOTTOM, 1,
                                 1);

    Gtk::Label *hb4label =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_TP_LABEL")));
    setExpandAlignProperties(hb4label, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    ckbHideTPVScrollbar =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_TP_VSCROLLBAR")));
    setExpandAlignProperties(ckbHideTPVScrollbar, false, false,
                             Gtk::ALIGN_START, Gtk::ALIGN_BASELINE);
    workflowGrid->attach_next_to(*hb4label, *ckbFileBrowserToolbarSingleRow,
                                 Gtk::POS_BOTTOM, 1, 1);
    Gtk::HBox *hb = Gtk::manage(new Gtk::HBox());
    hb->pack_start(*ckbHideTPVScrollbar);
    // workflowGrid->attach_next_to (*ckbHideTPVScrollbar, *hb4label,
    // Gtk::POS_RIGHT, 1, 1);
    ckbTpDisable = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_TP_DISABLE") + " (" +
                             M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    // workflowGrid->attach_next_to(*ckbTpDisable, *ckbHideTPVScrollbar,
    // Gtk::POS_RIGHT, 1, 1);
    hb->pack_start(*ckbTpDisable);
    workflowGrid->attach_next_to(*hb, *hb4label, Gtk::POS_RIGHT, 1, 1);

    ckbAutoSaveTpOpen =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_AUTOSAVE_TP_OPEN")));
    workflowGrid->attach_next_to(*ckbAutoSaveTpOpen, *hb4label, Gtk::POS_BOTTOM,
                                 1, 1);
    btnSaveTpOpenNow =
        Gtk::manage(new Gtk::Button(M("PREFERENCES_SAVE_TP_OPEN_NOW")));
    setExpandAlignProperties(btnSaveTpOpenNow, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    workflowGrid->attach_next_to(*btnSaveTpOpenNow, *ckbAutoSaveTpOpen,
                                 Gtk::POS_RIGHT, 1, 1);

    auto save_tp_open_now = [&]() -> void {
        parent->writeToolExpandedStatus(moptions.tpOpen);
    };
    btnSaveTpOpenNow->signal_clicked().connect(save_tp_open_now);

    fworklflow->add(*workflowGrid);

    vbGeneral->attach_next_to(*fworklflow, Gtk::POS_TOP, 2, 1);

    // ---------------------------------------------

    Gtk::Frame *flang = Gtk::manage(new Gtk::Frame(M("PREFERENCES_LANG")));
    setExpandAlignProperties(flang, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_START);
    Gtk::Grid *langGrid = Gtk::manage(new Gtk::Grid());
    langGrid->set_column_spacing(4);
    langGrid->set_row_spacing(4);
    setExpandAlignProperties(langGrid, false, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_BASELINE);

    ckbLangAutoDetect =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_LANGAUTODETECT")));
    setExpandAlignProperties(ckbLangAutoDetect, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);

    Gtk::Label *langlab =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_SELECTLANG") + ":"));
    setExpandAlignProperties(langlab, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    languages = Gtk::manage(new Gtk::ComboBoxText());
    setExpandAlignProperties(languages, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);

    std::vector<Glib::ustring> langs;
    parseDir(options.ART_base_dir + "/languages", langs, "");

    for (size_t i = 0; i < langs.size(); i++) {
        if (/*"default" != langs[i] &&*/ "README" != langs[i] &&
            "LICENSE" != langs[i] && langs[i].size() > 0 &&
            langs[i][langs[i].size() - 1] != '~') {
            languages->append(langs[i]);
        }
    }

    Gtk::Label *langw = Gtk::manage(new Gtk::Label(
        Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    setExpandAlignProperties(langw, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    langGrid->attach_next_to(*ckbLangAutoDetect, Gtk::POS_LEFT, 3, 1);
    langGrid->attach_next_to(*langlab, *ckbLangAutoDetect, Gtk::POS_BOTTOM, 1,
                             1);
    langGrid->attach_next_to(*languages, *langlab, Gtk::POS_RIGHT, 1, 1);
    langGrid->attach_next_to(*langw, *languages, Gtk::POS_RIGHT, 1, 1);
    flang->add(*langGrid);

    setExpandAlignProperties(flang, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_FILL);
    Gtk::HBox *abox = Gtk::manage(new Gtk::HBox());
    abox->pack_start(*flang, Gtk::PACK_EXPAND_WIDGET);
    // vbGeneral->attach_next_to (*flang, *fworklflow, Gtk::POS_BOTTOM, 2, 1);

    // Appearance ---------------------------------------------

    Gtk::Frame *appearanceFrame =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_APPEARANCE")));

    Gtk::Grid *appearanceGrid = Gtk::manage(new Gtk::Grid());
    appearanceGrid->get_style_context()->add_class("grid-spacing");
    setExpandAlignProperties(appearanceGrid, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    // appearanceGrid->set_column_homogeneous(false);

    Gtk::Label *themeLbl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_APPEARANCE_THEME") + ":"));
    setExpandAlignProperties(themeLbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    Gtk::Label *themeRestartLbl = Gtk::manage(new Gtk::Label(
        Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    setExpandAlignProperties(themeRestartLbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    MyComboBoxText *mcb = Gtk::manage(new MyComboBoxText());
    mcb->setPreferredWidth(150, 250);
    themeCBT = mcb;

    // setExpandAlignProperties(themeCBT, true, false, Gtk::ALIGN_START,
    // Gtk::ALIGN_CENTER);
    themeCBT->set_active(0);
    parseThemeDir(Glib::build_filename(options.ART_base_dir, "themes"));
    for (size_t i = 0; i < themeFNames.size(); i++) {
        auto name = themeFNames[i].shortFName;
        if (themeFNames[i].deprecated) {
            name += " (" + M("GENERAL_DEPRECATED") + ")";
        }
        themeCBT->append(name);
    }

    Gtk::Label *mainFontLbl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_APPEARANCE_MAINFONT")));
    setExpandAlignProperties(mainFontLbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    mainFontFB = Gtk::manage(new /*Gtk::*/MyFontButton());
    // setExpandAlignProperties(mainFontFB, false, false, Gtk::ALIGN_START,
    // Gtk::ALIGN_CENTER);
    mainFontFB->set_use_size(true);
    if (options.fontFamily == "default") {
        mainFontFB->set_font_name(Glib::ustring::compose(
            "%1 %2", initialFontFamily, initialFontSize));
    } else {
        mainFontFB->set_font_name(Glib::ustring::compose(
            "%1 %2", options.fontFamily, options.fontSize));
    }

    Gtk::Label *colorPickerFontLbl = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_APPEARANCE_COLORPICKERFONT") + ":"));
    setExpandAlignProperties(colorPickerFontLbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    colorPickerFontFB = Gtk::manage(new /*Gtk::*/MyFontButton());
    // setExpandAlignProperties(colorPickerFontFB, false, false,
    // Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
    colorPickerFontFB->set_use_size(true);
    if (options.fontFamily == "default") {
        colorPickerFontFB->set_font_name(Glib::ustring::compose(
            "%1 %2", initialFontFamily, initialFontSize));
    } else {
        colorPickerFontFB->set_font_name(Glib::ustring::compose(
            "%1 %2", options.CPFontFamily, options.CPFontSize));
    }

    // Gtk::Label* cropMaskColorLbl = Gtk::manage(new
    // Gtk::Label(M("PREFERENCES_APPEARANCE_CROPMASKCOLOR") + ":"));
    // setExpandAlignProperties(cropMaskColorLbl, false, false,
    // Gtk::ALIGN_START, Gtk::ALIGN_CENTER);

    // cropMaskColorCB = Gtk::manage(new Gtk::ColorButton());
    // cropMaskColorCB->set_use_alpha(true);

    // Gtk::Label* navGuideColorLbl = Gtk::manage(new
    // Gtk::Label(M("PREFERENCES_APPEARANCE_NAVGUIDECOLOR") + ":"));
    // setExpandAlignProperties(navGuideColorLbl, false, false,
    // Gtk::ALIGN_START, Gtk::ALIGN_CENTER);

    // navGuideColorCB = Gtk::manage(new Gtk::ColorButton());
    // navGuideColorCB->set_use_alpha(true);

    theme_bg_lbl = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_APPEARANCE_THEME_BG_COLOR") + ":"));
    setExpandAlignProperties(theme_bg_lbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    theme_bg_color = Gtk::manage(new Gtk::ColorButton());
    theme_bg_color->set_use_alpha(false);

    theme_fg_lbl = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_APPEARANCE_THEME_FG_COLOR") + ":"));
    setExpandAlignProperties(theme_fg_lbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    theme_fg_color = Gtk::manage(new Gtk::ColorButton());
    theme_fg_color->set_use_alpha(false);

    theme_hl_lbl = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_APPEARANCE_THEME_HL_COLOR") + ":"));
    setExpandAlignProperties(theme_hl_lbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    theme_hl_color = Gtk::manage(new Gtk::ColorButton());
    theme_hl_color->set_use_alpha(false);

    // theme_color_grid->attach(*theme_bg_lbl, 0, 0, 1, 1);
    // theme_color_grid->attach(*theme_bg_color, 1, 0, 1, 1);
    // theme_color_grid->attach(*theme_fg_lbl, 0, 1, 1, 1);
    // theme_color_grid->attach(*theme_fg_color, 1, 1, 1, 1);
    // theme_color_grid->attach(*theme_hl_lbl, 0, 2, 1, 1);
    // theme_color_grid->attach(*theme_hl_color, 1, 2, 1, 1);

    pseudoHiDPI = Gtk::manage(new Gtk::CheckButton(
        M("PREFERENCES_APPEARANCE_PSEUDOHIDPI") + Glib::ustring(" (") +
        M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    setExpandAlignProperties(pseudoHiDPI, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);

    Gtk::VSeparator *vSep = Gtk::manage(new Gtk::VSeparator());

    {
        // Gtk::HBox *hb = Gtk::manage(new Gtk::HBox());
        Gtk::HBox *hb2 = Gtk::manage(new Gtk::HBox());
        hb2->pack_start(*themeCBT, Gtk::PACK_EXPAND_WIDGET, 0);
        hb2->pack_start(*themeRestartLbl, Gtk::PACK_SHRINK);
        setExpandAlignProperties(hb2, true, false, Gtk::ALIGN_START,
                                 Gtk::ALIGN_BASELINE);

        appearanceGrid->attach(*themeLbl, 0, 0, 1, 1);
        appearanceGrid->attach(*hb2, 1, 0, 1, 1);
        // appearanceGrid->attach(*themeCBT,           1, 0, 1, 1);
        // appearanceGrid->attach(*themeRestartLbl,    2, 0, 2, 1);
        appearanceGrid->attach(*vSep, 2, 0, 1, 3);
        appearanceGrid->attach(*mainFontLbl, 0, 1, 1, 1);
        appearanceGrid->attach(*mainFontFB, 1, 1, 1, 1);
        appearanceGrid->attach(*colorPickerFontLbl, 0, 2, 1, 1);
        appearanceGrid->attach(*colorPickerFontFB, 1, 2, 1, 1);
#ifndef __APPLE__
        appearanceGrid->attach(*pseudoHiDPI, 0, 3, 2, 1);
#endif

        appearanceGrid->attach(*theme_bg_lbl, 3, 0, 1, 1);
        appearanceGrid->attach(*theme_bg_color, 4, 0, 1, 1);
        appearanceGrid->attach(*theme_fg_lbl, 3, 1, 1, 1);
        appearanceGrid->attach(*theme_fg_color, 4, 1, 1, 1);
        appearanceGrid->attach(*theme_hl_lbl, 3, 2, 1, 1);
        appearanceGrid->attach(*theme_hl_color, 4, 2, 1, 1);

        Gtk::Button *reset = Gtk::manage(new Gtk::Button());
        theme_colors_reset = reset;
        reset->set_tooltip_markup(M("ADJUSTER_RESET_TO_DEFAULT"));
        reset->add(*Gtk::manage(new RTImage("undo-small.svg")));
        reset->signal_clicked().connect(sigc::slot<void>([&]() -> void {
            Options opts;
            Gdk::RGBA c;
            c.set_rgba(opts.theme_bg_color[0] / 255.0,
                       opts.theme_bg_color[1] / 255.0,
                       opts.theme_bg_color[2] / 255.0);
            theme_bg_color->set_rgba(c);

            c.set_rgba(opts.theme_fg_color[0] / 255.0,
                       opts.theme_fg_color[1] / 255.0,
                       opts.theme_fg_color[2] / 255.0);
            theme_fg_color->set_rgba(c);

            c.set_rgba(opts.theme_hl_color[0] / 255.0,
                       opts.theme_hl_color[1] / 255.0,
                       opts.theme_hl_color[2] / 255.0);
            theme_hl_color->set_rgba(c);

            themeChanged();
        }));
        setExpandAlignProperties(reset, false, false, Gtk::ALIGN_CENTER,
                                 Gtk::ALIGN_START);
        reset->set_relief(Gtk::RELIEF_NONE);
        reset->get_style_context()->add_class(GTK_STYLE_CLASS_FLAT);
        reset->set_can_focus(false);
        reset->set_size_request(-1, 20);
        appearanceGrid->attach(*reset, 5, 0, 1, 1);

        // hb->pack_start(*appearanceGrid, Gtk::PACK_SHRINK);//EXPAND_WIDGET);
        // hb->pack_start(*theme_color_grid, Gtk::PACK_EXPAND_WIDGET);
        appearanceFrame->add(*appearanceGrid);
    }

    // appearanceFrame->add(*appearanceGrid);
    // vbGeneral->attach_next_to(*appearanceFrame, *flang, Gtk::POS_BOTTOM, 2,
    // 1);
    abox->set_spacing(4);
    abox->pack_start(*appearanceFrame, Gtk::PACK_EXPAND_WIDGET);
    vbGeneral->attach_next_to(*abox, *fworklflow, Gtk::POS_BOTTOM, 2, 1);

    // ---------------------------------------------

    Gtk::Frame *fclip =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_CLIPPINGIND")));
    setExpandAlignProperties(fclip, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_FILL);
    Gtk::Grid *clipGrid = Gtk::manage(new Gtk::Grid());
    clipGrid->set_column_spacing(4);
    clipGrid->set_row_spacing(4);
    setExpandAlignProperties(clipGrid, false, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_FILL);

    Gtk::Label *hll =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_HLTHRESHOLD") + ": "));
    setExpandAlignProperties(hll, true, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    hlThresh = Gtk::manage(new Gtk::SpinButton());
    setExpandAlignProperties(hlThresh, false, false, Gtk::ALIGN_END,
                             Gtk::ALIGN_BASELINE);
    hlThresh->set_digits(0);
    hlThresh->set_increments(1, 10);
    hlThresh->set_range(0, 255);
    clipGrid->attach_next_to(*hll, Gtk::POS_LEFT, 1, 1);
    clipGrid->attach_next_to(*hlThresh, *hll, Gtk::POS_RIGHT, 1, 1);

    Gtk::Label *shl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_SHTHRESHOLD") + ": "));
    setExpandAlignProperties(shl, true, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    shThresh = Gtk::manage(new Gtk::SpinButton());
    setExpandAlignProperties(shThresh, false, false, Gtk::ALIGN_END,
                             Gtk::ALIGN_BASELINE);
    shThresh->show();
    shThresh->set_digits(0);
    shThresh->set_increments(1, 10);
    shThresh->set_range(0, 255);
    clipGrid->attach_next_to(*shl, *hll, Gtk::POS_BOTTOM, 1, 1);
    clipGrid->attach_next_to(*shThresh, *shl, Gtk::POS_RIGHT, 1, 1);

    fclip->add(*clipGrid);
    // vbGeneral->attach_next_to (*fclip, *appearanceFrame, Gtk::POS_BOTTOM, 1,
    // 1);
    vbGeneral->attach_next_to(*fclip, *abox, Gtk::POS_BOTTOM, 1, 1);

    // ---------------------------------------------

    Gtk::Frame *fnav =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_NAVIGATIONFRAME")));
    setExpandAlignProperties(fclip, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_FILL);
    Gtk::Grid *navigationGrid = Gtk::manage(new Gtk::Grid());
    navigationGrid->set_column_spacing(4);
    navigationGrid->set_row_spacing(4);
    setExpandAlignProperties(fclip, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_FILL);

    Gtk::Label *panFactorLabel = Gtk::manage(new Gtk::Label(
        M("PREFERENCES_PANFACTORLABEL") + ":", Gtk::ALIGN_START));
    setExpandAlignProperties(panFactorLabel, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    panFactor = Gtk::manage(new Gtk::SpinButton());
    setExpandAlignProperties(panFactor, true, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_BASELINE);
    panFactor->set_digits(0);
    panFactor->set_increments(1, 5);
    panFactor->set_range(1, 10);
    navigationGrid->attach_next_to(*panFactorLabel, Gtk::POS_LEFT, 1, 1);
    navigationGrid->attach_next_to(*panFactor, *panFactorLabel, Gtk::POS_RIGHT,
                                   1, 1);

    rememberZoomPanCheckbutton =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_REMEMBERZOOMPAN")));
    setExpandAlignProperties(rememberZoomPanCheckbutton, false, false,
                             Gtk::ALIGN_START, Gtk::ALIGN_BASELINE);
    rememberZoomPanCheckbutton->set_tooltip_text(
        M("PREFERENCES_REMEMBERZOOMPAN_TOOLTIP"));

    navigationGrid->attach_next_to(*rememberZoomPanCheckbutton, *panFactorLabel,
                                   Gtk::POS_BOTTOM, 2, 1);

    fnav->add(*navigationGrid);
    {
        Gtk::HBox *hb = Gtk::manage(new Gtk::HBox());
        hb->set_spacing(4);
        hb->pack_start(*fnav, Gtk::PACK_EXPAND_WIDGET);
        vbGeneral->attach_next_to(*hb /*fnav*/, *fclip, Gtk::POS_RIGHT, 1, 1);

        Gtk::Frame *finspector =
            Gtk::manage(new Gtk::Frame(M("PREFERENCES_INSPECT_LABEL")));
        Gtk::VBox *vb = Gtk::manage(new Gtk::VBox());
        thumbnailInspectorHover = Gtk::manage(
            new Gtk::CheckButton(M("PREFERENCES_THUMBNAIL_INSPECTOR_HOVER")));
        vb->pack_start(*thumbnailInspectorHover);
        setExpandAlignProperties(thumbnailInspectorHover, false, false,
                                 Gtk::ALIGN_START, Gtk::ALIGN_START);
        finspector->add(*vb);
        hb->pack_start(*finspector, Gtk::PACK_SHRINK);
    }

    // ---------------------------------------------

    Gtk::Frame *fdg =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTERNALEDITOR")));
    setExpandAlignProperties(fdg, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_FILL);
    Gtk::Grid *externaleditorGrid = Gtk::manage(new Gtk::Grid());
    externaleditorGrid->set_column_spacing(4);
    externaleditorGrid->set_row_spacing(4);
    setExpandAlignProperties(externaleditorGrid, false, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_FILL);

    edOther =
        Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EDITORCMDLINE") + ":"));
    setExpandAlignProperties(edOther, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    editorToSendTo = Gtk::manage(new Gtk::Entry());
    setExpandAlignProperties(editorToSendTo, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_BASELINE);
    Gtk::RadioButton::Group ge = edOther->get_group();

#ifdef __APPLE__
    edGimp = Gtk::manage(new Gtk::RadioButton("GIMP"));
    setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    edGimp->set_group(ge);
    externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 2, 1);

    edPS = Gtk::manage(new Gtk::RadioButton("Adobe Photoshop"));
    setExpandAlignProperties(edPS, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    // psDir = Gtk::manage ( new MyFileChooserButton (M ("PREFERENCES_PSPATH"),
    // Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) ); setExpandAlignProperties
    // (psDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
    externaleditorGrid->attach_next_to(*edPS, *edGimp, Gtk::POS_BOTTOM, 1, 1);
    // externaleditorGrid->attach_next_to (*psDir, *edPS, Gtk::POS_RIGHT, 1, 1);
    edPS->set_group(ge);

    externaleditorGrid->attach_next_to(*edOther, *edPS, Gtk::POS_BOTTOM, 1, 1);
    externaleditorGrid->attach_next_to(*editorToSendTo, *edOther,
                                       Gtk::POS_RIGHT, 1, 1);
#elif defined WIN32
    edGimp = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_GIMPPATH") + ":"));
    setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    gimpDir = Gtk::manage(new MyFileChooserButton(
        M("PREFERENCES_GIMPPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
    setExpandAlignProperties(gimpDir, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 1, 1);
    externaleditorGrid->attach_next_to(*gimpDir, *edGimp, Gtk::POS_RIGHT, 1, 1);
    edGimp->set_group(ge);

    edPS = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_PSPATH") + ":"));
    setExpandAlignProperties(edPS, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    psDir = Gtk::manage(new MyFileChooserButton(
        M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
    setExpandAlignProperties(psDir, true, false, Gtk::ALIGN_FILL,
                             Gtk::ALIGN_CENTER);
    externaleditorGrid->attach_next_to(*edPS, *edGimp, Gtk::POS_BOTTOM, 1, 1);
    externaleditorGrid->attach_next_to(*psDir, *edPS, Gtk::POS_RIGHT, 1, 1);
    edPS->set_group(ge);

    externaleditorGrid->attach_next_to(*edOther, *edPS, Gtk::POS_BOTTOM, 1, 1);
    externaleditorGrid->attach_next_to(*editorToSendTo, *edOther,
                                       Gtk::POS_RIGHT, 1, 1);
#else  // !APPLE && !WIN32
    edGimp = Gtk::manage(new Gtk::RadioButton("GIMP"));
    setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 2, 1);
    edGimp->set_group(ge);

    externaleditorGrid->attach_next_to(*edOther, *edGimp, Gtk::POS_BOTTOM, 1,
                                       1);
    externaleditorGrid->attach_next_to(*editorToSendTo, *edOther,
                                       Gtk::POS_RIGHT, 1, 1);
#endif // external editors

    editor_dir_temp =
        Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_TEMP")));
    editor_dir_current = Gtk::manage(
        new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CURRENT")));
    editor_dir_custom = Gtk::manage(
        new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CUSTOM") + ": "));
    editor_dir_custom_path = Gtk::manage(
        new MyFileChooserButton("", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
    ge = editor_dir_temp->get_group();
    editor_dir_current->set_group(ge);
    editor_dir_custom->set_group(ge);

    editor_float32 =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_EXTEDITOR_FLOAT32")));
    editor_bypass_output_profile = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_EXTEDITOR_BYPASS_OUTPUT_PROFILE")));
    {
        Gtk::Frame *f =
            Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTEDITOR_DIR")));
        setExpandAlignProperties(f, true, false, Gtk::ALIGN_FILL,
                                 Gtk::ALIGN_FILL);
        Gtk::VBox *vb = Gtk::manage(new Gtk::VBox());
        vb->pack_start(*editor_dir_temp);
        vb->pack_start(*editor_dir_current);
        Gtk::HBox *hb = Gtk::manage(new Gtk::HBox());
        hb->pack_start(*editor_dir_custom, Gtk::PACK_SHRINK);
        hb->pack_start(*editor_dir_custom_path, Gtk::PACK_EXPAND_WIDGET, 2);
        vb->pack_start(*hb);
        f->add(*vb);

        hb = Gtk::manage(new Gtk::HBox());
        hb->pack_start(*externaleditorGrid);
        hb->pack_start(*f, Gtk::PACK_EXPAND_WIDGET, 4);

        vb = Gtk::manage(new Gtk::VBox());
        vb->pack_start(*hb);
        hb = Gtk::manage(new Gtk::HBox());
        hb->pack_start(*editor_float32, Gtk::PACK_SHRINK);
        hb->pack_start(*editor_bypass_output_profile, Gtk::PACK_SHRINK, 4);
        vb->pack_start(*hb, Gtk::PACK_SHRINK, 4);

        vb->show_all_children();
        vb->show();

        fdg->add(*vb);
    }
    vbGeneral->attach_next_to(*fdg, *fclip, Gtk::POS_BOTTOM, 2, 1);

    langAutoDetectConn = ckbLangAutoDetect->signal_toggled().connect(
        sigc::mem_fun(*this, &Preferences::langAutoDetectToggled));
    tconn = themeCBT->signal_changed().connect(
        sigc::mem_fun(*this, &Preferences::themeChanged));
    fconn = mainFontFB->signal_font_set().connect(
        sigc::mem_fun(*this, &Preferences::fontChanged));
    cpfconn = colorPickerFontFB->signal_font_set().connect(
        sigc::mem_fun(*this, &Preferences::cpFontChanged));

    theme_bg_color->signal_color_set().connect(
        sigc::mem_fun(*this, &Preferences::themeChanged));
    theme_fg_color->signal_color_set().connect(
        sigc::mem_fun(*this, &Preferences::themeChanged));
    theme_hl_color->signal_color_set().connect(
        sigc::mem_fun(*this, &Preferences::themeChanged));

    swGeneral->add(*vbGeneral);
    return swGeneral;
}

Gtk::Widget *Preferences::getFileBrowserPanel()
{
    swFileBrowser = Gtk::manage(new Gtk::ScrolledWindow());
    swFileBrowser->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

    Gtk::VBox *vbFileBrowser = Gtk::manage(new Gtk::VBox());

    Gtk::Frame *fsd =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_STARTUPIMDIR")));

    sdcurrent = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIRSOFTWARE")));
    sdlast = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIRLAST")));
    sdhome = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIRHOME")));
    sdother =
        Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIROTHER") + ": "));
    startupdir = Gtk::manage(new Gtk::Entry());

    Gtk::Button *sdselect = Gtk::manage(new Gtk::Button());
    sdselect->set_image(*Gtk::manage(new RTImage("folder-open-small.svg")));

    Gtk::RadioButton::Group opts = sdcurrent->get_group();
    sdlast->set_group(opts);
    sdhome->set_group(opts);
    sdother->set_group(opts);

    Gtk::VBox *vbsd = Gtk::manage(new Gtk::VBox());
    vbsd->pack_start(*sdcurrent, Gtk::PACK_SHRINK, 0);
    vbsd->pack_start(*sdlast, Gtk::PACK_SHRINK, 0);
    vbsd->pack_start(*sdhome, Gtk::PACK_SHRINK, 0);
    Gtk::HBox *otherbox = Gtk::manage(new Gtk::HBox());
    otherbox->pack_start(*sdother, Gtk::PACK_SHRINK);
    otherbox->pack_start(*startupdir);
    otherbox->pack_end(*sdselect, Gtk::PACK_SHRINK, 4);
    vbsd->pack_start(*otherbox, Gtk::PACK_SHRINK, 0);

    fsd->add(*vbsd);
    vbFileBrowser->pack_start(*fsd, Gtk::PACK_SHRINK, 4);

    sdselect->signal_clicked().connect(
        sigc::mem_fun(*this, &Preferences::selectStartupDir));

    //---

    Gtk::Frame *fro =
        Gtk::manage(new Gtk::Frame(M("PREFERENCES_FBROWSEROPTS")));
    showDateTime =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_SHOWDATETIME")));
    showBasicExif =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_SHOWBASICEXIF")));
    showExpComp = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_SHOWEXPOSURECOMPENSATION")));
    Gtk::VBox *vbro = Gtk::manage(new Gtk::VBox());
    Gtk::HBox *hbro1 = Gtk::manage(new Gtk::HBox());
    Gtk::HBox *hbro0 = Gtk::manage(new Gtk::HBox());
    overlayedFileNames =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_OVERLAY_FILENAMES")));
    filmStripOverlayedFileNames = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_OVERLAY_FILENAMES_FILMSTRIP")));
    highlight_selected_thumbnails = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_HIGHLIGHT_SELECTED_THUMBNAILS")));
    sameThumbSize = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT")));
    sameThumbSize->set_tooltip_text(
        M("PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT_HINT"));
    ckbInternalThumbIfUntouched = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_INTERNALTHUMBIFUNTOUCHED")));

    // vbro->pack_start (*showDateTime, Gtk::PACK_SHRINK, 0);
    Gtk::Label *dflab = Gtk::manage(
        new Gtk::Label(M("PREFERENCES_DATEFORMAT") + ":", Gtk::ALIGN_START));
    dateformat = Gtk::manage(new Gtk::Entry());
    dateformat->set_tooltip_markup(M("PREFERENCES_DATEFORMATHINT"));
    dflab->set_tooltip_markup(M("PREFERENCES_DATEFORMATHINT"));
    hbro0->pack_start(*showDateTime, Gtk::PACK_SHRINK, 4);
    hbro0->pack_start(*dflab, Gtk::PACK_SHRINK, 4);
    hbro0->pack_start(*dateformat, Gtk::PACK_SHRINK, 0);

    vbro->pack_start(*hbro0, Gtk::PACK_SHRINK, 0);
    hbro1->pack_start(*showBasicExif, Gtk::PACK_SHRINK, 0);
    hbro1->pack_start(*showExpComp, Gtk::PACK_SHRINK, 4);
    vbro->pack_start(*hbro1, Gtk::PACK_SHRINK, 0);
    vbro->pack_start(*overlayedFileNames, Gtk::PACK_SHRINK, 0);
    vbro->pack_start(*filmStripOverlayedFileNames, Gtk::PACK_SHRINK, 0);
    vbro->pack_start(*sameThumbSize, Gtk::PACK_SHRINK, 0);
    vbro->pack_start(*highlight_selected_thumbnails, Gtk::PACK_SHRINK, 0);
    vbro->pack_start(*ckbInternalThumbIfUntouched, Gtk::PACK_SHRINK, 0);

    thumbRatingMode =
        Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_THUMBNAIL_RATING")));
    remember_metadata_filters = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_REMEMBER_METADATA_FILTERS")));
    remember_rename_options = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_REMEMBER_RENAME_OPTIONS")));
    dir_browser_single_click = Gtk::manage(
        new Gtk::CheckButton(M("PREFERENCES_DIRBROWSER_SINGLECLICK") + " (" +
                             M("PREFERENCES_APPLNEXTSTARTUP") + ")"));
    vbro->pack_start(*thumbRatingMode, Gtk::PACK_SHRINK, 0);
    vbro->pack_start(*remember_metadata_filters, Gtk::PACK_SHRINK, 0);
    vbro->pack_start(*remember_rename_options, Gtk::PACK_SHRINK, 0);
    vbro->pack_start(*dir_browser_single_click, Gtk::PACK_SHRINK, 0);

    Gtk::HBox *hbrecent = Gtk::manage(new Gtk::HBox());
    Gtk::Label *labrecent =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_MAXRECENTFOLDERS") + ":"));
    maxRecentFolders = Gtk::manage(new Gtk::SpinButton());
    hbrecent->pack_start(*labrecent, Gtk::PACK_SHRINK, 4);
    hbrecent->pack_start(*maxRecentFolders, Gtk::PACK_SHRINK, 4);
    maxRecentFolders->set_digits(0);
    maxRecentFolders->set_increments(1, 5);
    maxRecentFolders->set_range(1, 25);
    vbro->pack_start(*hbrecent, Gtk::PACK_SHRINK, 4);

    fro->add(*vbro);

    // Gtk::Frame* frmnu = Gtk::manage ( new Gtk::Frame (M
    // ("PREFERENCES_MENUOPTIONS")) );

    // Gtk::Grid* menuGrid = Gtk::manage(new Gtk::Grid());
    // menuGrid->get_style_context()->add_class("grid-spacing");
    // setExpandAlignProperties(menuGrid, false, false, Gtk::ALIGN_START,
    // Gtk::ALIGN_CENTER);

    // ckbmenuGroupRank = Gtk::manage ( new Gtk::CheckButton (M
    // ("PREFERENCES_MENUGROUPRANK")) );
    // setExpandAlignProperties(ckbmenuGroupRank, false, false,
    // Gtk::ALIGN_START, Gtk::ALIGN_CENTER); ckbmenuGroupLabel = Gtk::manage (
    // new Gtk::CheckButton (M ("PREFERENCES_MENUGROUPLABEL")) );
    // ckbmenuGroupFileOperations = Gtk::manage ( new Gtk::CheckButton (M
    // ("PREFERENCES_MENUGROUPFILEOPERATIONS")) );
    // setExpandAlignProperties(ckbmenuGroupFileOperations, false, false,
    // Gtk::ALIGN_START, Gtk::ALIGN_CENTER); ckbmenuGroupProfileOperations =
    // Gtk::manage ( new Gtk::CheckButton (M
    // ("PREFERENCES_MENUGROUPPROFILEOPERATIONS")) ); ckbmenuGroupExtProg =
    // Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_MENUGROUPEXTPROGS"))
    // );

    // menuGrid->attach (*ckbmenuGroupRank, 0, 0, 1, 1);
    // menuGrid->attach (*ckbmenuGroupLabel, 1, 0, 1, 1);
    // menuGrid->attach (*ckbmenuGroupFileOperations, 0, 1, 1, 1);
    // menuGrid->attach (*ckbmenuGroupProfileOperations, 1, 1, 1, 1);
    // menuGrid->attach (*ckbmenuGroupExtProg, 0, 2, 2, 1);

    // frmnu->add (*menuGrid);

    Gtk::Frame *fre = Gtk::manage(new Gtk::Frame(M("PREFERENCES_PARSEDEXT")));
    Gtk::VBox *vbre = Gtk::manage(new Gtk::VBox());
    Gtk::HBox *hb0 = Gtk::manage(new Gtk::HBox());
    Gtk::Label *elab =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_PARSEDEXTADD") + ":"));
    hb0->pack_start(*elab, Gtk::PACK_SHRINK, 4);
    extension = Gtk::manage(new Gtk::Entry());
    extension->set_width_chars(5);
    extension->set_max_width_chars(5);
    hb0->pack_start(*extension);
    addExt = Gtk::manage(new Gtk::Button());
    delExt = Gtk::manage(new Gtk::Button());
    moveExtUp = Gtk::manage(new Gtk::Button());
    moveExtDown = Gtk::manage(new Gtk::Button());
    addExt->set_tooltip_text(M("PREFERENCES_PARSEDEXTADDHINT"));
    delExt->set_tooltip_text(M("PREFERENCES_PARSEDEXTDELHINT"));
    moveExtUp->set_tooltip_text(M("PREFERENCES_PARSEDEXTUPHINT"));
    moveExtDown->set_tooltip_text(M("PREFERENCES_PARSEDEXTDOWNHINT"));
    Gtk::Image *addExtImg = Gtk::manage(new RTImage("add-small.svg"));
    Gtk::Image *delExtImg = Gtk::manage(new RTImage("remove-small.svg"));
    Gtk::Image *moveExtUpImg = Gtk::manage(new RTImage("arrow-up-small.svg"));
    Gtk::Image *moveExtDownImg =
        Gtk::manage(new RTImage("arrow-down-small.svg"));
    addExt->add(*addExtImg);
    delExt->add(*delExtImg);
    moveExtUp->set_image(*moveExtUpImg);
    moveExtDown->set_image(*moveExtDownImg);
    hb0->pack_end(*moveExtDown, Gtk::PACK_SHRINK, 4);
    hb0->pack_end(*moveExtUp, Gtk::PACK_SHRINK, 4);
    hb0->pack_end(*delExt, Gtk::PACK_SHRINK, 4);
    hb0->pack_end(*addExt, Gtk::PACK_SHRINK, 4);
    extensions = Gtk::manage(new Gtk::TreeView());
    Gtk::ScrolledWindow *hscrollw = Gtk::manage(new Gtk::ScrolledWindow());
    hscrollw->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
    hscrollw->add(*extensions);
    extensionModel = Gtk::ListStore::create(extensionColumns);
    extensions->set_model(extensionModel);
    extensions->append_column_editable("Enabled", extensionColumns.enabled);
    extensions->append_column("Extension", extensionColumns.ext);
    extensions->set_headers_visible(false);
    setTreeViewCssProvider(extensions);
    vbre->pack_start(*hscrollw);
    vbre->pack_start(*hb0, Gtk::PACK_SHRINK, 4);

    fre->add(*vbre);

    // Cache

    Gtk::Frame *frc = Gtk::manage(new Gtk::Frame(M("PREFERENCES_CACHEOPTS")));
    Gtk::VBox *vbc = Gtk::manage(new Gtk::VBox());
    frc->add(*vbc);

    Gtk::Grid *cacheGrid = Gtk::manage(new Gtk::Grid());
    cacheGrid->get_style_context()->add_class("grid-spacing");
    setExpandAlignProperties(cacheGrid, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);

    Gtk::Label *maxThumbHeightLbl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_CACHETHUMBHEIGHT") + ":"));
    setExpandAlignProperties(maxThumbHeightLbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    maxThumbHeightSB = Gtk::manage(new Gtk::SpinButton());
    maxThumbHeightSB->set_digits(0);
    maxThumbHeightSB->set_increments(1, 10);
    maxThumbHeightSB->set_range(40, 800);

    Gtk::Label *maxCacheEntriesLbl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_CACHEMAXENTRIES") + ":"));
    setExpandAlignProperties(maxCacheEntriesLbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    maxCacheEntriesSB = Gtk::manage(new Gtk::SpinButton());
    maxCacheEntriesSB->set_digits(0);
    maxCacheEntriesSB->set_increments(1, 10);
    maxCacheEntriesSB->set_range(10, 100000);

    // Separation is needed so that a button is not accidentally clicked when
    // one wanted to click a spinbox. Ideally, the separation wouldn't require
    // attaching a widget, but how?
    Gtk::HSeparator *cacheSeparator = Gtk::manage(new Gtk::HSeparator());
    cacheSeparator->get_style_context()->add_class("grid-row-separator");

    Gtk::Label *clearThumbsLbl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_CACHECLEAR_ALLBUTPROFILES")));
    setExpandAlignProperties(clearThumbsLbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    Gtk::Button *clearThumbsBtn =
        Gtk::manage(new Gtk::Button(M("PREFERENCES_CACHECLEAR")));

    Gtk::Label *clearProfilesLbl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_CACHECLEAR_ONLYPROFILES")));
    setExpandAlignProperties(clearProfilesLbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    Gtk::Button *clearProfilesBtn =
        Gtk::manage(new Gtk::Button(M("PREFERENCES_CACHECLEAR")));

    Gtk::Label *clearAllLbl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_CACHECLEAR_ALL")));
    setExpandAlignProperties(clearAllLbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_CENTER);
    Gtk::Button *clearAllBtn =
        Gtk::manage(new Gtk::Button(M("PREFERENCES_CACHECLEAR")));

    cacheGrid->attach(*maxThumbHeightLbl, 0, 0, 1, 1);
    cacheGrid->attach(*maxThumbHeightSB, 1, 0, 1, 1);
    cacheGrid->attach(*maxCacheEntriesLbl, 0, 1, 1, 1);
    cacheGrid->attach(*maxCacheEntriesSB, 1, 1, 1, 1);
    cacheGrid->attach(*cacheSeparator, 0, 2, 2, 1);
    cacheGrid->attach(*clearThumbsLbl, 0, 3, 1, 1);
    cacheGrid->attach(*clearThumbsBtn, 1, 3, 1, 1);
    if (moptions.saveParamsCache) {
        cacheGrid->attach(*clearProfilesLbl, 0, 4, 1, 1);
        cacheGrid->attach(*clearProfilesBtn, 1, 4, 1, 1);
        cacheGrid->attach(*clearAllLbl, 0, 5, 1, 1);
        cacheGrid->attach(*clearAllBtn, 1, 5, 1, 1);
    }

    vbc->pack_start(*cacheGrid, Gtk::PACK_SHRINK, 4);

    Gtk::Label *clearSafetyLbl =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_CACHECLEAR_SAFETY")));
    setExpandAlignProperties(clearSafetyLbl, false, false, Gtk::ALIGN_START,
                             Gtk::ALIGN_START);
    clearSafetyLbl->set_line_wrap(true);
    vbc->pack_start(*clearSafetyLbl, Gtk::PACK_SHRINK, 4);

    Gtk::HBox *hb6 = Gtk::manage(new Gtk::HBox());
    Gtk::VBox *vb6 = Gtk::manage(new Gtk::VBox());

    vb6->pack_start(*fro);
    // vb6->pack_start (*frmnu);
    vb6->pack_end(*frc);
    hb6->pack_start(*vb6);
    hb6->pack_start(*fre);
    hb6->set_spacing(4);

    vbFileBrowser->pack_start(*hb6, Gtk::PACK_EXPAND_WIDGET, 4);

    addExt->signal_clicked().connect(
        sigc::mem_fun(*this, &Preferences::addExtPressed));
    delExt->signal_clicked().connect(
        sigc::mem_fun(*this, &Preferences::delExtPressed));
    moveExtUp->signal_clicked().connect(
        sigc::mem_fun(*this, &Preferences::moveExtUpPressed));
    moveExtDown->signal_clicked().connect(
        sigc::mem_fun(*this, &Preferences::moveExtDownPressed));
    extension->signal_activate().connect(
        sigc::mem_fun(*this, &Preferences::addExtPressed));
    clearThumbsBtn->signal_clicked().connect(
        sigc::mem_fun(*this, &Preferences::clearThumbImagesPressed));
    if (moptions.saveParamsCache) {
        clearProfilesBtn->signal_clicked().connect(
            sigc::mem_fun(*this, &Preferences::clearProfilesPressed));
        clearAllBtn->signal_clicked().connect(
            sigc::mem_fun(*this, &Preferences::clearAllPressed));
    }

    swFileBrowser->add(*vbFileBrowser);
    return swFileBrowser;
}

Gtk::Widget *Preferences::getSoundsPanel()
{
    swSounds = Gtk::manage(new Gtk::ScrolledWindow());
    swSounds->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

    Gtk::VBox *vbSounds = Gtk::manage(new Gtk::VBox());

    ckbSndEnable = Gtk::manage(new Gtk::CheckButton(M("GENERAL_ENABLE")));
    sndEnableConn = ckbSndEnable->signal_toggled().connect(
        sigc::mem_fun(*this, &Preferences::sndEnableToggled));

    vbSounds->pack_start(*ckbSndEnable, Gtk::PACK_SHRINK, 4);

    Gtk::HBox *hblSndHelp = Gtk::manage(new Gtk::HBox());
    Gtk::Label *lSndHelp =
        Gtk::manage(new Gtk::Label(M("PREFERENCES_SND_HELP")));
    hblSndHelp->pack_start(*lSndHelp, Gtk::PACK_SHRINK, 4);
    vbSounds->pack_start(*hblSndHelp, Gtk::PACK_SHRINK, 4);

    // BatchQueueDone
    Gtk::HBox *pBatchQueueDone = Gtk::manage(new Gtk::HBox());

    Gtk::Label *lSndBatchQueueDone = Gtk::manage(new Gtk::Label(
        M("PREFERENCES_SND_BATCHQUEUEDONE") + Glib::ustring(":")));
    pBatchQueueDone->pack_start(*lSndBatchQueueDone, Gtk::PACK_SHRINK, 4);

    txtSndBatchQueueDone = Gtk::manage(new Gtk::Entry());
    pBatchQueueDone->pack_end(*txtSndBatchQueueDone, Gtk::PACK_EXPAND_WIDGET,
                              4);

    vbSounds->pack_start(*pBatchQueueDone, Gtk::PACK_SHRINK, 4);

    // LngEditProcDone
    Gtk::HBox *pSndLngEditProcDone = Gtk::manage(new Gtk::HBox());

    Gtk::Label *lSndLngEditProcDone = Gtk::manage(new Gtk::Label(
        M("PREFERENCES_SND_LNGEDITPROCDONE") + Glib::ustring(":")));
    pSndLngEditProcDone->pack_start(*lSndLngEditProcDone, Gtk::PACK_SHRINK, 4);

    txtSndLngEditProcDone = Gtk::manage(new Gtk::Entry());
    pSndLngEditProcDone->pack_start(*txtSndLngEditProcDone,
                                    Gtk::PACK_EXPAND_WIDGET, 4);

    Gtk::Label *lSndLngEditProcDoneSecs = Gtk::manage(new Gtk::Label(
        M("PREFERENCES_SND_THRESHOLDSECS") + Glib::ustring(":")));
    pSndLngEditProcDone->pack_start(*lSndLngEditProcDoneSecs, Gtk::PACK_SHRINK,
                                    12);

    spbSndLngEditProcDoneSecs = Gtk::manage(new Gtk::SpinButton());
    spbSndLngEditProcDoneSecs->set_digits(1);
    spbSndLngEditProcDoneSecs->set_increments(0.5, 1);
    spbSndLngEditProcDoneSecs->set_range(0, 10);
    pSndLngEditProcDone->pack_end(*spbSndLngEditProcDoneSecs, Gtk::PACK_SHRINK,
                                  4);

    vbSounds->pack_start(*pSndLngEditProcDone, Gtk::PACK_SHRINK, 4);

    sndEnableToggled();

    auto f = Gtk::manage(new Gtk::Frame(""));
    f->add(*vbSounds);
    // swSounds->add(*vbSounds);
    swSounds->add(*f);

    return swSounds;
}

void Preferences::parseDir(Glib::ustring dirname,
                           std::vector<Glib::ustring> &items, Glib::ustring ext)
{

    if (dirname.empty()) {
        return;
    }

    // process directory
    Glib::Dir *dir = nullptr;

    try {
        dir = new Glib::Dir(dirname);
    } catch (const Glib::Error &e) {
        return;
    }

    for (Glib::DirIterator i = dir->begin(); i != dir->end(); ++i) {
        Glib::ustring fname = Glib::build_filename(dirname, *i);
        Glib::ustring sname = *i;

        // ignore directories
        if (!Glib::file_test(fname, Glib::FILE_TEST_IS_DIR) &&
            sname.size() >= ext.size() &&
            sname.substr(sname.size() - ext.size(), ext.size()).casefold() ==
                ext) {
            items.push_back(sname.substr(0, sname.size() - ext.size()));
        }
    }

    std::sort(items.begin(), items.end());
    delete dir;
}

void Preferences::parseThemeDir(Glib::ustring dirname)
{

    if (dirname.empty()) {
        return;
    }

    // process directory
    Glib::Dir *dir = nullptr;

    try {
        dir = new Glib::Dir(dirname);
    } catch (const Glib::Error &e) {
        return;
    }

    for (Glib::DirIterator i = dir->begin(); i != dir->end(); ++i) {
        Glib::ustring fname = Glib::build_filename(dirname, *i);
        Glib::ustring sname = *i;

        // ignore directories and filter out unsupported theme
        if (regex->match(sname, matchInfo) &&
            !Glib::file_test(fname, Glib::FILE_TEST_IS_DIR) &&
            sname.size() >= 4) {
            bool keepIt = false;
            Glib::ustring fname2 = matchInfo.fetch(1);
            Glib::ustring minMinor = matchInfo.fetch(2);
            Glib::ustring maxMinor = matchInfo.fetch(3);
            bool deprecated = !(matchInfo.fetch(4).empty());

            if (!minMinor.empty()) {
                guint64 minMinorVal = g_ascii_strtoll(minMinor.c_str(), 0, 0);

                if ((guint64)GTK_MINOR_VERSION >= minMinorVal) {
                    keepIt = true;
                }
            }

            if (!maxMinor.empty()) {
                guint64 maxMinorVal = g_ascii_strtoll(maxMinor.c_str(), 0, 0);

                if ((guint64)GTK_MINOR_VERSION <= maxMinorVal) {
                    keepIt = true;
                }
            }

            if (keepIt &&
                sname[0] == '_') { // filter out file names starting with _
                                   // (these are implementation files...)
                keepIt = false;
            }

            if (keepIt) {
                themeFNames.push_back(ThemeFilename(
                    matchInfo.fetch(1), sname.substr(0, sname.size() - 4),
                    deprecated));
            }
        }
    }

    std::sort(
        themeFNames.begin(), themeFNames.end(),
        [](const ThemeFilename &firstDir, const ThemeFilename &secondDir) {
            if (firstDir.deprecated != secondDir.deprecated) {
                return !firstDir.deprecated;
            }
            return firstDir.shortFName < secondDir.shortFName;
        });

    if (GTK_MINOR_VERSION >= 20) {
        themeFNames.insert(themeFNames.begin(),
                           ThemeFilename(M("PROFILEPANEL_PDEFAULT"),
                                         Options::DEFAULT_THEME, false));
    }

    delete dir;
}

void Preferences::storePreferences()
{

    // With the new mechanism, we can't be sure of the availability of the
    // Options::DEFPROFILE_RAW & Options::DEFPROFILE_IMG profiles, because
    // useBundledProfiles may be false. We're now using
    // Options::DEFPROFILE_INTERNAL instead, which is always available.

    moptions.defProfRaw = rprofiles->getFullPathFromActiveRow();

    if (moptions.defProfRaw.empty()) {
        moptions.defProfRaw = Options::DEFPROFILE_INTERNAL;
    }

    moptions.defProfImg = iprofiles->getFullPathFromActiveRow();

    if (moptions.defProfImg.empty()) {
        moptions.defProfImg = Options::DEFPROFILE_INTERNAL;
    }

    moptions.dateFormat = dateformat->get_text();
    moptions.panAccelFactor = (int)panFactor->get_value();
    moptions.rememberZoomAndPan = rememberZoomPanCheckbutton->get_active();

    moptions.thumbnail_inspector_hover = thumbnailInspectorHover->get_active();

    moptions.fbShowDateTime = showDateTime->get_active();
    moptions.fbShowBasicExif = showBasicExif->get_active();
    moptions.fbShowExpComp = showExpComp->get_active();
    // moptions.menuGroupRank = ckbmenuGroupRank->get_active();
    // moptions.menuGroupLabel = ckbmenuGroupLabel->get_active();
    // moptions.menuGroupFileOperations =
    // ckbmenuGroupFileOperations->get_active();
    // moptions.menuGroupProfileOperations =
    // ckbmenuGroupProfileOperations->get_active(); moptions.menuGroupExtProg =
    // ckbmenuGroupExtProg->get_active();
    moptions.highlightThreshold = (int)hlThresh->get_value();
    moptions.shadowThreshold = (int)shThresh->get_value();
    moptions.language = languages->get_active_text();
    moptions.languageAutoDetect = ckbLangAutoDetect->get_active();
    moptions.theme =
        themeFNames.at(themeCBT->get_active_row_number()).longFName;

    // Gdk::RGBA cropCol = cropMaskColorCB->get_rgba();
    // moptions.cutOverlayBrush[0] = cropCol.get_red();
    // moptions.cutOverlayBrush[1] = cropCol.get_green();
    // moptions.cutOverlayBrush[2] = cropCol.get_blue();
    // moptions.cutOverlayBrush[3] = cropMaskColorCB->get_alpha() / 65535.0;

    // Gdk::RGBA NavGuideCol = navGuideColorCB->get_rgba();
    // moptions.navGuideBrush[0] = NavGuideCol.get_red();
    // moptions.navGuideBrush[1] = NavGuideCol.get_green();
    // moptions.navGuideBrush[2] = NavGuideCol.get_blue();
    // moptions.navGuideBrush[3] = navGuideColorCB->get_alpha() / 65535.0;

    const auto getcol = [](double v) -> int {
        return rtengine::LIM(v * 255, 0., 255.);
    };

    Gdk::RGBA bg_col = theme_bg_color->get_rgba();
    moptions.theme_bg_color[0] = getcol(bg_col.get_red());
    moptions.theme_bg_color[1] = getcol(bg_col.get_green());
    moptions.theme_bg_color[2] = getcol(bg_col.get_blue());

    Gdk::RGBA fg_col = theme_fg_color->get_rgba();
    moptions.theme_fg_color[0] = getcol(fg_col.get_red());
    moptions.theme_fg_color[1] = getcol(fg_col.get_green());
    moptions.theme_fg_color[2] = getcol(fg_col.get_blue());

    Gdk::RGBA hl_col = theme_hl_color->get_rgba();
    moptions.theme_hl_color[0] = getcol(hl_col.get_red());
    moptions.theme_hl_color[1] = getcol(hl_col.get_green());
    moptions.theme_hl_color[2] = getcol(hl_col.get_blue());

    Pango::FontDescription fd(mainFontFB->get_font_name());

    if (newFont) {
        moptions.fontFamily = getFontFamily(fd);
        moptions.fontSize = fd.get_size() / Pango::SCALE;
    }

    Pango::FontDescription cpfd(colorPickerFontFB->get_font_name());

    if (newCPFont) {
        moptions.CPFontFamily = getFontFamily(cpfd);
        moptions.CPFontSize = cpfd.get_size() / Pango::SCALE;
    }

#ifndef __APPLE__
    moptions.pseudoHiDPISupport = pseudoHiDPI->get_active();
#endif

#ifdef WIN32
    moptions.gimpDir = gimpDir->get_filename();
    moptions.psDir = psDir->get_filename();
// #elif defined __APPLE__
//     moptions.psDir = psDir->get_filename ();
#endif
    moptions.customEditorProg = editorToSendTo->get_text();

    if (edGimp->get_active()) {
        moptions.editorToSendTo = 1;
    }

#ifdef WIN32
    else if (edPS->get_active()) {
        moptions.editorToSendTo = 2;
    }

#elif defined __APPLE__
    else if (edPS->get_active()) {
        moptions.editorToSendTo = 2;
    }

#endif
    else if (edOther->get_active()) {
        moptions.editorToSendTo = 3;
    }

    if (editor_dir_temp->get_active()) {
        moptions.editor_out_dir = Options::EDITOR_OUT_DIR_TEMP;
    } else if (editor_dir_current->get_active()) {
        moptions.editor_out_dir = Options::EDITOR_OUT_DIR_CURRENT;
    } else {
        moptions.editor_out_dir = Options::EDITOR_OUT_DIR_CUSTOM;
    }
    moptions.editor_custom_out_dir = editor_dir_custom_path->get_filename();
    moptions.editor_float32 = editor_float32->get_active();
    moptions.editor_bypass_output_profile =
        editor_bypass_output_profile->get_active();

    moptions.CPBPath = txtCustProfBuilderPath->get_text();
    moptions.CPBKeys =
        CPBKeyType(custProfBuilderLabelType->get_active_row_number());

    {
        auto &pp = moptions.rtSettings.printerProfile;
        pp = prtProfile->get_filename();
        if (!pp.empty()) {
            pp = "file:" + pp;
        }
    }
    // if (!prtProfile->get_active_row_number()) {
    //     moptions.rtSettings.printerProfile = "";
    // } else {
    //     moptions.rtSettings.printerProfile = prtProfile->get_active_text ();
    // }

    switch (prtIntent->get_active_row_number()) {
    default:
    case 0:
        moptions.rtSettings.printerIntent = rtengine::RI_PERCEPTUAL;
        break;

    case 1:
        moptions.rtSettings.printerIntent = rtengine::RI_RELATIVE;
        break;

    case 2:
        moptions.rtSettings.printerIntent = rtengine::RI_ABSOLUTE;
        break;
    }

    moptions.rtSettings.printerBPC = prtBPC->get_active();

    if (rtengine::Settings::color_mgmt_mode ==
        rtengine::Settings::ColorManagementMode::APPLICATION) {
        if (!monProfile->get_active_row_number()) {
            moptions.rtSettings.monitorProfile = "";
        } else {
            moptions.rtSettings.monitorProfile = monProfile->get_active_text();
        }

        switch (monIntent->get_active_row_number()) {
        default:
        case 0:
            moptions.rtSettings.monitorIntent = rtengine::RI_PERCEPTUAL;
            break;

        case 1:
            moptions.rtSettings.monitorIntent = rtengine::RI_RELATIVE;
            break;

        case 2:
            moptions.rtSettings.monitorIntent = rtengine::RI_ABSOLUTE;
            break;
        }

        moptions.rtSettings.monitorBPC = monBPC->get_active();
        moptions.rtSettings.autoMonitorProfile = cbAutoMonProfile->get_active();
    } else if (rtengine::Settings::color_mgmt_mode ==
               rtengine::Settings::ColorManagementMode::
                   OS_STD_MONITOR_PROFILE) {
        moptions.rtSettings.os_monitor_profile =
            rtengine::Settings::StdMonitorProfile(
                monProfile->get_active_row_number());
    }

    moptions.rtSettings.iccDirectory = iccDir->get_filename();
    moptions.rtSettings.monitorIccDirectory = monitorIccDir->get_filename();

    moptions.prevdemo = (prevdemo_t)cprevdemo->get_active_row_number();
    moptions.serializeTiffRead = ctiffserialize->get_active();
    moptions.denoiseZoomedOut = denoiseZoomedOut->get_active();
    moptions.wb_preview_mode =
        Options::WBPreviewMode(wbpreview->get_active_row_number());
    moptions.preview_resampling_quality = Options::PreviewResamplingQuality(
        preview_resampling_quality->get_active_row_number());

    if (sdcurrent->get_active()) {
        moptions.startupDir = Options::STARTUPDIR_CURRENT;
    } else if (sdhome->get_active()) {
        moptions.startupDir = Options::STARTUPDIR_HOME;
    } else if (sdlast->get_active()) {
        moptions.startupDir = Options::STARTUPDIR_LAST;
    } else if (sdother->get_active()) {
        moptions.startupDir = Options::STARTUPDIR_CUSTOM;
        moptions.startupPath = startupdir->get_text();
    }

    moptions.parseExtensions.clear();
    moptions.parseExtensionsEnabled.clear();
    Gtk::TreeNodeChildren c = extensionModel->children();

    for (size_t i = 0; i < c.size(); i++) {
        moptions.parseExtensions.push_back(c[i][extensionColumns.ext]);
        moptions.parseExtensionsEnabled.push_back(
            c[i][extensionColumns.enabled]);
    }

    moptions.maxRecentFolders = (int)maxRecentFolders->get_value();
    moptions.maxThumbnailHeight = (int)maxThumbHeightSB->get_value();
    moptions.maxCacheEntries = (int)maxCacheEntriesSB->get_value();
    moptions.overlayedFileNames = overlayedFileNames->get_active();
    moptions.filmStripOverlayedFileNames =
        filmStripOverlayedFileNames->get_active();
    moptions.highlight_selected_thumbnails =
        highlight_selected_thumbnails->get_active();
    moptions.sameThumbSize = sameThumbSize->get_active();
    moptions.internalThumbIfUntouched =
        ckbInternalThumbIfUntouched->get_active();

    auto save_where = saveParamsPreference->get_active_row_number();
    moptions.saveParamsFile = save_where == 0 || save_where == 2;
    moptions.saveParamsCache = save_where == 1 || save_where == 2;
    moptions.paramsLoadLocation =
        (PPLoadLocation)loadParamsPreference->get_active_row_number();
    moptions.params_out_embed =
        saveOutParamsPreference->get_active_row_number() == 1;
    moptions.params_sidecar_strip_extension =
        paramsSidecarStripExtension->get_active_row_number() == 1;
    moptions.useBundledProfiles = useBundledProfiles->get_active();

    moptions.rtSettings.darkFramesPath = darkFrameDir->get_filename();
    moptions.rtSettings.flatFieldsPath = flatFieldDir->get_filename();

    moptions.clutsDir = clutsDir->get_filename();

    int editorMode = editorLayout->get_active_row_number();
    moptions.tabbedUI = (editorMode > 1);
    moptions.multiDisplayMode = editorMode == 3 ? 1 : 0;
    moptions.filmstripBottom = editorMode == 1;

    moptions.curvebboxpos = curveBBoxPosC->get_active_row_number();
    moptions.histogramPosition = ckbHistogramPositionLeft->get_active()
                                     ? Options::HISTOGRAM_POS_LEFT
                                     : Options::HISTOGRAM_POS_RIGHT;
    moptions.FileBrowserToolbarSingleRow =
        ckbFileBrowserToolbarSingleRow->get_active();
    moptions.showFilmStripToolBar = ckbShowFilmStripToolBar->get_active();
    moptions.hideTPVScrollbar = ckbHideTPVScrollbar->get_active();
    moptions.overwriteOutputFile = chOverwriteOutputFile->get_active();
    moptions.adjuster_force_linear = adjuster_force_linear->get_active();
    moptions.sidecar_autosave_interval = autosaveInterval->get_value();

    moptions.autoSaveTpOpen = ckbAutoSaveTpOpen->get_active();

    moptions.rgbDenoiseThreadLimit = threadsSpinBtn->get_value_as_int();
    moptions.clutCacheSize = clutCacheSizeSB->get_value_as_int();
    moptions.maxInspectorBuffers = maxInspectorBuffersSB->get_value_as_int();
    moptions.rtSettings.thread_pool_size =
        thumbUpdateThreadLimit->get_value_as_int();
    moptions.thumb_delay_update = thumbDelayUpdate->get_active();
    moptions.thumb_lazy_caching = thumbLazyCaching->get_active();
    moptions.thumb_cache_processed = thumb_cache_processed_->get_active();
    moptions.rtSettings.ctl_scripts_fast_preview =
        ctl_scripts_fast_preview_->get_active();

// Sounds only on Windows and Linux
#if defined(WIN32) || defined(__linux__)
    moptions.sndEnable = ckbSndEnable->get_active();
    moptions.sndBatchQueueDone = txtSndBatchQueueDone->get_text();
    moptions.sndLngEditProcDone = txtSndLngEditProcDone->get_text();
    moptions.sndLngEditProcDoneSecs = spbSndLngEditProcDoneSecs->get_value();
#endif

    moptions.thumbnail_rating_mode =
        thumbRatingMode->get_active()
            ? Options::ThumbnailRatingMode::XMP
            : Options::ThumbnailRatingMode::PROCPARAMS;
    moptions.rtSettings.metadata_xmp_sync = rtengine::Settings::MetadataXmpSync(
        metadataSyncCombo->get_active_row_number());
    moptions.rtSettings.xmp_sidecar_style = rtengine::Settings::XmpSidecarStyle(
        xmpSidecarCombo->get_active_row_number());
    moptions.rtSettings.exiftool_path = exiftoolPath->get_text();
    moptions.show_exiftool_makernotes = show_exiftool_makernotes->get_active();

    moptions.toolpanels_disable = ckbTpDisable->get_active();

    moptions.remember_exif_filter_settings =
        remember_metadata_filters->get_active();
    moptions.renaming_remember = remember_rename_options->get_active();
    moptions.dir_browser_single_click = dir_browser_single_click->get_active();

    moptions.fastexport_resize_width = fastexport_max_width->get_value();
    moptions.fastexport_resize_height = fastexport_max_height->get_value();
}

void Preferences::fillPreferences()
{
    tconn.block(true);
    fconn.block(true);
    cpfconn.block(true);
    sconn.block(true);
    dfconn.block(true);
    ffconn.block(true);
    rpconn.block(true);
    ipconn.block(true);
    bpconn.block(true);

    rprofiles->setActiveRowFromFullPath(moptions.defProfRaw);
    forRAWComboChanged(); // update the tooltip
    iprofiles->setActiveRowFromFullPath(moptions.defProfImg);
    forImageComboChanged(); // update the tooltip
    dateformat->set_text(moptions.dateFormat);
    panFactor->set_value(moptions.panAccelFactor);
    rememberZoomPanCheckbutton->set_active(moptions.rememberZoomAndPan);

    thumbnailInspectorHover->set_active(moptions.thumbnail_inspector_hover);

    ctiffserialize->set_active(moptions.serializeTiffRead);
    denoiseZoomedOut->set_active(moptions.denoiseZoomedOut);
    wbpreview->set_active(int(moptions.wb_preview_mode));

    // setActiveTextOrIndex (*prtProfile, moptions.rtSettings.printerProfile,
    // 0);
    {
        auto pp = moptions.rtSettings.printerProfile;
        if (pp.find("file:") == 0) {
            pp = pp.substr(5);
            if (Glib::file_test(pp, Glib::FILE_TEST_EXISTS)) {
                prtProfile->set_filename(pp);
            }
        }
    }

    switch (moptions.rtSettings.printerIntent) {
    default:
    case rtengine::RI_PERCEPTUAL:
        prtIntent->set_active(0);
        break;

    case rtengine::RI_RELATIVE:
        prtIntent->set_active(1);
        break;

    case rtengine::RI_ABSOLUTE:
        prtIntent->set_active(2);
        break;
    }

    prtBPC->set_active(moptions.rtSettings.printerBPC);

    if (rtengine::Settings::color_mgmt_mode ==
        rtengine::Settings::ColorManagementMode::APPLICATION) {
        setActiveTextOrIndex(*monProfile, moptions.rtSettings.monitorProfile,
                             0);

        switch (moptions.rtSettings.monitorIntent) {
        default:
        case rtengine::RI_PERCEPTUAL:
            monIntent->set_active(0);
            break;

        case rtengine::RI_RELATIVE:
            monIntent->set_active(1);
            break;

        case rtengine::RI_ABSOLUTE:
            monIntent->set_active(2);
            break;
        }

        monBPC->set_active(moptions.rtSettings.monitorBPC);
        cbAutoMonProfile->set_active(moptions.rtSettings.autoMonitorProfile);
    } else {
        monProfile->set_active(int(moptions.rtSettings.os_monitor_profile));
    }

    if (Glib::file_test(moptions.rtSettings.iccDirectory,
                        Glib::FILE_TEST_IS_DIR)) {
        iccDir->set_current_folder(moptions.rtSettings.iccDirectory);
    }

    if (Glib::file_test(moptions.rtSettings.monitorIccDirectory,
                        Glib::FILE_TEST_IS_DIR)) {
        monitorIccDir->set_current_folder(
            moptions.rtSettings.monitorIccDirectory);
    }

    cprevdemo->set_active(moptions.prevdemo);
    preview_resampling_quality->set_active(
        int(moptions.preview_resampling_quality));

    languages->set_active_text(moptions.language);
    ckbLangAutoDetect->set_active(moptions.languageAutoDetect);
    int themeNbr = getThemeRowNumber(moptions.theme);
    themeCBT->set_active(themeNbr == -1 ? 0 : themeNbr);

    // Gdk::RGBA cropCol;
    // cropCol.set_rgba (moptions.cutOverlayBrush[0],
    // moptions.cutOverlayBrush[1], moptions.cutOverlayBrush[2]);
    // cropMaskColorCB->set_rgba (cropCol);
    // cropMaskColorCB->set_alpha ( (unsigned short)
    // (moptions.cutOverlayBrush[3] * 65535.0));

    // Gdk::RGBA NavGuideCol;
    // NavGuideCol.set_rgba (moptions.navGuideBrush[0],
    // moptions.navGuideBrush[1], moptions.navGuideBrush[2]);
    // navGuideColorCB->set_rgba (NavGuideCol);
    // navGuideColorCB->set_alpha ( (unsigned short) (moptions.navGuideBrush[3]
    // * 65535.0));

    Gdk::RGBA bg_col;
    bg_col.set_rgba(moptions.theme_bg_color[0] / 255.0,
                    moptions.theme_bg_color[1] / 255.0,
                    moptions.theme_bg_color[2] / 255.0);
    theme_bg_color->set_rgba(bg_col);

    Gdk::RGBA fg_col;
    fg_col.set_rgba(moptions.theme_fg_color[0] / 255.0,
                    moptions.theme_fg_color[1] / 255.0,
                    moptions.theme_fg_color[2] / 255.0);
    theme_fg_color->set_rgba(fg_col);

    Gdk::RGBA hl_col;
    hl_col.set_rgba(moptions.theme_hl_color[0] / 255.0,
                    moptions.theme_hl_color[1] / 255.0,
                    moptions.theme_hl_color[2] / 255.0);
    theme_hl_color->set_rgba(hl_col);

    if (options.fontFamily == "default") {
        mainFontFB->set_font_name(Glib::ustring::compose(
            "%1 %2", initialFontFamily, initialFontSize));
    } else {
        mainFontFB->set_font_name(Glib::ustring::compose(
            "%1 %2", options.fontFamily, options.fontSize));
    }

    if (options.CPFontFamily == "default") {
        colorPickerFontFB->set_font_name(Glib::ustring::compose(
            "%1 %2", initialFontFamily, initialFontSize));
    } else {
        colorPickerFontFB->set_font_name(Glib::ustring::compose(
            "%1 %2", options.CPFontFamily, options.CPFontSize));
    }

    pseudoHiDPI->set_active(options.pseudoHiDPISupport);

    showDateTime->set_active(moptions.fbShowDateTime);
    showBasicExif->set_active(moptions.fbShowBasicExif);
    showExpComp->set_active(moptions.fbShowExpComp);
    // ckbmenuGroupRank->set_active (moptions.menuGroupRank);
    // ckbmenuGroupLabel->set_active (moptions.menuGroupLabel);
    // ckbmenuGroupFileOperations->set_active
    // (moptions.menuGroupFileOperations);
    // ckbmenuGroupProfileOperations->set_active
    // (moptions.menuGroupProfileOperations); ckbmenuGroupExtProg->set_active
    // (moptions.menuGroupExtProg);

    hlThresh->set_value(moptions.highlightThreshold);
    shThresh->set_value(moptions.shadowThreshold);

    edGimp->set_active(moptions.editorToSendTo == 1);
    edOther->set_active(moptions.editorToSendTo == 3);
#ifdef WIN32
    edPS->set_active(moptions.editorToSendTo == 2);

    if (Glib::file_test(moptions.gimpDir, Glib::FILE_TEST_IS_DIR)) {
        gimpDir->set_current_folder(moptions.gimpDir);
    } else {
        gimpDir->set_current_folder(Glib::get_home_dir());
    }

    if (Glib::file_test(moptions.psDir, Glib::FILE_TEST_IS_DIR)) {
        psDir->set_current_folder(moptions.psDir);
    } else {
        psDir->set_current_folder(Glib::get_home_dir());
    }

#elif defined __APPLE__
    edPS->set_active(moptions.editorToSendTo == 2);

    // if (Glib::file_test (moptions.psDir, Glib::FILE_TEST_IS_DIR)) {
    //     psDir->set_current_folder (moptions.psDir);
    // } else {
    //     psDir->set_current_folder (Glib::get_home_dir());
    // }

#endif
    editorToSendTo->set_text(moptions.customEditorProg);

    editor_dir_temp->set_active(moptions.editor_out_dir ==
                                Options::EDITOR_OUT_DIR_TEMP);
    editor_dir_current->set_active(moptions.editor_out_dir ==
                                   Options::EDITOR_OUT_DIR_CURRENT);
    editor_dir_custom->set_active(moptions.editor_out_dir ==
                                  Options::EDITOR_OUT_DIR_CUSTOM);
    if (Glib::file_test(moptions.editor_custom_out_dir,
                        Glib::FILE_TEST_IS_DIR)) {
        editor_dir_custom_path->set_current_folder(
            moptions.editor_custom_out_dir);
    } else {
        editor_dir_custom_path->set_current_folder(Glib::get_tmp_dir());
    }
    editor_float32->set_active(moptions.editor_float32);
    editor_bypass_output_profile->set_active(
        moptions.editor_bypass_output_profile);

    txtCustProfBuilderPath->set_text(moptions.CPBPath);
    custProfBuilderLabelType->set_active(moptions.CPBKeys);

    if (moptions.startupDir == Options::STARTUPDIR_CURRENT) {
        sdcurrent->set_active();
    } else if (moptions.startupDir == Options::STARTUPDIR_LAST) {
        sdlast->set_active();
    } else if (moptions.startupDir == Options::STARTUPDIR_HOME) {
        sdhome->set_active();
    } else if (moptions.startupDir == Options::STARTUPDIR_CUSTOM) {
        sdother->set_active();
        startupdir->set_text(moptions.startupPath);
    }

    extensionModel->clear();

    for (size_t i = 0; i < moptions.parseExtensions.size(); i++) {
        Gtk::TreeRow row = *(extensionModel->append());
        row[extensionColumns.enabled] = moptions.parseExtensionsEnabled[i];
        row[extensionColumns.ext] = moptions.parseExtensions[i];
    }

    maxRecentFolders->set_value(moptions.maxRecentFolders);
    maxThumbHeightSB->set_value(moptions.maxThumbnailHeight);
    maxCacheEntriesSB->set_value(moptions.maxCacheEntries);
    overlayedFileNames->set_active(moptions.overlayedFileNames);
    filmStripOverlayedFileNames->set_active(
        moptions.filmStripOverlayedFileNames);
    highlight_selected_thumbnails->set_active(
        moptions.highlight_selected_thumbnails);
    sameThumbSize->set_active(moptions.sameThumbSize);
    ckbInternalThumbIfUntouched->set_active(moptions.internalThumbIfUntouched);

    saveParamsPreference->set_active(
        moptions.saveParamsFile ? (moptions.saveParamsCache ? 2 : 0) : 1);

    loadParamsPreference->set_active(moptions.paramsLoadLocation);
    saveOutParamsPreference->set_active(moptions.params_out_embed ? 1 : 0);
    paramsSidecarStripExtension->set_active(
        moptions.params_sidecar_strip_extension ? 1 : 0);
    useBundledProfiles->set_active(moptions.useBundledProfiles);

    if (!moptions.tabbedUI) {
        editorLayout->set_active(moptions.filmstripBottom ? 1 : 0);
    } else {
        editorLayout->set_active(moptions.multiDisplayMode ? 3 : 2);
    }

    curveBBoxPosC->set_active(moptions.curvebboxpos);
    ckbHistogramPositionLeft->set_active(moptions.histogramPosition ==
                                         Options::HISTOGRAM_POS_LEFT);
    ckbFileBrowserToolbarSingleRow->set_active(
        moptions.FileBrowserToolbarSingleRow);
    ckbShowFilmStripToolBar->set_active(moptions.showFilmStripToolBar);
    ckbHideTPVScrollbar->set_active(moptions.hideTPVScrollbar);
    adjuster_force_linear->set_active(moptions.adjuster_force_linear);

    ckbAutoSaveTpOpen->set_active(moptions.autoSaveTpOpen);

    threadsSpinBtn->set_value(moptions.rgbDenoiseThreadLimit);
    clutCacheSizeSB->set_value(moptions.clutCacheSize);
    maxInspectorBuffersSB->set_value(moptions.maxInspectorBuffers);
    thumbUpdateThreadLimit->set_value(moptions.rtSettings.thread_pool_size);
    thumbDelayUpdate->set_active(moptions.thumb_delay_update);
    thumbLazyCaching->set_active(moptions.thumb_lazy_caching);
    thumb_cache_processed_->set_active(moptions.thumb_cache_processed);
    ctl_scripts_fast_preview_->set_active(
        moptions.rtSettings.ctl_scripts_fast_preview);

    if (!moptions.rtSettings.darkFramesPath.empty()) {
        darkFrameDir->set_current_folder(moptions.rtSettings.darkFramesPath);
        darkFrameChanged();
    }

    if (!moptions.rtSettings.flatFieldsPath.empty()) {
        flatFieldDir->set_current_folder(moptions.rtSettings.flatFieldsPath);
        flatFieldChanged();
    }

    clutsDir->set_current_folder(moptions.clutsDir);

    addc.block(true);
    setc.block(true);

    addc.block(false);
    setc.block(false);
    cpfconn.block(false);
    fconn.block(false);
    tconn.block(false);
    sconn.block(false);
    dfconn.block(false);
    ffconn.block(false);
    rpconn.block(true);
    ipconn.block(true);
    bpconn.block(false);

    chOverwriteOutputFile->set_active(moptions.overwriteOutputFile);
    autosaveInterval->set_value(moptions.sidecar_autosave_interval);

    // Sounds only on Windows and Linux
#if defined(WIN32) || defined(__linux__)
    ckbSndEnable->set_active(moptions.sndEnable);
    txtSndBatchQueueDone->set_text(moptions.sndBatchQueueDone);
    txtSndLngEditProcDone->set_text(moptions.sndLngEditProcDone);
    spbSndLngEditProcDoneSecs->set_value(moptions.sndLngEditProcDoneSecs);
#endif

    thumbRatingMode->set_active(moptions.thumbnail_rating_mode ==
                                Options::ThumbnailRatingMode::XMP);
    metadataSyncCombo->set_active(int(moptions.rtSettings.metadata_xmp_sync));
    xmpSidecarCombo->set_active(int(moptions.rtSettings.xmp_sidecar_style));
    exiftoolPath->set_text(moptions.rtSettings.exiftool_path);
    show_exiftool_makernotes->set_active(moptions.show_exiftool_makernotes);

    ckbTpDisable->set_active(moptions.toolpanels_disable);

    remember_metadata_filters->set_active(
        moptions.remember_exif_filter_settings);
    remember_rename_options->set_active(moptions.renaming_remember);
    dir_browser_single_click->set_active(moptions.dir_browser_single_click);

    fastexport_max_width->set_value(moptions.fastexport_resize_width);
    fastexport_max_height->set_value(moptions.fastexport_resize_height);

    bool theme_colors_visible =
        (GTK_MINOR_VERSION >= 20 && moptions.theme == Options::DEFAULT_THEME);
    theme_bg_lbl->set_visible(theme_colors_visible);
    theme_fg_lbl->set_visible(theme_colors_visible);
    theme_hl_lbl->set_visible(theme_colors_visible);
    theme_bg_color->set_visible(theme_colors_visible);
    theme_fg_color->set_visible(theme_colors_visible);
    theme_hl_color->set_visible(theme_colors_visible);
    theme_colors_reset->set_visible(theme_colors_visible);
}

void Preferences::autoMonProfileToggled()
{
    monProfile->set_sensitive(!cbAutoMonProfile->get_active());
}

void Preferences::sndEnableToggled()
{
    txtSndBatchQueueDone->set_sensitive(ckbSndEnable->get_active());
    txtSndLngEditProcDone->set_sensitive(ckbSndEnable->get_active());
    spbSndLngEditProcDoneSecs->set_sensitive(ckbSndEnable->get_active());
}

void Preferences::langAutoDetectToggled()
{
    languages->set_sensitive(!ckbLangAutoDetect->get_active());
}

void Preferences::okPressed()
{

    storePreferences();
    workflowUpdate();
    options.copyFrom(&moptions);
    options.filterOutParsedExtensions();

    try {
        Options::save();
    } catch (Options::Error &e) {
        Gtk::MessageDialog msgd(getToplevelWindow(this), e.get_msg(), true,
                                Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true);
        msgd.run();
    }

    dynProfilePanel->save();
    hide();
}

void Preferences::cancelPressed()
{
    // set the initial theme back
    if (themeFNames.at(themeCBT->get_active_row_number()).longFName !=
            options.theme ||
        options.theme_bg_color != moptions.theme_bg_color ||
        options.theme_fg_color != moptions.theme_fg_color ||
        options.theme_hl_color != moptions.theme_hl_color) {
        // RTImage::updateImages();
        switchThemeTo(options.theme);
    }

    // set the initial font back
    Pango::FontDescription fd(mainFontFB->get_font_name());

    if (getFontFamily(fd) != options.fontFamily &&
        (fd.get_size() / Pango::SCALE) != options.fontSize) {
        if (options.fontFamily == "default") {
            switchFontTo(initialFontFamily, initialFontSize);
        } else {
            switchFontTo(options.fontFamily, options.fontSize);
        }
    }

    // update the profileStore
    if (useBundledProfiles->get_active() != options.useBundledProfiles) {
        // we have to rescan with the old value
        bpconn.block(true);
        useBundledProfiles->set_active(false);
        bundledProfilesChanged();
        bpconn.block(false);
    }

    hide();
}

void Preferences::selectStartupDir()
{

    Gtk::FileChooserDialog dialog(getToplevelWindow(this),
                                  M("PREFERENCES_DIRSELECTDLG"),
                                  Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
    // dialog.set_transient_for(*this);

    // Add response buttons to the dialog:
    dialog.add_button(M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL);
    dialog.add_button(M("GENERAL_OPEN"), Gtk::RESPONSE_OK);

    int result = dialog.run();

    if (result == Gtk::RESPONSE_OK) {
        startupdir->set_text(dialog.get_filename());
    }
}

void Preferences::aboutPressed()
{

    splash = new Splash(*this);
    splash->set_transient_for(*this);
    splash->signal_delete_event().connect(
        sigc::mem_fun(*this, &Preferences::splashClosed));
    splash->show();
}

void Preferences::themeChanged()
{
    moptions.theme =
        themeFNames.at(themeCBT->get_active_row_number()).longFName;
    moptions.theme_bg_color = get_theme_color(theme_bg_color);
    moptions.theme_fg_color = get_theme_color(theme_fg_color);
    moptions.theme_hl_color = get_theme_color(theme_hl_color);

    bool theme_color_visible =
        (GTK_MINOR_VERSION >= 20 && moptions.theme == Options::DEFAULT_THEME);

    theme_bg_lbl->set_visible(theme_color_visible);
    theme_fg_lbl->set_visible(theme_color_visible);
    theme_hl_lbl->set_visible(theme_color_visible);
    theme_bg_color->set_visible(theme_color_visible);
    theme_fg_color->set_visible(theme_color_visible);
    theme_hl_color->set_visible(theme_color_visible);
    theme_colors_reset->set_visible(theme_color_visible);

    // RTImage::cleanup(true);
    options.svg_color = options.svg_dark_color;
    if (theme_color_visible) {
        options.svg_color = rtengine::get_html_color(
            moptions.theme_fg_color[0], moptions.theme_fg_color[1],
            moptions.theme_fg_color[2]);
        if (options.rtSettings.verbose > 1) {
            std::cout << "switched to svg color: " << options.svg_color
                      << std::endl;
        }
    }
    // RTImage::updateImages();
    switchThemeTo(moptions.theme, &moptions);
}

void Preferences::forRAWComboChanged()
{
    if (!rprofiles) {
        return;
    }

    const ProfileStoreEntry *selectedEntry = rprofiles->getSelectedEntry();

    if (!selectedEntry) {
        return;
    }

    if (selectedEntry->type == PSET_FOLDER) {
        rpconn.block(true);
        rprofiles->set_active(currRawRow);
        rpconn.block(false);
    } else {
        currRawRow = rprofiles->get_active();
    }

    rprofiles->set_tooltip_text(selectedEntry->label);
}

void Preferences::forImageComboChanged()
{
    if (!iprofiles) {
        return;
    }

    const ProfileStoreEntry *selectedEntry = iprofiles->getSelectedEntry();

    if (!selectedEntry) {
        return;
    }

    if (selectedEntry->type == PSET_FOLDER) {
        ipconn.block(true);
        iprofiles->set_active(currImgRow);
        ipconn.block(false);
    } else {
        currImgRow = rprofiles->get_active();
    }

    iprofiles->set_tooltip_text(iprofiles->getSelectedEntry()->label);
}

void Preferences::layoutComboChanged()
{
    editorLayout->set_tooltip_text(editorLayout->get_active_text());
}

void Preferences::bundledProfilesChanged()
{
    rpconn.block(true);
    ipconn.block(true);

    // parseProfiles does use options.useBundledProfiles, so we temporarily
    // change its value
    bool currValue = options.useBundledProfiles;
    options.useBundledProfiles = useBundledProfiles->get_active();

    // rescan the file's tree
    ProfileStore::getInstance()
        ->parseProfiles(); // This will call Preferences::updateProfileList in
                           // return

    // restoring back the old value
    options.useBundledProfiles = currValue;

    ipconn.block(false);
    rpconn.block(false);
}

void Preferences::iccDirChanged()
{
    const auto currentSelection = monProfile->get_active_text();
    const auto profiles = rtengine::ICCStore::getInstance()->getProfilesFromDir(
        monitorIccDir->get_filename());

    monProfile->remove_all();

    monProfile->append(M("PREFERENCES_PROFILE_NONE"));

    for (const auto &profile : profiles) {
        monProfile->append(profile);
    }

    setActiveTextOrIndex(*monProfile, currentSelection, 0);
}

void Preferences::storeCurrentValue()
{
    // TODO: Find a way to get and restore the current selection; the following
    // line can't work anymore
    storedValueRaw = rprofiles->getFullPathFromActiveRow();
    storedValueImg = iprofiles->getFullPathFromActiveRow();
}

void Preferences::updateProfileList()
{
    rprofiles->updateProfileList();
    iprofiles->updateProfileList();
    const ProfileStoreEntry *dynpse =
        ProfileStore::getInstance()->getInternalDynamicPSE();
    rprofiles->addRow(dynpse);
    iprofiles->addRow(dynpse);
}

void Preferences::restoreValue()
{
    if (!rprofiles->setActiveRowFromFullPath(storedValueRaw)) {
        moptions.defProfRaw = Options::DEFPROFILE_INTERNAL;
        rpconn.block(true);
        rprofiles->setInternalEntry();
        rpconn.block(false);
    }

    currRawRow = rprofiles->get_active();

    if (!iprofiles->setActiveRowFromFullPath(storedValueImg)) {
        moptions.defProfImg = Options::DEFPROFILE_INTERNAL;
        ipconn.block(true);
        iprofiles->setInternalEntry();
        ipconn.block(false);
    }

    currImgRow = iprofiles->get_active();

    storedValueRaw = "";
    storedValueImg = "";
}

namespace {

std::vector<int> get_theme_color(const std::vector<int> &c)
{
    std::vector<int> res(c);
    getGUIColor(res[0], res[1], res[2]);
    return res;
}

} // namespace

void Preferences::switchThemeTo(const Glib::ustring &newTheme,
                                const Options *opts)
{
    if (!themecss) {
        themecss = Gtk::CssProvider::create();
        Glib::RefPtr<Gdk::Screen> screen = Gdk::Screen::get_default();
        Gtk::StyleContext::add_provider_for_screen(
            screen, themecss, GTK_STYLE_PROVIDER_PRIORITY_USER);
    }

    if (GTK_MINOR_VERSION >= 20 && newTheme == Options::DEFAULT_THEME) {
        if (!opts) {
            opts = &options;
        }
        const auto pth = [](std::string s) -> std::string {
#ifdef WIN32
            for (auto &c : s) {
                if (c == '\\') {
                    c = '/';
                }
            }
#endif // WIN32
            return s;
        };
        std::ostringstream buf;
        auto bg = get_theme_color(opts->theme_bg_color);
        auto fg = get_theme_color(opts->theme_fg_color);
        auto hl = get_theme_color(opts->theme_hl_color);
        auto lum = rtengine::Color::rgbLuminance(bg[0] / 255.0, bg[1] / 255.0,
                                                 bg[2] / 255.0);
        float factor = 0.1;
        if (lum < 0.2) {
            factor = 2 + (0.2 - lum) / 0.2;
        } else if (lum > 0.5) {
            factor = 0.2 + 0.6 * (lum - 0.5) / 0.5;
        }
        std::string dark =
            std::string("rgb(") + std::to_string(int(bg[0] * factor)) + "," +
            std::to_string(int(bg[1] * factor)) + "," +
            std::to_string(int(bg[2] * factor)) + ")"; // "black";
        std::string filename(
            Glib::build_filename(options.ART_base_dir, "themes", "_ART.css"));
        buf << "@define-color ART-bg rgb(" << bg[0] << "," << bg[1] << ","
            << bg[2] << ");\n"
            << "@define-color ART-fg rgb(" << fg[0] << "," << fg[1] << ","
            << fg[2] << ");\n"
            << "@define-color ART-hl rgb(" << hl[0] << "," << hl[1] << ","
            << hl[2] << ");\n"
            << "@define-color ART-dark " << dark << ";\n"
            << "@import \"" << pth(filename) << "\";\n";
        try {
            themecss->load_from_data(buf.str());
        } catch (Glib::Error &err) {
            printf("Error: Can't load css file \"%s\"\nMessage: %s\n",
                   filename.c_str(), err.what().c_str());
        } catch (...) {
            printf("Error: Can't load css file \"%s\"\n", filename.c_str());
        }
    } else {
        Glib::ustring filename(Glib::build_filename(
            options.ART_base_dir, "themes", newTheme + ".css"));

        try {
            themecss->load_from_path(filename);
        } catch (Glib::Error &err) {
            printf("Error: Can't load css file \"%s\"\nMessage: %s\n",
                   filename.c_str(), err.what().c_str());
        } catch (...) {
            printf("Error: Can't load css file \"%s\"\n", filename.c_str());
        }
    }
}

void Preferences::fontChanged()
{
    newFont = true;
    Pango::FontDescription fd(mainFontFB->get_font_name());
    switchFontTo(getFontFamily(fd), fd.get_size() / Pango::SCALE);
}

void Preferences::cpFontChanged() { newCPFont = true; }

void Preferences::switchFontTo(const Glib::ustring &newFontFamily,
                               const int newFontSize)
{

    if (newFontFamily != "default") {
        if (!fontcss) {
            fontcss = Gtk::CssProvider::create();
            Glib::RefPtr<Gdk::Screen> screen = Gdk::Screen::get_default();
            Gtk::StyleContext::add_provider_for_screen(
                screen, fontcss, GTK_STYLE_PROVIDER_PRIORITY_USER);
        }

        try {
            // GTK318
            // #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 20
            //             fontcss->load_from_data (Glib::ustring::compose ("* {
            //             font-family: %1; font-size: %2px }", newFontFamily,
            //             newFontSize * RTScalable::getPseudoHiDPIScale()));
            // #else
            fontcss->load_from_data(Glib::ustring::compose(
                "* { font-family: %1; font-size: %2pt }", newFontFamily,
                newFontSize * RTScalable::getPseudoHiDPIScale()));
            // #endif
            // GTK318
        } catch (Glib::Error &err) {
            printf("Error: \"%s\"\n", err.what().c_str());
        } catch (...) {
            printf("Error: Can't find the font named \"%s\"\n",
                   newFontFamily.c_str());
        }
    } else {
        if (fontcss) {
            fontcss = Gtk::CssProvider::create();
            Glib::RefPtr<Gdk::Screen> screen = Gdk::Screen::get_default();
            Gtk::StyleContext::remove_provider_for_screen(screen, fontcss);
        }
    }
}

void Preferences::workflowUpdate()
{

    if (moptions.tabbedUI != options.tabbedUI) {
        parent->setEditorMode(moptions.tabbedUI);
    }

    if (moptions.hideTPVScrollbar != options.hideTPVScrollbar) {
        // Update the tool panels
        parent->updateTPVScrollbar(moptions.hideTPVScrollbar);
    }

    if (moptions.FileBrowserToolbarSingleRow !=
        options.FileBrowserToolbarSingleRow) {
        // Update the position of the Query toolbar
        parent->updateFBQueryTB(moptions.FileBrowserToolbarSingleRow);
    }

    if (moptions.showFilmStripToolBar != options.showFilmStripToolBar) {
        // Update the visibility of FB toolbar
        parent->updateFBToolBarVisibility(moptions.showFilmStripToolBar);
    }

    if (moptions.histogramPosition != options.histogramPosition) {
        // Update the position of the Histogram
        parent->updateHistogramPosition(options.histogramPosition,
                                        moptions.histogramPosition);
    }

    if (moptions.rtSettings.printerProfile !=
            options.rtSettings.printerProfile ||
        moptions.rtSettings.printerBPC != options.rtSettings.printerBPC ||
        moptions.rtSettings.printerIntent != options.rtSettings.printerIntent) {
        // Update the position of the Histogram
        parent->updateProfiles(moptions.rtSettings.printerProfile,
                               moptions.rtSettings.printerIntent,
                               moptions.rtSettings.printerBPC);
    }
}

void Preferences::addExtPressed()
{

    Gtk::TreeNodeChildren c = extensionModel->children();

    for (size_t i = 0; i < c.size(); i++)
        if (c[i][extensionColumns.ext] == extension->get_text()) {
            return;
        }

    Gtk::TreeRow row = *(extensionModel->append());

    row[extensionColumns.enabled] = true;
    row[extensionColumns.ext] = extension->get_text();
}

void Preferences::delExtPressed()
{

    extensionModel->erase(extensions->get_selection()->get_selected());
}

void Preferences::moveExtUpPressed()
{
    const Glib::RefPtr<Gtk::TreeSelection> selection =
        extensions->get_selection();

    if (!selection) {
        return;
    }

    const Gtk::TreeModel::iterator selected = selection->get_selected();

    if (!selected || selected == extensionModel->children().begin()) {
        return;
    }

    Gtk::TreeModel::iterator previous = selected;
    --previous;
    extensionModel->iter_swap(selected, previous);
}

void Preferences::moveExtDownPressed()
{
    const Glib::RefPtr<Gtk::TreeSelection> selection =
        extensions->get_selection();

    if (!selection) {
        return;
    }

    const Gtk::TreeModel::iterator selected = selection->get_selected();

    if (!selected) {
        return;
    }

    Gtk::TreeModel::iterator next = selected;

    if (++next) {
        extensionModel->iter_swap(selected, next);
    }
}

void Preferences::clearProfilesPressed() { cacheMgr->clearProfiles(); }

void Preferences::clearThumbImagesPressed() { cacheMgr->clearImages(); }

void Preferences::clearAllPressed() { cacheMgr->clearAll(); }

void Preferences::darkFrameChanged()
{
    // Glib::ustring s(darkFrameDir->get_filename());
    Glib::ustring s(darkFrameDir->get_current_folder());
    // if( s.compare( rtengine::dfm.getPathname()) !=0 ){
    rtengine::dfm.init(s);
    updateDFinfos();
    //}
}

void Preferences::flatFieldChanged()
{
    // Glib::ustring s(flatFieldDir->get_filename());
    Glib::ustring s(flatFieldDir->get_current_folder());
    // if( s.compare( rtengine::ffm.getPathname()) !=0 ){
    rtengine::ffm.init(s);
    updateFFinfos();
    //}
}

void Preferences::updateDFinfos()
{
    int t1, t2;
    rtengine::dfm.getStat(t1, t2);
    Glib::ustring s = Glib::ustring::compose(
        "%1: %2 %3, %4 %5", M("PREFERENCES_DARKFRAMEFOUND"), t1,
        M("PREFERENCES_DARKFRAMESHOTS"), t2,
        M("PREFERENCES_DARKFRAMETEMPLATES"));
    dfLabel->set_text(s);
}

void Preferences::updateFFinfos()
{
    int t1, t2;
    rtengine::ffm.getStat(t1, t2);
    Glib::ustring s = Glib::ustring::compose(
        "%1: %2 %3, %4 %5", M("PREFERENCES_FLATFIELDFOUND"), t1,
        M("PREFERENCES_FLATFIELDSHOTS"), t2,
        M("PREFERENCES_FLATFIELDTEMPLATES"));
    ffLabel->set_text(s);
}

bool Preferences::splashClosed(GdkEventAny *event)
{
    delete splash;
    splash = nullptr;
    return true;
}
