rawTherapee/rtgui/curveeditorgroup.cc
Hombre 8b2eac9a3d Pipette and "On Preview Widgets" branch. See issue 227
The pipette part is already working quite nice but need to be finished. The widgets part needs more work...
2014-01-21 23:37:36 +01:00

402 lines
13 KiB
C++

/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*
* Class created by Jean-Christophe FRISCH, aka 'Hombre'
*/
#include "curveeditor.h"
#include "curveeditorgroup.h"
#include "diagonalcurveeditorsubgroup.h"
#include "flatcurveeditorsubgroup.h"
#include "multilangmgr.h"
#include "../rtengine/safegtk.h"
#include "rtimage.h"
CurveEditorGroup::CurveEditorGroup (Glib::ustring& curveDir, Glib::ustring groupLabel) : curveDir(curveDir), cl(NULL) {
curveEditors.clear();
displayedCurve = 0;
numberOfPackedCurve = 0;
flatSubGroup = 0;
diagonalSubGroup = 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));
}
CurveEditorGroup::~CurveEditorGroup() {
for (std::vector<CurveEditor*>::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i)
{
delete *i;
}
delete flatSubGroup;
delete diagonalSubGroup;
}
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
*
* Parameters:
* cType: enum saying which kind of curve type has to be created
* curveLabel: Name of the curve that will be inserted in the toggle button, before the image.
* If empty, no text will prepend the image
* relatedWidget: pointer to a widget (or NULL) that will be inserted next to the curve's toggle button.
* if a smart pointer created by Gtk::manage is passed in, the widget will be deleted by the destructor,
* otherwise it'll have to be delete it manually
* periodic: for FlatCurve only, ask the curve to be periodic (default: True)
*
*/
CurveEditor* CurveEditorGroup::addCurve(CurveType cType, Glib::ustring curveLabel, Gtk::Widget *relatedWidget, bool periodic) {
switch (cType) {
case (CT_Diagonal):
{
if (!diagonalSubGroup) {
diagonalSubGroup = new DiagonalCurveEditorSubGroup(this, curveDir);
}
// We add it to the curve editor list
DiagonalCurveEditor* newCE = diagonalSubGroup->addCurve(curveLabel);
newCE->relatedWidget = relatedWidget;
curveEditors.push_back(newCE);
return (newCE);
}
case (CT_Flat):
{
if (!flatSubGroup) {
flatSubGroup = new FlatCurveEditorSubGroup(this, curveDir);
}
// We add it to the curve editor list
FlatCurveEditor* newCE = flatSubGroup->addCurve(curveLabel, periodic);
newCE->relatedWidget = relatedWidget;
curveEditors.push_back(newCE);
return (newCE);
}
default:
return (static_cast<CurveEditor*>(NULL));
break;
}
return NULL; // to avoid complains from Gcc
}
/*
* 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 RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.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);
}
int j = numberOfPackedCurve;
bool hasRelatedWidget = false;
for (int i = (int)(curveEditors.size())-1; i >= j; i--) {
if (curveEditors[i]->relatedWidget != NULL)
hasRelatedWidget = true;
}
for (int i = (int)(curveEditors.size())-1; i >= j; i--) {
if (curveEditors[i]->relatedWidget != NULL)
headerBox->pack_end (*curveEditors[i]->relatedWidget, Gtk::PACK_EXPAND_WIDGET, 2);
headerBox->pack_end (*curveEditors[i]->curveType->buttonGroup, hasRelatedWidget ? Gtk::PACK_SHRINK : 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 && n==(int)ce->selected)
return;
if (n<ce->subGroup->valUnchanged)
ce->selected = 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()) {
ce->subGroup->storeDisplayedCurve();
// We set it pressed : it will emit the toggle on signal and update the GUI
ce->curveType->set_active( n>ce->subGroup->valLinear && n<ce->subGroup->valUnchanged );
if (n==ce->subGroup->valLinear || n==ce->subGroup->valUnchanged) {
// Since we do not activate the curve when the user switch the toggled off button to 'Linear', we have to
// to call the curve listener manually, because 'curveChanged' uses displayedCurve...
if (cl) {
if (cl->isMulti())
cl->curveChanged (ce);
else
cl->curveChanged ();
}
}
else
curveChanged ();
}
else {
// The button is already pressed so we switch the GUI ourselves
ce->subGroup->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()==ce->subGroup->valUnchanged) {
curveRestored = true;
ce->curveType->setSelected(ce->selected);
}
// then show this CurveEditor
int ct = ce->curveType->getSelected();
if (ct < ce->subGroup->valUnchanged)
ce->subGroup->restoreDisplayedHistogram();
}
else {
// The button is now released, so we have to hide this CurveEditor
displayedCurve = 0;
}
ce->subGroup->switchGUI();
if (curveRestored)
curveChanged ();
}
/*
* 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()<ce->subGroup->valUnchanged)
ce->curveType->setSelected(ce->selected);
// if not displayed or "unchanged" is selected, do not change gui
if (ce==displayedCurve && ce->curveType->getSelected()<ce->subGroup->valUnchanged) {
ce->subGroup->switchGUI();
}
}
/*
* Called from the outside to set the curve type & values
*/
void CurveEditorGroup::setCurveExternal (CurveEditor* ce, const std::vector<double>& c) {
if (!c.empty()) {
ce->subGroup->storeCurveValues(ce, c); // The new curve is saved in the CurveEditor
(ce)->selected = c[0]; // We set the selected curve type in the CurveEditor to the one of the specified curve
}
updateGUI(static_cast<CurveEditor*>(ce)); // And we update the GUI if necessary
}
/*
* Listener called when the user has modified the curve
*/
void CurveEditorGroup::curveChanged () {
displayedCurve->subGroup->storeDisplayedCurve();
if (cl) {
if (cl->isMulti())
cl->curveChanged (displayedCurve);
else
cl->curveChanged ();
}
}
/*
* Call back method when the reset button is pressed :
* reset the currently toggled on curve editor
*/
void CurveEditorGroup::curveResetPressed () {
if (displayedCurve) {
if (displayedCurve->subGroup->curveReset(displayedCurve->selected, displayedCurve->getIdentityValue())) {
curveChanged();
}
}
}
/*
* Set the tooltip text of the label of the curve group
*/
void CurveEditorGroup::setTooltip( Glib::ustring ttip) {
curveGroupLabel->set_tooltip_text( ttip );
}
void CurveEditorGroup::setBatchMode (bool batchMode) {
for (std::vector<CurveEditor*>::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i) {
(*i)->curveType->addEntry("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(ce->subGroup->valUnchanged);
//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);
}
}
CurveEditorSubGroup::CurveEditorSubGroup(Glib::ustring& curveDir) : curveDir(curveDir), lastFilename("") {
leftBar = NULL;
bottomBar = NULL;
}
CurveEditorSubGroup::~CurveEditorSubGroup() {
if (leftBar) delete leftBar;
if (bottomBar) delete bottomBar;
}
Glib::ustring CurveEditorSubGroup::outputFile () {
Gtk::FileChooserDialog dialog(M("CURVEEDITOR_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE);
FileChooserLastFolderPersister persister(&dialog, curveDir);
dialog.set_current_name (lastFilename);
dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL);
dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_APPLY);
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);
Glib::ustring fname;
do {
if (dialog.run() == Gtk::RESPONSE_APPLY) {
fname = dialog.get_filename();
if (getExtension (fname) != "rtc")
fname += ".rtc";
if (confirmOverwrite (dialog, fname)) {
lastFilename = Glib::path_get_basename (fname);
break;
}
} else {
fname = "";
break;
}
} while (1);
return fname;
}
Glib::ustring CurveEditorSubGroup::inputFile () {
Gtk::FileChooserDialog dialog(M("CURVEEDITOR_LOADDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN);
FileChooserLastFolderPersister persister(&dialog, curveDir);
dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL);
dialog.add_button(Gtk::StockID("gtk-apply"), Gtk::RESPONSE_APPLY);
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);
int result = dialog.run();
Glib::ustring fname;
if (result==Gtk::RESPONSE_APPLY) {
fname = dialog.get_filename();
if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS))
return fname;
}
fname = "";
return fname;
}