"Fossies" - the Fresh Open Source Software Archive

Member "rawtherapee-5.7/rtgui/filmsimulation.cc" (10 Sep 2019, 12443 Bytes) of package /linux/misc/rawtherapee-5.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "filmsimulation.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.6_vs_5.7.

    1 #include <chrono>
    2 #include <map>
    3 #include <set>
    4 
    5 #include "filmsimulation.h"
    6 
    7 #include "options.h"
    8 
    9 #include "../rtengine/clutstore.h"
   10 #include "../rtengine/procparams.h"
   11 
   12 using namespace rtengine;
   13 using namespace rtengine::procparams;
   14 
   15 namespace
   16 {
   17 
   18 Glib::ustring stripPrefixDir(const Glib::ustring& filename, const Glib::ustring& dir)
   19 {
   20     const Glib::ustring full_dir =
   21         !Glib::str_has_suffix(dir, G_DIR_SEPARATOR_S)
   22             ? dir + G_DIR_SEPARATOR_S
   23             : dir;
   24     return
   25         Glib::str_has_prefix(filename, full_dir)
   26             ? filename.substr(full_dir.size())
   27             : filename;
   28 }
   29 
   30 bool notifySlowParseDir (const std::chrono::system_clock::time_point& startedAt)
   31 {
   32     enum Decision {
   33         UNDECIDED,
   34         CANCEL,
   35         CONTINUE
   36     };
   37 
   38     static Decision decision = UNDECIDED;
   39 
   40     if (decision == CANCEL) {
   41         return false;
   42     } else if (decision == CONTINUE) {
   43         return true;
   44     }
   45 
   46     const auto now = std::chrono::system_clock::now();
   47     if (now - startedAt < std::chrono::seconds(10)) {
   48         return true;
   49     }
   50 
   51     Gtk::MessageDialog dialog(M("TP_FILMSIMULATION_SLOWPARSEDIR"), false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
   52     if (dialog.run() == Gtk::RESPONSE_YES) {
   53         decision = CANCEL;
   54         return false;
   55     } else {
   56         decision = CONTINUE;
   57         return true;
   58     }
   59 }
   60 
   61 }
   62 
   63 FilmSimulation::FilmSimulation()
   64     :   FoldableToolPanel( this, "filmsimulation", M("TP_FILMSIMULATION_LABEL"), false, true )
   65 {
   66     m_clutComboBox = Gtk::manage( new ClutComboBox(options.clutsDir) );
   67     int foundClutsCount = m_clutComboBox->foundClutsCount();
   68 
   69     if ( foundClutsCount == 0 ) {
   70         pack_start( *Gtk::manage( new Gtk::Label( M("TP_FILMSIMULATION_ZEROCLUTSFOUND") ) ) );
   71     }
   72 
   73     m_clutComboBoxConn = m_clutComboBox->signal_changed().connect( sigc::mem_fun( *this, &FilmSimulation::onClutSelected ) );
   74     pack_start( *m_clutComboBox );
   75 
   76     m_strength = Gtk::manage( new Adjuster( M("TP_FILMSIMULATION_STRENGTH"), 0., 100, 1., 100 ) );
   77     m_strength->setAdjusterListener( this );
   78 
   79     pack_start( *m_strength, Gtk::PACK_SHRINK, 0 );
   80 
   81 }
   82 
   83 void FilmSimulation::onClutSelected()
   84 {
   85     Glib::ustring currentClutFilename = m_clutComboBox->getSelectedClut();
   86 
   87     if ( getEnabled() && !currentClutFilename.empty() && listener && currentClutFilename != m_oldClutFilename ) {
   88         Glib::ustring clutName, dummy;
   89         HaldCLUT::splitClutFilename( currentClutFilename, clutName, dummy, dummy );
   90         listener->panelChanged( EvFilmSimulationFilename, clutName );
   91 
   92         m_oldClutFilename = currentClutFilename;
   93     }
   94 }
   95 
   96 void FilmSimulation::enabledChanged ()
   97 {
   98 
   99     if (listener) {
  100         if (get_inconsistent()) {
  101             listener->panelChanged (EvFilmSimulationEnabled, M("GENERAL_UNCHANGED"));
  102         } else if (getEnabled()) {
  103             listener->panelChanged (EvFilmSimulationEnabled, M("GENERAL_ENABLED"));
  104         } else {
  105             listener->panelChanged (EvFilmSimulationEnabled, M("GENERAL_DISABLED"));
  106         }
  107     }
  108 }
  109 
  110 void FilmSimulation::adjusterChanged(Adjuster* a, double newval)
  111 {
  112     if (listener && (multiImage || getEnabled())) {
  113         const Glib::ustring value = a->getTextValue();
  114         listener->panelChanged(EvFilmSimulationStrength, value);
  115     }
  116 }
  117 
  118 void FilmSimulation::setBatchMode( bool batchMode )
  119 {
  120     ToolPanel::setBatchMode( batchMode );
  121     m_clutComboBox->setBatchMode(batchMode);
  122 }
  123 
  124 void FilmSimulation::read( const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited )
  125 {
  126     //copypasted from lensprofile.cc & sharpening.cc
  127     disableListener();
  128     updateDisable(true);
  129 
  130     setEnabled(pp->filmSimulation.enabled);
  131 
  132     if (!pp->filmSimulation.clutFilename.empty()) {
  133         m_clutComboBox->setSelectedClut(
  134             !Glib::path_is_absolute(pp->filmSimulation.clutFilename)
  135                 ? Glib::ustring(Glib::build_filename(options.clutsDir, pp->filmSimulation.clutFilename))
  136                 : pp->filmSimulation.clutFilename
  137         );
  138         m_oldClutFilename = m_clutComboBox->getSelectedClut();
  139     } else {
  140         m_clutComboBox->set_active(-1);
  141     }
  142 
  143     m_strength->setValue(pp->filmSimulation.strength);
  144 
  145     if (pedited) {
  146         set_inconsistent (multiImage && !pedited->filmSimulation.enabled);
  147         m_strength->setEditedState(
  148             pedited->filmSimulation.strength
  149                 ? Edited
  150                 : UnEdited
  151         );
  152 
  153         if (!pedited->filmSimulation.clutFilename) {
  154             m_clutComboBox->setSelectedClut("NULL");
  155         }
  156     }
  157 
  158     if (!get_inconsistent() && !pp->filmSimulation.enabled) {
  159         if (options.clutCacheSize == 1) {
  160             CLUTStore::getInstance().clearCache();
  161         }
  162     }
  163 
  164     updateDisable(false);
  165     enableListener();
  166 }
  167 
  168 void FilmSimulation::updateDisable( bool value )
  169 {
  170     m_clutComboBoxConn.block( value );
  171 }
  172 
  173 void FilmSimulation::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited )
  174 {
  175     if (pedited) {
  176         pedited->filmSimulation.enabled = !get_inconsistent();
  177         pedited->filmSimulation.strength = m_strength->getEditedState();
  178         pedited->filmSimulation.clutFilename = m_clutComboBox->getSelectedClut() != "NULL";
  179     }
  180 
  181     pp->filmSimulation.enabled = getEnabled();
  182     const Glib::ustring clutFName = m_clutComboBox->getSelectedClut();
  183 
  184     if (clutFName != "NULL") { // We do not want to set "NULL" in clutFilename, even if "unedited"
  185         pp->filmSimulation.clutFilename = stripPrefixDir(clutFName, options.clutsDir);
  186     }
  187 
  188     pp->filmSimulation.strength = m_strength->getValue();
  189 }
  190 
  191 void FilmSimulation::setAdjusterBehavior( bool strength )
  192 {
  193     m_strength->setAddMode( strength );
  194 }
  195 
  196 void FilmSimulation::trimValues( rtengine::procparams::ProcParams* pp )
  197 {
  198     m_strength->trimValue( pp->filmSimulation.strength );
  199 }
  200 
  201 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  202 
  203 
  204 std::unique_ptr<ClutComboBox::ClutModel> ClutComboBox::cm;
  205 std::unique_ptr<ClutComboBox::ClutModel> ClutComboBox::cm2;
  206 
  207 ClutComboBox::ClutComboBox(const Glib::ustring &path):
  208     MyComboBox(),
  209     batchMode(false)
  210 {
  211     if (!cm) {
  212         cm.reset(new ClutModel(path));
  213     }
  214     if (!cm2 && options.multiDisplayMode) {
  215         cm2.reset(new ClutModel(path));
  216     }
  217 
  218     set_model(m_model());
  219 
  220     if (cm->count > 0) {
  221         pack_start(m_columns().label, false);
  222     }
  223 
  224     if (!options.multiDisplayMode) {
  225         signal_map().connect(sigc::mem_fun(*this, &ClutComboBox::updateUnchangedEntry));
  226     }
  227 }
  228 
  229 
  230 inline Glib::RefPtr<Gtk::TreeStore> &ClutComboBox::m_model()
  231 {
  232     if (!batchMode || !options.multiDisplayMode) {
  233         return cm->m_model;
  234     } else {
  235         return cm2->m_model;
  236     }
  237 }
  238 
  239 
  240 inline ClutComboBox::ClutColumns &ClutComboBox::m_columns()
  241 {
  242     if (!batchMode || !options.multiDisplayMode) {
  243         return cm->m_columns;
  244     } else {
  245         return cm2->m_columns;
  246     }
  247 }
  248 
  249 
  250 void ClutComboBox::setBatchMode(bool yes)
  251 {
  252     if (batchMode != yes) {
  253         batchMode = yes;
  254         set_model(m_model());
  255         if (batchMode) {
  256             updateUnchangedEntry();
  257         }
  258     }
  259 }
  260 
  261 
  262 void ClutComboBox::cleanup()
  263 {
  264     cm.reset();
  265     cm2.reset();
  266 }
  267 
  268 
  269 void ClutComboBox::updateUnchangedEntry()
  270 {
  271     auto c = m_model()->children();
  272 
  273     if (batchMode) {
  274         if (c.empty() || c[c.size()-1][m_columns().clutFilename] != "NULL") {
  275             Gtk::TreeModel::Row row = *(m_model()->append());
  276             row[m_columns().label] = M("GENERAL_UNCHANGED");
  277             row[m_columns().clutFilename] = "NULL";
  278         }
  279     } else {
  280         if (c.size() > 0) {
  281             Gtk::TreeModel::Row row = c[c.size()-1];
  282             if (row[m_columns().clutFilename] == "NULL") {
  283                 m_model()->erase(row);
  284             }
  285         }
  286     }
  287 }
  288 
  289 ClutComboBox::ClutColumns::ClutColumns()
  290 {
  291     add( label );
  292     add( clutFilename );
  293 }
  294 
  295 ClutComboBox::ClutModel::ClutModel(const Glib::ustring &path)
  296 {
  297     m_model = Gtk::TreeStore::create (m_columns);
  298     //set_model (m_model);
  299     count = path.empty() ? 0 : parseDir(path);
  300 }
  301 
  302 int ClutComboBox::ClutModel::parseDir(const Glib::ustring& path)
  303 {
  304     if (path.empty() || !Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) {
  305         return 0;
  306     }
  307 
  308     const auto sorted_dir_dirs = [](const Glib::ustring& path) -> std::map<std::string, std::string>
  309         {
  310             std::map<std::string, std::string> res;
  311 
  312             for (const auto& dir : Glib::Dir(path)) {
  313                 const std::string full_path = Glib::build_filename(path, dir);
  314 
  315                 if (Glib::file_test(full_path, Glib::FILE_TEST_IS_DIR)) {
  316                     res.emplace(dir, full_path);
  317                 }
  318             }
  319 
  320             return res;
  321         };
  322 
  323     const auto startedAt = std::chrono::system_clock::now();
  324 
  325     // Build menu of limited directory structure using breadth-first search
  326     using Dirs = std::vector<std::pair<Glib::ustring, Gtk::TreeModel::Row>>;
  327     Dirs dirs;
  328 
  329     {
  330         Dirs currDirs;
  331         Dirs nextDirs;
  332 
  333         currDirs.emplace_back(path, Gtk::TreeModel::Row());
  334 
  335         while (!currDirs.empty()) {
  336             for (auto& dir : currDirs) {
  337                 const auto& path = dir.first;
  338                 const auto& row = dir.second;
  339 
  340                 try {
  341                     for (const auto& entry : sorted_dir_dirs(path)) {
  342                         auto newRow = row ? *m_model->append(row.children()) : *m_model->append();
  343                         newRow[m_columns.label] = entry.first;
  344 
  345                         nextDirs.emplace_back(entry.second, newRow);
  346                     }
  347                 } catch (Glib::Exception&) {}
  348 
  349                 dirs.push_back(std::move(dir));
  350 
  351                 if (!notifySlowParseDir(startedAt)) {
  352                     m_model->clear();
  353                     return 0;
  354                 }
  355             }
  356 
  357             currDirs.clear();
  358             currDirs.swap(nextDirs);
  359         }
  360     }
  361 
  362     // Fill menu structure with CLUT files
  363     std::set<std::string> entries;
  364 
  365     unsigned long fileCount = 0;
  366 
  367     for (const auto& dir : dirs) {
  368         const auto& path = dir.first;
  369         const auto& row = dir.second;
  370 
  371         entries.clear();
  372 
  373         try {
  374             for (const auto& entry : Glib::Dir(path)) {
  375                 const auto entryPath = Glib::build_filename(path, entry);
  376 
  377                 if (!Glib::file_test(entryPath, Glib::FILE_TEST_IS_REGULAR)) {
  378                     continue;
  379                 }
  380 
  381                 entries.insert(entryPath);
  382             }
  383         } catch (Glib::Exception&) {}
  384 
  385         for (const auto& entry : entries) {
  386             Glib::ustring name;
  387             Glib::ustring extension;
  388             Glib::ustring profileName;
  389             HaldCLUT::splitClutFilename (entry, name, extension, profileName, false);
  390 
  391             extension = extension.casefold();
  392             if (extension != "png" && extension != "tif") {
  393                 continue;
  394             }
  395 
  396             auto newRow = row ? *m_model->append(row.children()) : *m_model->append();
  397             newRow[m_columns.label] = name;
  398             newRow[m_columns.clutFilename] = entry;
  399 
  400             ++fileCount;
  401 
  402             if (!notifySlowParseDir(startedAt)) {
  403                 m_model->clear();
  404                 return 0;
  405             }
  406         }
  407     }
  408 
  409     return fileCount;
  410 }
  411 
  412 int ClutComboBox::foundClutsCount() const
  413 {
  414     return cm->count;
  415 }
  416 
  417 Glib::ustring ClutComboBox::getSelectedClut()
  418 {
  419     Glib::ustring result;
  420     Gtk::TreeModel::iterator current = get_active();
  421     Gtk::TreeModel::Row row = *current;
  422 
  423     if ( row ) {
  424         result = row[ m_columns().clutFilename ];
  425     }
  426 
  427     return result;
  428 }
  429 
  430 void ClutComboBox::setSelectedClut( Glib::ustring filename )
  431 {
  432     if ( !filename.empty() ) {
  433         Gtk::TreeIter found = findRowByClutFilename( m_model()->children(), filename );
  434 
  435         if ( found ) {
  436             set_active( found );
  437         } else {
  438             set_active(-1);
  439         }
  440     }
  441 }
  442 
  443 Gtk::TreeIter ClutComboBox::findRowByClutFilename( Gtk::TreeModel::Children childs, Glib::ustring filename )
  444 {
  445     Gtk::TreeIter result = childs.end();
  446 
  447     for( Gtk::TreeModel::Children::iterator it = childs.begin(); !result && it != childs.end(); ++it ) {
  448         Gtk::TreeModel::Row row = *it;
  449 
  450         if ( row[ m_columns().clutFilename ] == filename ) {
  451             result = it;
  452         } else {
  453             result = findRowByClutFilename( it->children(), filename );
  454         }
  455     }
  456 
  457     return result;
  458 }