diff --git a/rtdata/images/curveType-NURBS.png b/rtdata/images/curveType-NURBS.png new file mode 100644 index 000000000..81d78b517 Binary files /dev/null and b/rtdata/images/curveType-NURBS.png differ diff --git a/rtdata/images/curveType-linear.png b/rtdata/images/curveType-linear.png new file mode 100644 index 000000000..3b0ef7946 Binary files /dev/null and b/rtdata/images/curveType-linear.png differ diff --git a/rtdata/images/curveType-parametric.png b/rtdata/images/curveType-parametric.png new file mode 100644 index 000000000..4d2d0a7d3 Binary files /dev/null and b/rtdata/images/curveType-parametric.png differ diff --git a/rtdata/images/curveType-spline.png b/rtdata/images/curveType-spline.png new file mode 100644 index 000000000..794f6142c Binary files /dev/null and b/rtdata/images/curveType-spline.png differ diff --git a/rtdata/images/curveType-unchanged.png b/rtdata/images/curveType-unchanged.png new file mode 100644 index 000000000..e89930a77 Binary files /dev/null and b/rtdata/images/curveType-unchanged.png differ diff --git a/rtdata/languages/English b/rtdata/languages/English index 21d94637c..23596a21d 100644 --- a/rtdata/languages/English +++ b/rtdata/languages/English @@ -10,6 +10,8 @@ !ADJUSTER_RESET_TO_DEFAULT;Reset to default !BATCHQUEUE_AUTOSTART;Auto start !BATCH_PROCESSING;Batch processing +!CURVEEDITOR_CURVE;Curve +!CURVEEDITOR_CURVES;Curves !CURVEEDITOR_CUSTOM;Custom !CURVEEDITOR_DARKS;Darks !CURVEEDITOR_FILEDLGFILTERANY;Any files @@ -230,6 +232,8 @@ !HISTORY_MSG_90;Directional pyramid luminance !HISTORY_MSG_91;Directional pyramid chominance !HISTORY_MSG_92;Directional pyramid gamma +!HISTORY_MSG_93;Contrast by detail levels parameter +!HISTORY_MSG_94;Contrast by detail levels !HISTORY_MSG_9;Highlight Compression !HISTORY_NEWSNAPSHOT;Add !HISTORY_NEWSNAPSHOTAS;As... diff --git a/rtdata/languages/English (UK) b/rtdata/languages/English (UK) index a98b3f047..7db4afff3 100644 --- a/rtdata/languages/English (UK) +++ b/rtdata/languages/English (UK) @@ -39,6 +39,8 @@ TP_HLREC_COLOR;Colour Propagation !ADJUSTER_RESET_TO_DEFAULT;Reset to default !BATCHQUEUE_AUTOSTART;Auto start !BATCH_PROCESSING;Batch processing +!CURVEEDITOR_CURVE;Curve +!CURVEEDITOR_CURVES;Curves !CURVEEDITOR_CUSTOM;Custom !CURVEEDITOR_DARKS;Darks !CURVEEDITOR_FILEDLGFILTERANY;Any files diff --git a/rtdata/languages/English (US) b/rtdata/languages/English (US) index 97c9487c3..616903a98 100644 --- a/rtdata/languages/English (US) +++ b/rtdata/languages/English (US) @@ -10,6 +10,8 @@ !ADJUSTER_RESET_TO_DEFAULT;Reset to default !BATCHQUEUE_AUTOSTART;Auto start !BATCH_PROCESSING;Batch processing +!CURVEEDITOR_CURVE;Curve +!CURVEEDITOR_CURVES;Curves !CURVEEDITOR_CUSTOM;Custom !CURVEEDITOR_DARKS;Darks !CURVEEDITOR_FILEDLGFILTERANY;Any files diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 880cde336..8f5ff5fd9 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -7,6 +7,8 @@ ADJUSTER_RESET_TO_DEFAULT;Réglages par défaut BATCHQUEUE_AUTOSTART;Démarrage auto BATCH_PROCESSING;Traitement par lot +CURVEEDITOR_CURVE;Courbe +CURVEEDITOR_CURVES;Courbes CURVEEDITOR_CUSTOM;Personnalisé CURVEEDITOR_DARKS;Zones sombres CURVEEDITOR_FILEDLGFILTERANY;Tous les fichiers @@ -224,6 +226,8 @@ HISTORY_MSG_8;Compensation d'exposition HISTORY_MSG_90;Réd. de bruit Luminance HISTORY_MSG_91;Réd. de bruit Chominance HISTORY_MSG_92;Réd. de bruit Gamma +HISTORY_MSG_93;Param. de contraste +HISTORY_MSG_94;Contraste par niveau de détail HISTORY_MSG_9;Compression des hautes lumières HISTORY_NEWSNAPSHOT;Ajouter HISTORY_NEWSNAPSHOTAS;Sous... diff --git a/rtdata/languages/default b/rtdata/languages/default index dbb0fbe87..3a65d7e42 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -3,6 +3,8 @@ ADJUSTER_RESET_TO_DEFAULT;Reset to default BATCHQUEUE_AUTOSTART;Auto start BATCH_PROCESSING;Batch processing +CURVEEDITOR_CURVE;Curve +CURVEEDITOR_CURVES;Curves CURVEEDITOR_CUSTOM;Custom CURVEEDITOR_DARKS;Darks CURVEEDITOR_FILEDLGFILTERANY;Any files @@ -223,6 +225,8 @@ HISTORY_MSG_8;Exposure Compensation HISTORY_MSG_90;Directional pyramid luminance HISTORY_MSG_91;Directional pyramid chominance HISTORY_MSG_92;Directional pyramid gamma +HISTORY_MSG_93;Contrast by detail levels parameter +HISTORY_MSG_94;Contrast by detail levels HISTORY_MSG_9;Highlight Compression HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOTAS;As... diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 4cba0b926..06f751323 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -12,7 +12,7 @@ set (BASESOURCEFILES exifpanel.cc sharpening.cc whitebalance.cc vignetting.cc rotate.cc distortion.cc - crophandler.cc curveeditor.cc dirbrowser.cc + crophandler.cc curveeditorgroup.cc curveeditor.cc dirbrowser.cc filecatalog.cc previewloader.cc histogrampanel.cc history.cc imagearea.cc @@ -26,7 +26,8 @@ set (BASESOURCEFILES batchqueue.cc lwbutton.cc lwbuttonset.cc batchqueuebuttonset.cc browserfilter.cc exiffiltersettings.cc profilestore.cc partialpastedlg.cc rawprocess.cc preprocess.cc - equalizer.cc dirpyrequalizer.cc) + equalizer.cc dirpyrequalizer.cc + popupcommon.cc popupbutton.cc popuptogglebutton.cc) if (WIN32) set (EXTRA_SRC windirmonitor.cc myicon.o) diff --git a/rtgui/curveeditor.cc b/rtgui/curveeditor.cc index d156aaf98..6d2b6b11b 100644 --- a/rtgui/curveeditor.cc +++ b/rtgui/curveeditor.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ #include +#include #include #include #include @@ -24,495 +25,96 @@ extern Glib::ustring argv0; -CurveEditor::CurveEditor () : cl(NULL), realized(false), curveTypeIx(Linear), activeParamControl(-1) { +/* + * CurveEditor (CurveEditorGroup* ceGroup, Glib::ustring text) + * + * parameters: + * ceGroup = NULL or the address of the Widget that will receive the CurveTypeToggleButton + * text = (optional) label of the curve, displayed in the CurveTypeToggleButton, next to the image + */ +CurveEditor::CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup) { - Gtk::HBox* tsbox = Gtk::manage (new Gtk::HBox ()); - Gtk::Label* tslab = Gtk::manage (new Gtk::Label (M("CURVEEDITOR_TYPE"))); - curveType = Gtk::manage (new Gtk::ComboBoxText ()); - curve_reset = Gtk::manage (new Gtk::Button ()); - curve_reset->add (*Gtk::manage (new Gtk::Image (argv0+"/images/undo.png"))); - curve_reset->set_relief (Gtk::RELIEF_NONE); - curve_reset->set_border_width (0); - curve_reset->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLINEAR")); + bgHistValid = false; + selected = Linear; - tsbox->pack_start (*tslab, Gtk::PACK_SHRINK, 8); - tsbox->pack_start (*curveType); - tsbox->pack_start (*curve_reset, Gtk::PACK_SHRINK, 0); - - pack_start (*tsbox); + group = ceGroup; + if (group && text.size()) + curveType = Gtk::manage (new PopUpToggleButton(text + ":", true)); + else + curveType = Gtk::manage (new PopUpToggleButton()); + + curveType->set_image_position(Gtk::POS_RIGHT); // Order set in the same order than "enum CurveType". Shouldn't change, for compatibility reason - curveType->append_text (M("CURVEEDITOR_LINEAR")); // 0 Linear - curveType->append_text (M("CURVEEDITOR_CUSTOM")); // 1 Spline - curveType->append_text (M("CURVEEDITOR_PARAMETRIC")); // 2 Parametric - curveType->append_text (M("CURVEEDITOR_NURBS")); // 3 NURBS - curveType->set_active (Linear); + curveType->addEntry(argv0+"/images/curveType-linear.png", M("CURVEEDITOR_LINEAR")); // 0 Linear + curveType->addEntry(argv0+"/images/curveType-spline.png", M("CURVEEDITOR_CUSTOM")); // 1 Spline + curveType->addEntry(argv0+"/images/curveType-parametric.png", M("CURVEEDITOR_PARAMETRIC")); // 2 Parametric + curveType->addEntry(argv0+"/images/curveType-NURBS.png", M("CURVEEDITOR_NURBS")); // 3 NURBS + curveType->setSelected(Linear); + curveType->set_tooltip_text(M("CURVEEDITOR_TYPE")); + // TODO: Does this signal have to be blocked when on curve type change ? + curveType->signal_toggled().connect ( sigc::mem_fun(*this, &CurveEditor::curveTypeToggled) ); + typeconn = curveType->signal_changed().connect (sigc::mem_fun(*this, &CurveEditor::typeSelectionChanged) ); - curve_reset->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::curveResetPressed) ); - - // custom curve - customCurveBox = new Gtk::VBox (); - Gtk::HBox* tmpa = Gtk::manage (new Gtk::HBox ()); - customCurve = Gtk::manage (new MyCurve ()); - //Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); - //af->add (*customCurve); - customCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); - customCurve->setType (Spline); - //customCurve->set_tooltip_text (M("CURVEEDITOR_TOOLTIPMOVESPEED")); - tmpa->pack_start (*customCurve, true, false, 4); - customCurveBox->pack_start (*tmpa, true, true,4); - - Gtk::HBox* custombbox = Gtk::manage (new Gtk::HBox ()); - saveCustom = Gtk::manage (new Gtk::Button ()); - saveCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); - loadCustom = Gtk::manage (new Gtk::Button ()); - loadCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); - - custombbox->pack_end (*saveCustom, Gtk::PACK_EXPAND_WIDGET, 4); - custombbox->pack_end (*loadCustom, Gtk::PACK_EXPAND_WIDGET, 4); - - customCurveBox->pack_end (*custombbox, Gtk::PACK_SHRINK, 2); - customCurveBox->show_all (); - - saveCustom->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::savePressed) ); - loadCustom->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::loadPressed) ); - saveCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); - loadCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); - - // NURBS curve - NURBSCurveBox = new Gtk::VBox (); - Gtk::HBox* tmpb = Gtk::manage (new Gtk::HBox ()); - NURBSCurve = Gtk::manage (new MyCurve ()); - //Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); - //af->add (*customCurve); - NURBSCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); - NURBSCurve->setType (NURBS); - //customCurve->set_tooltip_text (M("CURVEEDITOR_TOOLTIPMOVESPEED")); - tmpb->pack_start (*NURBSCurve, true, false, 4); - NURBSCurveBox->pack_start (*tmpb, true, true,4); - - Gtk::HBox* NURBSbbox = Gtk::manage (new Gtk::HBox ()); - saveNURBS = Gtk::manage (new Gtk::Button ()); - saveNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); - loadNURBS = Gtk::manage (new Gtk::Button ()); - loadNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); - - NURBSbbox->pack_end (*saveNURBS, Gtk::PACK_EXPAND_WIDGET, 4); - NURBSbbox->pack_end (*loadNURBS, Gtk::PACK_EXPAND_WIDGET, 4); - - NURBSCurveBox->pack_end (*NURBSbbox, Gtk::PACK_SHRINK, 2); - NURBSCurveBox->show_all (); - - saveNURBS->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::savePressed) ); - loadNURBS->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::loadPressed) ); - saveNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); - loadNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); - - // parametric curve - paramCurveBox = new Gtk::VBox (); - paramCurve = Gtk::manage (new MyCurve ()); - Gtk::Table* paramctab = Gtk::manage (new Gtk::Table (2,1)); - //Gtk::AspectFrame* afp = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); - //afp->add (*paramCurve); - paramCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); - paramCurve->setType (Parametric); - shcSelector = Gtk::manage (new SHCSelector ()); - shcSelector->set_size_request (GRAPH_SIZE, 20); - - paramctab->attach (*paramCurve, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 4, 4); - paramctab->attach (*shcSelector, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, RADIUS+4, 0); - - Gtk::HBox* tmpc = Gtk::manage (new Gtk::HBox ()); - tmpc->pack_start (*paramctab, true, false); - - paramCurveBox->pack_start (*tmpc, true, true); - - highlights = Gtk::manage (new Adjuster (M("CURVEEDITOR_HIGHLIGHTS"), -100, 100, 1, 0)); - lights = Gtk::manage (new Adjuster (M("CURVEEDITOR_LIGHTS"), -100, 100, 1, 0)); - darks = Gtk::manage (new Adjuster (M("CURVEEDITOR_DARKS"), -100, 100, 1, 0)); - shadows = Gtk::manage (new Adjuster (M("CURVEEDITOR_SHADOWS"), -100, 100, 1, 0)); - - Gtk::EventBox* evhighlights = Gtk::manage (new Gtk::EventBox ()); - Gtk::EventBox* evlights = Gtk::manage (new Gtk::EventBox ()); - Gtk::EventBox* evdarks = Gtk::manage (new Gtk::EventBox ()); - Gtk::EventBox* evshadows = Gtk::manage (new Gtk::EventBox ()); - - evhighlights->add (*highlights); - evlights->add (*lights); - evdarks->add (*darks); - evshadows->add (*shadows); - - paramCurveBox->pack_start (*Gtk::manage (new Gtk::HSeparator ())); - paramCurveBox->pack_start (*evhighlights); - paramCurveBox->pack_start (*evlights); - paramCurveBox->pack_start (*evdarks); - paramCurveBox->pack_start (*evshadows); - paramCurveBox->show_all (); - - customCurveBox->reference (); - paramCurveBox->reference (); - - customCurve->setCurveListener (this); - NURBSCurve->setCurveListener (this); - paramCurve->setCurveListener (this); - shcSelector->setSHCListener (this); - - highlights->setAdjusterListener (this); - lights->setAdjusterListener (this); - darks->setAdjusterListener (this); - shadows->setAdjusterListener (this); - - evhighlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); - evlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); - evdarks->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); - evshadows->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); - typeconn = curveType->signal_changed().connect (sigc::mem_fun(*this, &CurveEditor::typeSelectionChanged) ); - evhighlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterEntered), 4)); - evlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterEntered), 5)); - evdarks->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterEntered), 6)); - evshadows->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterEntered), 7)); - evhighlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterLeft), 4)); - evlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterLeft), 5)); - evdarks->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterLeft), 6)); - evshadows->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterLeft), 7)); - - show_all (); + curveType->show(); } +/* CurveEditor::~CurveEditor () { - delete customCurveBox; - delete paramCurveBox; } +*/ -void CurveEditor::savePressed () { - - Gtk::FileChooserDialog dialog(M("CURVEEDITOR_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE); -// if (options.multiUser) -// dialog.set_current_folder (Options::rtdir + "/" + options.profilePath); -// else -// dialog.set_current_folder (argv0 + "/" + options.profilePath); - - dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_OK); - - Gtk::FileFilter filter_pp; - filter_pp.set_name(M("CURVEEDITOR_FILEDLGFILTERCURVE")); - filter_pp.add_pattern("*.rtc"); - dialog.add_filter(filter_pp); - - Gtk::FileFilter filter_any; - filter_any.set_name(M("CURVEEDITOR_FILEDLGFILTERANY")); - filter_any.add_pattern("*"); - dialog.add_filter(filter_any); - - dialog.set_do_overwrite_confirmation (true); - - int result = dialog.run(); - - if (result==Gtk::RESPONSE_OK) { - - std::string fname = dialog.get_filename(); - - if (getExtension (fname)!="rtc") - fname = fname + ".rtc"; - - if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) { - Glib::ustring msg_ = Glib::ustring("") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + ""; - Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); - int response = msgd.run (); - if (response==Gtk::RESPONSE_NO) - return; - } - - std::ofstream f (fname.c_str()); - std::vector p = customCurve->getPoints (); - - switch (curveType->get_active_row_number()) { - case Spline: // custom - p = customCurve->getPoints (); - break; - case NURBS: // NURBS - p = NURBSCurve->getPoints (); - break; - default: - break; - } - - int ix = 0; - if (p[ix]==(double)(Linear)) - f << "Linear\n"; - else if (p[ix]==(double)(Spline)) - f << "Spline\n"; - else if (p[ix]==(double)(NURBS)) - f << "NURBS\n"; - ix++; - for (unsigned int i=0; i p; - std::string s; - f >> s; - if (s=="Linear") - p.push_back ((double)(Linear)); - else if (s=="Spline") - p.push_back ((double)(Spline)); - else if (s=="NURBS") - p.push_back ((double)(NURBS)); - else return; - double x; - while (f) { - f >> x; - if (f) - p.push_back (x); - } - if (p[0] == (double)(Spline)) { - customCurve->setPoints (p); - customCurve->queue_draw (); - customCurve->notifyListener (); - } - else if (p[0] == (double)(NURBS)) { - NURBSCurve->setPoints (p); - NURBSCurve->queue_draw (); - NURBSCurve->notifyListener (); - } - } - } -} - -void CurveEditor::on_realize () { - - Gtk::VBox::on_realize(); - realized = true; - setCurve (tmpCurve); -} - -void CurveEditor::setCurve (const std::vector& c) { - - tmpCurve = c; - - if (realized && curveType->get_active_row_number()<=Unchanged) { // if it is not realized or "unchanged" is selected, just store the curve (prev line) and do not change gui - - typeconn.block(true); - if (c.size()==0 || c[0]==(double)(Linear)) { - curveType->set_active (Linear); // Change the combo selection - curveTypeIx = Linear; - } - else if (c[0]==(double)(Spline)) { - curveType->set_active (Spline); - curveTypeIx = Spline; - customCurve->setPoints (c); - } - else if (c[0]==(double)(Parametric)) { - curveType->set_active (Parametric); - curveTypeIx = Parametric; - paramCurve->setPoints (c); - shcSelector->setPositions (c[1], c[2], c[3]); - highlights->setValue (c[4]); - lights->setValue (c[5]); - darks->setValue (c[6]); - shadows->setValue (c[7]); - } - else if (c[0]==(double)(NURBS)) { - curveType->set_active (NURBS); - curveTypeIx = NURBS; - NURBSCurve->setPoints (c); - } - removeIfThere (this, customCurveBox, false); - removeIfThere (this, paramCurveBox, false); - removeIfThere (this, NURBSCurveBox, false); - - if (curveType->get_active_row_number()==Spline) - pack_start (*customCurveBox); - else if (curveType->get_active_row_number()==Parametric) - pack_start (*paramCurveBox); - else if (curveType->get_active_row_number()==NURBS) - pack_start (*NURBSCurveBox); - - typeconn.block(false); - } +void CurveEditor::setCurve (const std::vector& p) { + tempCurve = p; + group->setCurveExternal(this, p); } std::vector CurveEditor::getCurve () { + std::vector curve; - if (!realized || curveType->get_active_row_number()==Unchanged) - return tmpCurve; - - // linear - if (curveTypeIx<=Linear) { - std::vector lcurve (1); - lcurve[0] = (double)(Linear); - return lcurve; - } - // parametric - else if (curveTypeIx==Parametric) { - std::vector lcurve (8); - lcurve[0] = (double)(Parametric); - shcSelector->getPositions (lcurve[1], lcurve[2], lcurve[3]); - lcurve[4] = highlights->getValue (); - lcurve[5] = lights->getValue (); - lcurve[6] = darks->getValue (); - lcurve[7] = shadows->getValue (); - return lcurve; - } - // spline (custom) - else if (curveTypeIx==Spline) - return customCurve->getPoints (); - // NURBS (control cage) - else // Default solution, we return the NURBS curve (curveTypeIx==NURBS) - return NURBSCurve->getPoints (); -} - -void CurveEditor::typeSelectionChanged () { - - removeIfThere (this, customCurveBox, false); - removeIfThere (this, paramCurveBox, false); - removeIfThere (this, NURBSCurveBox, false); - - if (curveType->get_active_row_number()==Spline) { - pack_start (*customCurveBox); - } - else if (curveType->get_active_row_number()==Parametric) { - pack_start (*paramCurveBox); - } - else if (curveType->get_active_row_number()==NURBS) { - pack_start (*NURBSCurveBox); - } - - if (curveType->get_active_row_number() < Unchanged) - curveTypeIx = (CurveType)curveType->get_active_row_number(); - - curveChanged (); -} - -void CurveEditor::curveChanged () { - - if (cl) { - if (cl->isMulti()) - cl->curveChanged (this); - else - cl->curveChanged (); - } -} - -void CurveEditor::curveResetPressed () { - switch (curveTypeIx) { - case NURBS : // = Control cage - NURBSCurve->reset (); - break; - case Spline : // = Custom - customCurve->reset (); - break; - case Parametric : - highlights->resetPressed(); - lights->resetPressed(); - darks->resetPressed(); - shadows->resetPressed(); - shcSelector->reset(); - paramCurve->reset (); - break; + switch (selected) { + case (Spline): + return curve = customCurveEd; + case (Parametric): + return curve = paramCurveEd; + case (NURBS): + return curve = NURBSCurveEd; default: - break; + // returning Linear or Unchanged + curve.push_back((double)(selected)); + return curve; } - curveChanged (); } -void CurveEditor::shcChanged () { - - paramCurve->setPoints (getCurve()); - if (cl) { - if (cl->isMulti()) - cl->curveChanged (this); - else - cl->curveChanged (); - } +void CurveEditor::typeSelectionChanged (int n) { + group->typeSelectionChanged(this, n); } -void CurveEditor::adjusterChanged (Adjuster* a, double newval) { - - paramCurve->setPoints (getCurve()); - if (cl) { - if (cl->isMulti()) - cl->curveChanged (this); - else - cl->curveChanged (); - } -} - -bool CurveEditor::adjusterEntered (GdkEventCrossing* ev, int ac) { - - if (ev->detail != GDK_NOTIFY_INFERIOR) { - activeParamControl = ac; - paramCurve->setActiveParam (activeParamControl); - } - return true; -} - -bool CurveEditor::adjusterLeft (GdkEventCrossing* ev, int ac) { - - if (ev->detail != GDK_NOTIFY_INFERIOR) { - activeParamControl = -1; - paramCurve->setActiveParam (activeParamControl); - } - return true; -} - -void CurveEditor::setBatchMode (bool batchMode) { - - curveType->append_text (M("GENERAL_UNCHANGED")); +void CurveEditor::curveTypeToggled() { + group->curveTypeToggled(this); } bool CurveEditor::isUnChanged () { - - return curveType->get_active_row_number()==Unchanged; + return curveType->getSelected()==Unchanged; } void CurveEditor::setUnChanged (bool uc) { - - if (uc) { - typeconn.block(true); - removeIfThere (this, customCurveBox, false); - removeIfThere (this, paramCurveBox, false); - removeIfThere (this, NURBSCurveBox, false); - curveType->set_active (Unchanged); - typeconn.block(false); - } - else { - typeconn.block(true); - curveType->set_active (-1); // hack: if it remains 3 (unchanged), then setcurve does not switch selection in the combo - setCurve (getCurve ()); - typeconn.block(false); - } + group->setUnChanged(uc, this); } +/* + * Update the backgrounds histograms + */ void CurveEditor::updateBackgroundHistogram (unsigned int* hist) { + // Copy the histogram in the curve editor cache + if (hist!=NULL) { + memcpy (histogram, hist, 256*sizeof(unsigned int)); + bgHistValid = true; + } + else + bgHistValid = false; - paramCurve->updateBackgroundHistogram (hist); - customCurve->updateBackgroundHistogram (hist); - NURBSCurve->updateBackgroundHistogram (hist); + // Then call the curve editor group to eventually update the histogram + group->updateBackgroundHistogram (this); } diff --git a/rtgui/curveeditor.h b/rtgui/curveeditor.h index bb9cd3638..fe8944912 100644 --- a/rtgui/curveeditor.h +++ b/rtgui/curveeditor.h @@ -1,85 +1,71 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * 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 . - */ -#ifndef _CURVEEDITOR_ -#define _CURVEEDITOR_ - -#include -#include -#include -#include - -class CurveEditor : public Gtk::VBox, public CurveListener, public SHCListener, public AdjusterListener { - - Gtk::ComboBoxText* curveType; - Gtk::Button* curve_reset; - Gtk::VBox* paramCurveBox; - Gtk::VBox* customCurveBox; - Gtk::VBox* NURBSCurveBox; - - MyCurve* customCurve; - MyCurve* NURBSCurve; - MyCurve* paramCurve; - SHCSelector* shcSelector; - - Adjuster* highlights; - Adjuster* lights; - Adjuster* darks; - Adjuster* shadows; - - Gtk::Button* saveCustom; - Gtk::Button* loadCustom; - Gtk::Button* saveNURBS; - Gtk::Button* loadNURBS; - - CurveListener* cl; - - bool realized; - std::vector tmpCurve; - CurveType curveTypeIx; - - int activeParamControl; - - sigc::connection typeconn; - - public: - - CurveEditor (); - virtual ~CurveEditor (); - void setBatchMode (bool batchMode); - bool isUnChanged (); - void setUnChanged (bool uc); - - void on_realize (); - void setCurveListener (CurveListener* l) { cl = l; } - void savePressed (); - void loadPressed (); - void typeSelectionChanged (); - void setCurve (const std::vector& c); - std::vector getCurve (); - void curveChanged (); - void curveResetPressed (); - void shcChanged (); - void adjusterChanged (Adjuster* a, double newval); - bool adjusterEntered (GdkEventCrossing* ev, int ac); - bool adjusterLeft (GdkEventCrossing* ev, int ac); - void updateBackgroundHistogram (unsigned int* hist); -}; - - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + */ +#ifndef _CURVEEDITOR_ +#define _CURVEEDITOR_ + +#include +#include +#include +#include + +class CurveEditorGroup; + +/* + * This class is an interface between RT and the curve editor group ; it handles the methods + * related to a specific curve. It is created by CurveEditorGroup::addCurve + */ +class CurveEditor { + +private: + + /* + * The curve editor contains only one widget (the curve type button) to receive the signals + * but it's co-handled by the CurveEditorGroup too + */ + + // reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value + CurveType selected; + + PopUpToggleButton* curveType; + unsigned int histogram[256]; // histogram values + bool bgHistValid; + + CurveEditorGroup* group; + std::vector tempCurve; + std::vector customCurveEd; + std::vector paramCurveEd; + std::vector NURBSCurveEd; + sigc::connection typeconn; + +public: + + friend class CurveEditorGroup; + CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup); + //~CurveEditor (); + void typeSelectionChanged (int n); + void curveTypeToggled(); + void setCurve (const std::vector& p); + std::vector getCurve (); + bool isUnChanged (); + void setUnChanged (bool uc); + void updateBackgroundHistogram (unsigned int* hist); +}; + + +#endif diff --git a/rtgui/curveeditorgroup.cc b/rtgui/curveeditorgroup.cc new file mode 100644 index 000000000..e85debb7f --- /dev/null +++ b/rtgui/curveeditorgroup.cc @@ -0,0 +1,733 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ +#include +#include + +extern Glib::ustring argv0; + +CurveEditorGroup::CurveEditorGroup (Glib::ustring groupLabel) : cl(NULL), activeParamControl(-1) { + curveEditors.clear(); + displayedCurve = 0; + numberOfPackedCurve = 0; + + // We set the label to the one provided as parameter, even if it's an empty string + curveGroupLabel = Gtk::manage (new Gtk::Label (groupLabel+":", Gtk::ALIGN_LEFT)); + + // custom curve + customCurveBox = new Gtk::HBox (); + Gtk::HBox* tmpa = Gtk::manage (new Gtk::HBox ()); + customCurve = Gtk::manage (new MyCurve ()); + //Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); + //af->add (*customCurve); + customCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); + customCurve->setType (Spline); + //customCurve->set_tooltip_text (M("CURVEEDITOR_TOOLTIPMOVESPEED")); + tmpa->pack_start (*customCurve, true, false, 4); + customCurveBox->pack_start (*tmpa, true, true,4); + + Gtk::VBox* custombbox = Gtk::manage (new Gtk::VBox ()); + saveCustom = Gtk::manage (new Gtk::Button ()); + saveCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); + loadCustom = Gtk::manage (new Gtk::Button ()); + loadCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); + + custombbox->pack_end (*saveCustom, Gtk::PACK_SHRINK, 4); + custombbox->pack_end (*loadCustom, Gtk::PACK_SHRINK, 4); + + customCurveBox->pack_end (*custombbox, Gtk::PACK_SHRINK, 0); + customCurveBox->show_all (); + + saveCustom->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::savePressed) ); + loadCustom->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::loadPressed) ); + saveCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); + loadCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); + + // NURBS curve + NURBSCurveBox = new Gtk::HBox (); + Gtk::HBox* tmpb = Gtk::manage (new Gtk::HBox ()); + NURBSCurve = Gtk::manage (new MyCurve ()); + //Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); + //af->add (*customCurve); + NURBSCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); + NURBSCurve->setType (NURBS); + //customCurve->set_tooltip_text (M("CURVEEDITOR_TOOLTIPMOVESPEED")); + tmpb->pack_start (*NURBSCurve, true, false, 4); + NURBSCurveBox->pack_start (*tmpb, true, true,4); + + Gtk::VBox* NURBSbbox = Gtk::manage (new Gtk::VBox ()); + saveNURBS = Gtk::manage (new Gtk::Button ()); + saveNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); + loadNURBS = Gtk::manage (new Gtk::Button ()); + loadNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); + + NURBSbbox->pack_end (*saveNURBS, Gtk::PACK_SHRINK, 4); + NURBSbbox->pack_end (*loadNURBS, Gtk::PACK_SHRINK, 4); + + NURBSCurveBox->pack_end (*NURBSbbox, Gtk::PACK_SHRINK, 0); + NURBSCurveBox->show_all (); + + saveNURBS->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::savePressed) ); + loadNURBS->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::loadPressed) ); + saveNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); + loadNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); + + // parametric curve + paramCurveBox = new Gtk::VBox (); + paramCurve = Gtk::manage (new MyCurve ()); + Gtk::Table* paramctab = Gtk::manage (new Gtk::Table (2,1)); + //Gtk::AspectFrame* afp = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); + //afp->add (*paramCurve); + paramCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); + paramCurve->setType (Parametric); + shcSelector = Gtk::manage (new SHCSelector ()); + shcSelector->set_size_request (GRAPH_SIZE, 20); + + paramctab->attach (*paramCurve, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 4, 4); + paramctab->attach (*shcSelector, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, RADIUS+4, 0); + + Gtk::HBox* tmpc = Gtk::manage (new Gtk::HBox ()); + tmpc->pack_start (*paramctab, true, false); + + paramCurveBox->pack_start (*tmpc, true, true); + + highlights = Gtk::manage (new Adjuster (M("CURVEEDITOR_HIGHLIGHTS"), -100, 100, 1, 0)); + lights = Gtk::manage (new Adjuster (M("CURVEEDITOR_LIGHTS"), -100, 100, 1, 0)); + darks = Gtk::manage (new Adjuster (M("CURVEEDITOR_DARKS"), -100, 100, 1, 0)); + shadows = Gtk::manage (new Adjuster (M("CURVEEDITOR_SHADOWS"), -100, 100, 1, 0)); + + Gtk::EventBox* evhighlights = Gtk::manage (new Gtk::EventBox ()); + Gtk::EventBox* evlights = Gtk::manage (new Gtk::EventBox ()); + Gtk::EventBox* evdarks = Gtk::manage (new Gtk::EventBox ()); + Gtk::EventBox* evshadows = Gtk::manage (new Gtk::EventBox ()); + + evhighlights->add (*highlights); + evlights->add (*lights); + evdarks->add (*darks); + evshadows->add (*shadows); + + paramCurveBox->pack_start (*Gtk::manage (new Gtk::HSeparator ())); + paramCurveBox->pack_start (*evhighlights); + paramCurveBox->pack_start (*evlights); + paramCurveBox->pack_start (*evdarks); + paramCurveBox->pack_start (*evshadows); + paramCurveBox->show_all (); + + customCurveBox->reference (); + paramCurveBox->reference (); + + customCurve->setCurveListener (this); + NURBSCurve->setCurveListener (this); + paramCurve->setCurveListener (this); + shcSelector->setSHCListener (this); + + highlights->setAdjusterListener (this); + lights->setAdjusterListener (this); + darks->setAdjusterListener (this); + shadows->setAdjusterListener (this); + + evhighlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evdarks->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evshadows->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evhighlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterEntered), 4)); + evlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterEntered), 5)); + evdarks->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterEntered), 6)); + evshadows->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterEntered), 7)); + evhighlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterLeft), 4)); + evlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterLeft), 5)); + evdarks->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterLeft), 6)); + evshadows->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterLeft), 7)); + +} + +CurveEditorGroup::~CurveEditorGroup() { + for (std::vector::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i) + { + delete *i; + } + delete customCurveBox; + delete paramCurveBox; + delete NURBSCurveBox; +} + +void CurveEditorGroup::hideCurrentCurve() { + // Setting the curve type to 'Unchanged' hide the CurveEditor + if (displayedCurve) + displayedCurve->curveType->set_active(false); +} + +/* + * Add a new curve to the curves list + */ +CurveEditor* CurveEditorGroup::addCurve(Glib::ustring curveLabel) { + CurveEditor* newCE = new CurveEditor(curveLabel, this); + + // Initialization of the new curve + storeCurveValues(newCE, getCurveFromGUI(Spline)); + storeCurveValues(newCE, getCurveFromGUI(Parametric)); + storeCurveValues(newCE, getCurveFromGUI(NURBS)); + + // We add it to the curve editor list + curveEditors.push_back(newCE); + return newCE; +} + +/* + * Use this method to start a new line of button + */ +void CurveEditorGroup::newLine() { + Gtk::HBox* headerBox; + + if (curveEditors.size() > numberOfPackedCurve) { + headerBox = Gtk::manage (new Gtk::HBox ()); + + if (!numberOfPackedCurve) { + headerBox->pack_start(*curveGroupLabel, Gtk::PACK_SHRINK, 2); + + curve_reset = Gtk::manage (new Gtk::Button ()); + curve_reset->add (*Gtk::manage (new Gtk::Image (argv0+"/images/undo.png"))); + curve_reset->set_relief (Gtk::RELIEF_NONE); + curve_reset->set_border_width (0); + curve_reset->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLINEAR")); + curve_reset->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::curveResetPressed) ); + + headerBox->pack_end (*curve_reset, Gtk::PACK_SHRINK, 0); + curve_reset->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::curveResetPressed) ); + } + + int j = numberOfPackedCurve; + for (int i = (int)(curveEditors.size())-1; i >= j; i--) + { + headerBox->pack_end (*curveEditors[i]->curveType, Gtk::PACK_EXPAND_WIDGET, 2); + numberOfPackedCurve++; + } + + pack_start (*headerBox, Gtk::PACK_SHRINK, 2); + } + + +} + +/* + * Create all the widgets now that the curve list is complete + * This method should handle all curve number correctly, i.e. eventually display the curve type buttons + * in a grid (or table) + */ +void CurveEditorGroup::curveListComplete() { + newLine(); + + // We check the length of the label ; if it contains only one char (':'), we set it to the right default string + if (curveGroupLabel->get_label().size()==1) + curveGroupLabel->set_label(M(curveEditors.size() > 1 ? "CURVEEDITOR_CURVES" : "CURVEEDITOR_CURVE") + ":"); + + if (curveEditors.size() > 1) + cl->setMulti(true); +} + +/* + * Callback method used when a curve type button has changed ; + * it will activate the button, and so emit 'signal_toggled' (-> curveTypeToggled here under) + */ +void CurveEditorGroup::typeSelectionChanged (CurveEditor* ce, int n) { + // Same type : do nothing + if (ce==displayedCurve && (CurveType)n==ce->selected) + return; + + if ((CurveType)(n)selected = (CurveType)n; + + // The user selected a new type from a toggled off button + if (ce!=displayedCurve) + // We toggle off the other curve: it will emit the toggle off signal + hideCurrentCurve(); + + // If the button was not pressed before + if (!ce->curveType->get_active()) { + storeDisplayedCurve(); + // We set it pressed : it will emit the toggle on signal and update the GUI + ce->curveType->set_active( n>Linear && nisMulti()) + cl->curveChanged (ce); + else + cl->curveChanged (); + } + } + else + curveChanged (); + } + else { + // The button is already pressed so we switch the GUI ourselves + switchGUI(); + curveChanged (); + } +} + +/* + * Callback method used when a button has been toggled on/off + * It then hide any other displayed curve and display it's curve + */ +void CurveEditorGroup::curveTypeToggled(CurveEditor* ce) { + bool curveRestored = false; + + // Looking for the button state + if (ce->curveType->get_active()) { + // The button is now pressed, so we have to first hide all other CurveEditor + hideCurrentCurve(); + + displayedCurve = ce; + + if (ce->curveType->getSelected()==Unchanged) { + curveRestored = true; + ce->curveType->setSelected(ce->selected); + } + + // then show this CurveEditor + int ct = ce->curveType->getSelected(); + if (ct < Unchanged) + restoreDisplayedHistogram(); + } + else { + // The button is now released, so we have to hide this CurveEditor + displayedCurve = 0; + } + switchGUI(); + + if (curveRestored) + curveChanged (); + +} + +/* + * Switch the editor widgets to the currently edited curve + */ +void CurveEditorGroup::switchGUI() { + + removeEditor(); + + if (displayedCurve) { + + // Initializing GUI values + repacking the appropriated widget + //displayedCurve->typeconn.block(true); + + switch((CurveType)(displayedCurve->curveType->getSelected())) { + case (Spline): + customCurve->setPoints (displayedCurve->customCurveEd); + pack_start (*customCurveBox); + break; + case (Parametric): + paramCurve->setPoints (displayedCurve->paramCurveEd); + shcSelector->setPositions ( + displayedCurve->paramCurveEd.at(1), + displayedCurve->paramCurveEd.at(2), + displayedCurve->paramCurveEd.at(3) + ); + highlights->setValue (displayedCurve->paramCurveEd.at(4)); + lights->setValue (displayedCurve->paramCurveEd.at(5)); + darks->setValue (displayedCurve->paramCurveEd.at(6)); + shadows->setValue (displayedCurve->paramCurveEd.at(7)); + pack_start (*paramCurveBox); + break; + case (NURBS): + NURBSCurve->setPoints (displayedCurve->NURBSCurveEd); + pack_start (*NURBSCurveBox); + break; + default: // (Linear, Unchanged) + // ... do nothing + break; + } + + //displayedCurve->typeconn.block(false); + } +} + +void CurveEditorGroup::savePressed () { + + Gtk::FileChooserDialog dialog(M("CURVEEDITOR_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE); +// if (options.multiUser) +// dialog.set_current_folder (Options::rtdir + "/" + options.profilePath); +// else +// dialog.set_current_folder (argv0 + "/" + options.profilePath); + + dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_OK); + + Gtk::FileFilter filter_pp; + filter_pp.set_name(M("CURVEEDITOR_FILEDLGFILTERCURVE")); + filter_pp.add_pattern("*.rtc"); + dialog.add_filter(filter_pp); + + Gtk::FileFilter filter_any; + filter_any.set_name(M("CURVEEDITOR_FILEDLGFILTERANY")); + filter_any.add_pattern("*"); + dialog.add_filter(filter_any); + + dialog.set_do_overwrite_confirmation (true); + + int result = dialog.run(); + + if (result==Gtk::RESPONSE_OK) { + + std::string fname = dialog.get_filename(); + + if (getExtension (fname)!="rtc") + fname = fname + ".rtc"; + + if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) { + Glib::ustring msg_ = Glib::ustring("") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + ""; + Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); + int response = msgd.run (); + if (response==Gtk::RESPONSE_NO) + return; + } + + std::ofstream f (fname.c_str()); + std::vector p = customCurve->getPoints (); + + switch (displayedCurve->selected) { + case Spline: // custom + p = customCurve->getPoints (); + break; + case NURBS: // NURBS + p = NURBSCurve->getPoints (); + break; + default: + break; + } + + int ix = 0; + if (p[ix]==(double)(Linear)) + f << "Linear\n"; + else if (p[ix]==(double)(Spline)) + f << "Spline\n"; + else if (p[ix]==(double)(NURBS)) + f << "NURBS\n"; + ix++; + for (unsigned int i=0; i p; + std::string s; + f >> s; + if (s=="Linear") + p.push_back ((double)(Linear)); + else if (s=="Spline") + p.push_back ((double)(Spline)); + else if (s=="NURBS") + p.push_back ((double)(NURBS)); + else return; + double x; + while (f) { + f >> x; + if (f) + p.push_back (x); + } + if (p[0] == (double)(Spline)) { + customCurve->setPoints (p); + customCurve->queue_draw (); + customCurve->notifyListener (); + } + else if (p[0] == (double)(NURBS)) { + NURBSCurve->setPoints (p); + NURBSCurve->queue_draw (); + NURBSCurve->notifyListener (); + } + } + } +} + +/* + * Store the curves of the currently displayed type from the widgets to the CurveEditor object + */ +void CurveEditorGroup::storeDisplayedCurve() { + if (displayedCurve) { + switch (displayedCurve->selected) { + case (Spline): + storeCurveValues(displayedCurve, getCurveFromGUI(Spline)); + break; + case (Parametric): + storeCurveValues(displayedCurve, getCurveFromGUI(Parametric)); + break; + case (NURBS): + storeCurveValues(displayedCurve, getCurveFromGUI(NURBS)); + break; + default: + break; + } + } +} + +/* + * Restore the histogram to all types from the CurveEditor object to the widgets + */ +void CurveEditorGroup::restoreDisplayedHistogram() { + if (displayedCurve) { + paramCurve->updateBackgroundHistogram (displayedCurve->bgHistValid ? displayedCurve->histogram : NULL); + customCurve->updateBackgroundHistogram (displayedCurve->bgHistValid ? displayedCurve->histogram : NULL); + NURBSCurve->updateBackgroundHistogram (displayedCurve->bgHistValid ? displayedCurve->histogram : NULL); + } + +} + +void CurveEditorGroup::storeCurveValues (CurveEditor* ce, const std::vector& p) { + if (p.size()) { + CurveType t = (CurveType)p[0]; + for (int i=0; i<(int)p.size(); i++) + + switch (t) { + case (Spline): + ce->customCurveEd = p; + break; + case (Parametric): + ce->paramCurveEd = p; + break; + case (NURBS): + ce->NURBSCurveEd = p; + break; + default: + break; + } + } +} + +/* + * Update the GUI if the given curveEditor is currently displayed + */ +void CurveEditorGroup::updateGUI (CurveEditor* ce) { + if (!ce) { + return; + } + + // we update the curve type button to the corresponding curve type, only if it is not currently set to 'Unchanged' + if (ce->curveType->getSelected()curveType->setSelected(ce->selected); + + // if not displayed or "unchanged" is selected, do not change gui + if (ce==displayedCurve && ce->curveType->getSelected()& c) { + if (c.size()) { + storeCurveValues(ce, c); // The new curve is saved in the CurveEditor + ce->selected = (CurveType)(c[0]); // We set the selected curve type in the CurveEditor to the one of the specified curve + } + updateGUI(ce); // And we update the GUI if necessary +} + +/* + * Called to update the parametric curve graph with new slider values + */ +const std::vector CurveEditorGroup::getCurveFromGUI (CurveType type) { + switch (type) { + case (Parametric): { + std::vector lcurve (8); + lcurve[0] = (double)(Parametric); + shcSelector->getPositions (lcurve[1], lcurve[2], lcurve[3]); + lcurve[4] = highlights->getValue (); + lcurve[5] = lights->getValue (); + lcurve[6] = darks->getValue (); + lcurve[7] = shadows->getValue (); + return lcurve; + } + case (Spline): + return customCurve->getPoints (); + case (NURBS): + return NURBSCurve->getPoints (); + default: { + // linear and other solutions + std::vector lcurve (1); + lcurve[0] = (double)(Linear); + return lcurve; + } + } +} + +/* + * Unlink the tree editor widgets from their parent box to hide them + */ +void CurveEditorGroup::removeEditor () { + removeIfThere (this, customCurveBox, false); + removeIfThere (this, paramCurveBox, false); + removeIfThere (this, NURBSCurveBox, false); +} + +/* + * Listener called when the user has modified the curve + */ +void CurveEditorGroup::curveChanged () { + + storeDisplayedCurve(); + if (cl) { + if (cl->isMulti()) + cl->curveChanged (displayedCurve); + else + cl->curveChanged (); + } +} + +/* + * Listener + */ +void CurveEditorGroup::shcChanged () { + + paramCurve->setPoints (getCurveFromGUI(Parametric)); + storeDisplayedCurve(); + if (cl->isMulti()) + cl->curveChanged (displayedCurve); + else + cl->curveChanged (); +} + +/* + * Listener + */ +void CurveEditorGroup::adjusterChanged (Adjuster* a, double newval) { + + paramCurve->setPoints (getCurveFromGUI(Parametric)); + storeDisplayedCurve(); + if (cl->isMulti()) + cl->curveChanged (displayedCurve); + else + cl->curveChanged (); +} + +/* + * Listener called when the mouse is over a parametric curve's slider + */ +bool CurveEditorGroup::adjusterEntered (GdkEventCrossing* ev, int ac) { + + if (ev->detail != GDK_NOTIFY_INFERIOR) { + activeParamControl = ac; + paramCurve->setActiveParam (activeParamControl); + } + return true; +} + +/* + * Listener called when the mouse left the parametric curve's slider + */ +bool CurveEditorGroup::adjusterLeft (GdkEventCrossing* ev, int ac) { + + if (ev->detail != GDK_NOTIFY_INFERIOR) { + activeParamControl = -1; + paramCurve->setActiveParam (activeParamControl); + } + return true; +} + +/* + * Call back method when the reset button is pressed : + * reset the currently toggled on curve editor + */ +void CurveEditorGroup::curveResetPressed() { + if (displayedCurve) { + switch (displayedCurve->selected) { + case (NURBS) : // = Control cage + NURBSCurve->reset (); + curveChanged (); + break; + case (Spline) : // = Custom + customCurve->reset (); + curveChanged (); + break; + case (Parametric) : + highlights->resetPressed(); + lights->resetPressed(); + darks->resetPressed(); + shadows->resetPressed(); + shcSelector->reset(); + paramCurve->reset (); + curveChanged (); + break; + default: + break; + } + } +} + +void CurveEditorGroup::setBatchMode (bool batchMode) { + for (std::vector::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i) { + (*i)->curveType->addEntry(argv0+"/images/curveType-unchanged.png", M("GENERAL_UNCHANGED")); + (*i)->curveType->show(); + } +} + +void CurveEditorGroup::setUnChanged (bool uc, CurveEditor* ce) { + if (uc) { + // the user selected several thumbnails, so we hide the editors and set the curveEditor selection to 'Unchanged' + //ce->typeconn.block(true); + // we hide the editor widgets + hideCurrentCurve(); + // the curve type selected option is set to unchanged + ce->curveType->setSelected(Unchanged); + //ce->typeconn.block(false); + } + else { + // we want it to use back the 'CurveEditor::setCurve' memorized in CurveEditor::tempCurve + //ce->typeconn.block(true); + // we switch back the curve type selected option to the one of the used curve + ce->curveType->setSelected(ce->selected); + updateGUI (ce); + //ce->typeconn.block(false); + } +} + +void CurveEditorGroup::updateBackgroundHistogram (CurveEditor* ce) { + if (ce==displayedCurve) { + paramCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL); + customCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL); + NURBSCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL); + printf(" - fait! (ce==displayedCurve)"); + } +} diff --git a/rtgui/curveeditorgroup.h b/rtgui/curveeditorgroup.h new file mode 100644 index 000000000..19a361932 --- /dev/null +++ b/rtgui/curveeditorgroup.h @@ -0,0 +1,108 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + */ +#ifndef _CURVEEDITORGROUP_ +#define _CURVEEDITORGROUP_ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This class handle the curve widgets, shared between any number curve + * - to add a curve to the list, use the 'addCurve' method + * - to start a new line of curve button, use the 'newLine' method + * - if you add more than one curve, you must add a "CurveEditor* ce" parameter to your listener + */ +class CurveEditorGroup : public Gtk::VBox, public CurveListener, public SHCListener, public AdjusterListener { + +private: + Gtk::Label* curveGroupLabel; + + Gtk::Button* curve_reset; + Gtk::HBox* customCurveBox; + Gtk::VBox* paramCurveBox; + Gtk::HBox* NURBSCurveBox; + + MyCurve* customCurve; + MyCurve* paramCurve; + MyCurve* NURBSCurve; + + SHCSelector* shcSelector; + Adjuster* highlights; + Adjuster* lights; + Adjuster* darks; + Adjuster* shadows; + + Gtk::Button* saveCustom; + Gtk::Button* loadCustom; + Gtk::Button* saveNURBS; + Gtk::Button* loadNURBS; + + CurveListener* cl; + + CurveType curveTypeIx; + unsigned int numberOfPackedCurve; + + std::vector curveEditors; + CurveEditor* displayedCurve; + + int activeParamControl; + + void curveResetPressed (); + void curveTypeToggled (); + void typeSelectionChanged (CurveEditor* ce, int n); + void curveTypeToggled (CurveEditor* ce); + void savePressed (); + void loadPressed (); + void hideCurrentCurve (); + void setUnChanged (bool uc, CurveEditor* ce); + void storeDisplayedCurve (); + void restoreDisplayedHistogram(); + void storeCurveValues (CurveEditor* ce, const std::vector& p); + void typeSelectionChanged (int n); + void switchGUI(); + void updateGUI (CurveEditor* ce); + void removeEditor (); + void curveChanged (); + void shcChanged (); + void adjusterChanged (Adjuster* a, double newval); + bool adjusterEntered (GdkEventCrossing* ev, int ac); + bool adjusterLeft (GdkEventCrossing* ev, int ac); + const std::vector getCurveFromGUI (CurveType type); + void updateBackgroundHistogram (CurveEditor* ce); + +public: + friend class CurveEditor; + CurveEditorGroup(Glib::ustring groupLabel = ""); + ~CurveEditorGroup(); + CurveEditor* addCurve(Glib::ustring curveLabel = ""); + void newLine(); + void curveListComplete(); + void setBatchMode (bool batchMode); + void setCurveExternal (CurveEditor* ce, const std::vector& c); + //void on_realize (); + void setCurveListener (CurveListener* l) { cl = l; } +}; + +#endif diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc index e8a38f6a3..be30e66df 100644 --- a/rtgui/labcurve.cc +++ b/rtgui/labcurve.cc @@ -23,28 +23,6 @@ using namespace rtengine; using namespace rtengine::procparams; LCurve::LCurve () : ToolPanel(), brAdd(false), contrAdd(false), satAdd(false) { - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -/* - Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ()); - hb->set_border_width (4); - hb->show (); - Gtk::Label* labchan = Gtk::manage (new Gtk::Label (M("TP_LABCURVE_CHANNEL")+":")); - labchan->show (); - channel = Gtk::manage (new Gtk::ComboBoxText ()); - channel->append_text (M("TP_LCURVE")); - channel->append_text (M("TP_ACURVE")); - channel->append_text (M("TP_BCURVE")); - channel->show (); - hb->pack_start(*labchan, Gtk::PACK_SHRINK, 4); - hb->pack_start(*channel); - pack_start (*hb); -*/ - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - - Gtk::HBox* abox = Gtk::manage (new Gtk::HBox ()); - abox->set_border_width (2); brightness = Gtk::manage (new Adjuster (M("TP_LABCURVE_BRIGHTNESS"), -100, 100, 0.01, 0)); contrast = Gtk::manage (new Adjuster (M("TP_LABCURVE_CONTRAST"), -100, 100, 1, 0)); @@ -55,7 +33,7 @@ LCurve::LCurve () : ToolPanel(), brAdd(false), contrAdd(false), satAdd(false) { pack_start (*contrast); contrast->show (); - + pack_start (*saturation); saturation->show (); @@ -63,25 +41,19 @@ LCurve::LCurve () : ToolPanel(), brAdd(false), contrAdd(false), satAdd(false) { hsep3->show (); pack_start (*hsep3); - lshape = Gtk::manage (new CurveEditor ()); - lshape->show (); - lshape->setCurveListener (this); - CurveListener::setMulti(true); - - ashape = Gtk::manage (new CurveEditor ()); - ashape->show (); - ashape->setCurveListener (this); - CurveListener::setMulti(true); - - bshape = Gtk::manage (new CurveEditor ()); - bshape->show (); - bshape->setCurveListener (this); - CurveListener::setMulti(true); + curveEditorG = new CurveEditorGroup (); + curveEditorG->setCurveListener (this); - pack_start (*lshape, Gtk::PACK_SHRINK, 4); - pack_start (*ashape, Gtk::PACK_SHRINK, 4); - pack_start (*bshape, Gtk::PACK_SHRINK, 4); + lshape = curveEditorG->addCurve("L"); + ashape = curveEditorG->addCurve("a"); + bshape = curveEditorG->addCurve("b"); + // This will add the reset button at the end of the curveType buttons + curveEditorG->curveListComplete(); + + pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4); + + //curveEditorG->show(); brightness->setAdjusterListener (this); contrast->setAdjusterListener (this); @@ -92,6 +64,10 @@ LCurve::LCurve () : ToolPanel(), brAdd(false), contrAdd(false), satAdd(false) { } +LCurve::~LCurve () { + delete curveEditorG; +} + void LCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { disableListener (); @@ -159,6 +135,12 @@ void LCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pedit } } +/* + * Curve listener + * + * If more than one curve has been added, the curve listener is automatically + * set to 'multi=true', and send a pointer of the modified curve in a parameter + */ void LCurve::curveChanged (CurveEditor* ce) { if (listener) { @@ -217,9 +199,7 @@ void LCurve::setBatchMode (bool batchMode) { contrast->showEditedCB (); saturation->showEditedCB (); - lshape->setBatchMode (batchMode); - ashape->setBatchMode (batchMode); - bshape->setBatchMode (batchMode); + curveEditorG->setBatchMode (batchMode); } void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd) { diff --git a/rtgui/labcurve.h b/rtgui/labcurve.h index 14dc531f2..ce404f959 100644 --- a/rtgui/labcurve.h +++ b/rtgui/labcurve.h @@ -30,6 +30,7 @@ class LCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, publ protected: Gtk::ComboBoxText* channel; + CurveEditorGroup* curveEditorG; Adjuster* brightness; Adjuster* contrast; Adjuster* saturation; @@ -42,6 +43,7 @@ class LCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, publ public: LCurve (); + ~LCurve (); void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); diff --git a/rtgui/mycurve.cc b/rtgui/mycurve.cc index 4430fabba..6805a9230 100644 --- a/rtgui/mycurve.cc +++ b/rtgui/mycurve.cc @@ -36,10 +36,10 @@ MyCurve::MyCurve () : listener(NULL), activeParam(-1), bghistvalid(false) { add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK); signal_event().connect( sigc::mem_fun(*this, &MyCurve::handleEvents) ); - curve.x.push_back(0); - curve.y.push_back(0); - curve.x.push_back(1); - curve.y.push_back(1); + curve.x.push_back(0.); + curve.y.push_back(0.); + curve.x.push_back(1.); + curve.y.push_back(1.); curve.type = Spline; mcih = new MyCurveIdleHelper; @@ -54,8 +54,8 @@ MyCurve::~MyCurve () { mcih->destroyed = true; else delete mcih; - curve.x.empty(); - curve.y.empty(); + //curve.x.clear(); + //curve.y.clear(); } std::vector MyCurve::get_vector (int veclen) { @@ -563,12 +563,12 @@ void MyCurve::findClosestPoint() { } std::vector MyCurve::getPoints () { - std::vector result; if (curve.type==Parametric) { result.push_back ((double)(Parametric)); - for (int i=0; i<(int)curve.x.size(); i++) + for (int i=0; i<(int)curve.x.size(); i++) { result.push_back (curve.x[i]); + } } else { // the first value gives the type of the curve @@ -579,17 +579,17 @@ std::vector MyCurve::getPoints () { else if (curve.type==NURBS) result.push_back ((double)(NURBS)); // then we push all the points coordinate - for (int i=0; i<(int)curve.x.size(); i++) + for (int i=0; i<(int)curve.x.size(); i++) { if (curve.x[i]>=0) { result.push_back (curve.x[i]); result.push_back (curve.y[i]); } + } } return result; } void MyCurve::setPoints (const std::vector& p) { - int ix = 0; CurveType t = (CurveType)p[ix++]; curve.type = t; diff --git a/rtgui/options.cc b/rtgui/options.cc index 23c9aa8e9..fbb4065e6 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -105,7 +105,7 @@ void Options::setDefaults () { editorToSendTo = 1; liveThumbnails = true; tpOpen.clear (); - crvOpen.clear (); + //crvOpen.clear (); parseExtensions.clear (); parseExtensionsEnabled.clear (); renameUseTemplates = false; @@ -266,7 +266,7 @@ if (keyFile.has_group ("GUI")) { if (keyFile.has_key ("GUI", "FrameColor")) bgcolor = keyFile.get_integer ("GUI", "FrameColor"); if (keyFile.has_key ("GUI", "ProcessingQueueEnbled"))procQueueEnabled = keyFile.get_boolean ("GUI", "ProcessingQueueEnbled"); if (keyFile.has_key ("GUI", "ToolPanelsExpanded")) tpOpen = keyFile.get_integer_list ("GUI", "ToolPanelsExpanded"); - if (keyFile.has_key ("GUI", "CurvePanelsExpanded")) crvOpen = keyFile.get_integer_list ("GUI", "CurvePanelsExpanded"); + //if (keyFile.has_key ("GUI", "CurvePanelsExpanded")) crvOpen = keyFile.get_integer_list ("GUI", "CurvePanelsExpanded"); } @@ -395,8 +395,8 @@ int Options::saveToFile (Glib::ustring fname) { keyFile.set_boolean ("GUI", "ProcessingQueueEnbled", procQueueEnabled); Glib::ArrayHandle tpopen = tpOpen; keyFile.set_integer_list ("GUI", "ToolPanelsExpanded", tpopen); - Glib::ArrayHandle crvopen = crvOpen; - keyFile.set_integer_list ("GUI", "CurvePanelsExpanded", crvopen); + //Glib::ArrayHandle crvopen = crvOpen; + //keyFile.set_integer_list ("GUI", "CurvePanelsExpanded", crvopen); keyFile.set_integer ("Crop Settings", "DPI", cropDPI); diff --git a/rtgui/options.h b/rtgui/options.h index c56475948..da848cd50 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -116,7 +116,7 @@ class Options { std::vector parseExtensions; std::vector parseExtensionsEnabled; std::vector tpOpen; - std::vector crvOpen; + //std::vector crvOpen; std::vector baBehav; rtengine::Settings rtSettings; diff --git a/rtgui/popupbutton.cc b/rtgui/popupbutton.cc new file mode 100644 index 000000000..bc201ce77 --- /dev/null +++ b/rtgui/popupbutton.cc @@ -0,0 +1,41 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ + +#include + +/* + * PopUpButton::PopUpButton (const Glib::ustring& label, bool imgRight) + * + * Creates a button with a contextual menu where you can select an item that the button content will reflect + * + * Parameters: + * label = label displayed in the button + * imRight = 0: the image is displayed at the left of the label (default) + * 1: the image is displayed at the right of the label + */ +PopUpButton::PopUpButton (const Glib::ustring& label, bool imgRight) : Gtk::Button(), PopUpCommon(this, label, imgRight) { } + +void PopUpButton::show() { + PopUpCommon::show(); +} +void PopUpButton::set_tooltip_text (const Glib::ustring &text) { + PopUpCommon::set_tooltip_text (text); +} diff --git a/rtgui/popupbutton.h b/rtgui/popupbutton.h new file mode 100644 index 000000000..3cf981a16 --- /dev/null +++ b/rtgui/popupbutton.h @@ -0,0 +1,35 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ +#ifndef _POPUPBUTTON_ +#define _POPUPBUTTON_ + +#include +#include + +class PopUpButton : public Gtk::Button, public PopUpCommon { + +public: + PopUpButton (const Glib::ustring& label = "", bool imgRight=false); + void show (); + void set_tooltip_text (const Glib::ustring &text); +}; + +#endif diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc new file mode 100644 index 000000000..31e8ce674 --- /dev/null +++ b/rtgui/popupcommon.cc @@ -0,0 +1,141 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ + +#include +#include + +PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label, bool imgRight) { + button = thisButton; + if (label.size()) { + hasText = true; + button->set_label(label + " "); + } + else + hasText = false; + // Create the list entry + imagePaths.clear(); + images.clear(); + sItems.clear(); + items.clear(); + selected = -1; // -1 : means that the button is invalid + menu = 0; + buttonImage = 0; + buttonHint = ""; + imageRight = imgRight; // By default, image is on the left in the menu +} + +PopUpCommon::~PopUpCommon () { + for (std::vector::iterator i = images.begin(); i != images.end(); ++i) + { + delete *i; + } + for (std::vector::iterator i = items.begin(); i != items.end(); ++i) + { + delete *i; + } + if (menu) delete menu; + if (buttonImage) delete buttonImage; +} + +PopUpCommon::type_signal_changed PopUpCommon::signal_changed() { + return message; +} + +bool PopUpCommon::addEntry (Glib::ustring imagePath, Glib::ustring label) { + bool added = false; + if ( Glib::file_test(safe_locale_from_utf8(imagePath), Glib::FILE_TEST_EXISTS) && label.size() ) { + imagePaths.push_back(imagePath); + sItems.push_back(label); + // Create the image + Gtk::Image* newImage = new Gtk::Image(imagePath); + images.push_back(newImage); + int currPos = (int)images.size(); + // Create the menu item + Gtk::ImageMenuItem* newItem = new Gtk::ImageMenuItem (*newImage, label); + items.push_back(newItem); + if (selected == -1) { + // Create the menu on the first item + menu = new Gtk::Menu (); + // Create the image for the button + buttonImage = new Gtk::Image(imagePath); + // Use the first image by default + if (hasText) { + button->set_image_position(imageRight ? Gtk::POS_RIGHT : Gtk::POS_LEFT); + button->set_image(*buttonImage); + } + else { + button->add(*buttonImage); + } + selected = 0; + } + newItem->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &PopUpCommon::entrySelected), currPos-1)); + menu->attach (*newItem, 0, 1, currPos-1, currPos); + // When there is at least 2 choice, we add the RMB connector + if (images.size() == 2) { + button->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) ); + } + // The item has been created + added = true; + } + return added; +} + +// TODO: 'PopUpCommon::removeEntry' method to be created... + +void PopUpCommon::entrySelected (int i) { + if (setSelected((unsigned int)i)) + // Emit a a signal if the selected item has changed + message.emit(selected); +} + +/* + * Set the button image with the selected item + */ +bool PopUpCommon::setSelected (int entryNum) { + if (entryNum < 0 || entryNum > (int)images.size()-1 || (int)entryNum == selected) + return false; + else { + // Maybe we could do something better than loading the image file each time the selection is changed !? + buttonImage->set(imagePaths.at(entryNum)); + selected = entryNum; + setButtonHint(); + return true; + } +} + +void PopUpCommon::show() { + menu->reposition(); + setButtonHint(); + menu->show_all(); + button->show(); +} + +void PopUpCommon::setButtonHint() { + button->set_tooltip_text(buttonHint.size() ? buttonHint + " : " + sItems.at(selected) : sItems.at(selected)); +} + +void PopUpCommon::showMenu(GdkEventButton* event) { + if (event->button == 3) menu->popup(event->button, event->time); +} + +void PopUpCommon::set_tooltip_text (const Glib::ustring &text) { + buttonHint = text; +} diff --git a/rtgui/popupcommon.h b/rtgui/popupcommon.h new file mode 100644 index 000000000..22def0799 --- /dev/null +++ b/rtgui/popupcommon.h @@ -0,0 +1,68 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ +#ifndef _POPUPCOMMON_ +#define _POPUPCOMMON_ + + +#include +#include + + +class PopUpCommon { + +public: + typedef sigc::signal type_signal_changed; + type_signal_changed signal_changed(); + + PopUpCommon (Gtk::Button* button, const Glib::ustring& label = "", bool imgRight=false); + ~PopUpCommon (); + bool addEntry (Glib::ustring imagePath, Glib::ustring label); + bool setSelected (int entryNum); + int getSelected () { return selected; } + void setButtonHint(); + void show (); + void set_tooltip_text (const Glib::ustring &text); + +private: + type_signal_changed message; + + /* + TODO: MenuItem::get_label() seems to be buggy : it doesn't return any string, or an empty string !? + That's why we store entries strings in sItems, but it would be nice to get ride of it... + */ + std::vector sItems; + std::vector imagePaths; + std::vector images; + std::vector items; + Glib::ustring buttonHint; + Gtk::Image* buttonImage; + Gtk::Menu* menu; + Gtk::Button* button; + int selected; + bool hasText; + bool imageRight; + + void showMenu(GdkEventButton* event); + void entrySelected (int i); + +}; + +#endif diff --git a/rtgui/popuptogglebutton.cc b/rtgui/popuptogglebutton.cc new file mode 100644 index 000000000..27e0bff30 --- /dev/null +++ b/rtgui/popuptogglebutton.cc @@ -0,0 +1,41 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ + +#include + +/* + * PopUpToggleButton::PopUpToggleButton (const Glib::ustring& label, bool imgRight) + * + * Creates a toggle button with a contextual menu where you can select an item that the button content will reflect + * + * Parameters: + * label = label displayed in the button + * imRight = 0: the image is displayed at the left of the label (default) + * 1: the image is displayed at the right of the label + */ +PopUpToggleButton::PopUpToggleButton (const Glib::ustring& label, bool imgRight) : Gtk::ToggleButton(), PopUpCommon(this, label, imgRight) { } + +void PopUpToggleButton::show() { + PopUpCommon::show(); +} +void PopUpToggleButton::set_tooltip_text (const Glib::ustring &text) { + PopUpCommon::set_tooltip_text (text); +} diff --git a/rtgui/popuptogglebutton.h b/rtgui/popuptogglebutton.h new file mode 100644 index 000000000..bc18a888f --- /dev/null +++ b/rtgui/popuptogglebutton.h @@ -0,0 +1,35 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ +#ifndef _POPUPTOGGLEBUTTON_ +#define _POPUPTOGGLEBUTTON_ + +#include +#include + +class PopUpToggleButton : public Gtk::ToggleButton, public PopUpCommon { + +public: + PopUpToggleButton (const Glib::ustring& label = "", bool imgRight=false); + void show (); + void set_tooltip_text (const Glib::ustring &text); +}; + +#endif diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index 5f6c07547..01359dde3 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -72,12 +72,17 @@ ToneCurve::ToneCurve () : ToolPanel(), expAdd(false), blackAdd(false), brAdd(fal //----------- Curve ------------------------------ pack_start (*Gtk::manage (new Gtk::HSeparator())); - shape = Gtk::manage (new CurveEditor ()); - shape->setCurveListener (this); - curvexp = Gtk::manage (new Gtk::Expander (M("TP_EXPOSURE_CURVEEDITOR"))); - curvexp->add (*shape); + curveEditorG = new CurveEditorGroup (M("TP_EXPOSURE_CURVEEDITOR")); + curveEditorG->setCurveListener (this); - pack_start (*curvexp, Gtk::PACK_SHRINK, 4); + shape = curveEditorG->addCurve(); + + // This will add the reset button at the end of the curveType buttons + curveEditorG->curveListComplete(); + + pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4); + + //curveEditorG->show(); // --------- Set Up Listeners ------------- expcomp->setAdjusterListener (this); @@ -267,7 +272,7 @@ void ToneCurve::waitForAutoExp () { hlcompr->setEnabled (false); shcompr->setEnabled (false); contrast->setEnabled (false); - shape->set_sensitive (false); + curveEditorG->set_sensitive (false); } int aexpcomputed (void* data) { @@ -296,7 +301,7 @@ void ToneCurve::enableAll () { hlcompr->setEnabled (true); shcompr->setEnabled (true); contrast->setEnabled (true); - shape->set_sensitive (true); + curveEditorG->set_sensitive (true); } bool ToneCurve::autoExpComputed_ () { @@ -310,17 +315,6 @@ bool ToneCurve::autoExpComputed_ () { return false; } -void ToneCurve::expandCurve (bool isExpanded) { - - curvexp->set_expanded (isExpanded); -} - -bool ToneCurve::isCurveExpanded () { - - return curvexp->get_expanded (); -} - - void ToneCurve::setBatchMode (bool batchMode) { removeIfThere (abox, autolevels, false); @@ -336,7 +330,7 @@ void ToneCurve::setBatchMode (bool batchMode) { brightness->showEditedCB (); contrast->showEditedCB (); - shape->setBatchMode (batchMode); + curveEditorG->setBatchMode (batchMode); } void ToneCurve::setAdjusterBehavior (bool expadd, bool bradd, bool blackadd, bool contradd) { diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h index 900e6f34e..6af309cc1 100644 --- a/rtgui/tonecurve.h +++ b/rtgui/tonecurve.h @@ -23,6 +23,7 @@ #include #include #include +#include #include class ToneCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, public rtengine::AutoExpListener, public CurveListener { @@ -39,8 +40,8 @@ class ToneCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, p Adjuster* contrast; bool expAdd, blackAdd, brAdd, contrAdd, clipDirty, lastAuto; sigc::connection autoconn; + CurveEditorGroup* curveEditorG; CurveEditor* shape; - Gtk::Expander* curvexp; double nextBr; int nextBl; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index ef52ca239..9a8a200af 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -275,8 +275,8 @@ void ToolPanelCoordinator::readOptions () { if (iset_expanded (options.tpOpen[i]); - if (options.crvOpen.size()>1) - curve->expandCurve (options.crvOpen[0]); + //if (options.crvOpen.size()>1) + // curve->expandCurve (options.crvOpen[0]); } void ToolPanelCoordinator::writeOptions () { @@ -286,8 +286,8 @@ void ToolPanelCoordinator::writeOptions () { for (int i=0; iget_expanded ()); - options.crvOpen.clear (); - options.crvOpen.push_back (curve->isCurveExpanded()); + //options.crvOpen.clear (); + //options.crvOpen.push_back (curve->isCurveExpanded()); } diff --git a/tools/CurveType.svg b/tools/CurveType.svg new file mode 100644 index 000000000..fde437f65 --- /dev/null +++ b/tools/CurveType.svg @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + +