Patch from issue 1267: "New Threshold curve widget", used in USM Sharpening and Vibrance
This commit is contained in:
@@ -3,7 +3,7 @@ set (BASESOURCEFILES
|
||||
editwindow.cc batchtoolpanelcoord.cc paramsedited.cc cropwindow.cc previewhandler.cc previewwindow.cc navigator.cc indclippedpanel.cc previewmodepanel.cc filterpanel.cc
|
||||
exportpanel.cc cursormanager.cc rtwindow.cc renamedlg.cc recentbrowser.cc placesbrowser.cc filepanel.cc editorpanel.cc batchqueuepanel.cc
|
||||
ilabel.cc thumbbrowserbase.cc adjuster.cc filebrowserentry.cc filebrowser.cc filethumbnailbuttonset.cc
|
||||
cachemanager.cc cacheimagedata.cc shcselector.cc perspective.cc
|
||||
cachemanager.cc cacheimagedata.cc shcselector.cc perspective.cc thresholdselector.cc thresholdadjuster.cc
|
||||
clipboard.cc thumbimageupdater.cc bqentryupdater.cc lensgeom.cc
|
||||
coarsepanel.cc cacorrection.cc hlrec.cc chmixer.cc
|
||||
resize.cc icmpanel.cc crop.cc shadowshighlights.cc
|
||||
|
@@ -49,11 +49,10 @@
|
||||
#define ADDSET_SHARPENMICRO_UNIFORMITY 39
|
||||
#define ADDSET_VIBRANCE_PASTELS 40
|
||||
#define ADDSET_VIBRANCE_SATURATED 41
|
||||
#define ADDSET_VIBRANCE_PSTHRESHOLD 42
|
||||
#define ADDSET_FREE_OUPUT_GAMMA 43
|
||||
#define ADDSET_FREE_OUTPUT_SLOPE 44
|
||||
#define ADDSET_FREE_OUPUT_GAMMA 42
|
||||
#define ADDSET_FREE_OUTPUT_SLOPE 43
|
||||
|
||||
// When adding items, make sure to update ADDSET_PARAM_NUM
|
||||
#define ADDSET_PARAM_NUM 45 // THIS IS USED AS A DELIMITER!!
|
||||
#define ADDSET_PARAM_NUM 44 // THIS IS USED AS A DELIMITER!!
|
||||
|
||||
#endif
|
||||
|
@@ -243,11 +243,6 @@ void Adjuster::setAddMode(bool addM) {
|
||||
}
|
||||
}
|
||||
|
||||
void Adjuster::setAdjusterListener (AdjusterListener* alistener) {
|
||||
|
||||
adjusterListener = alistener;
|
||||
}
|
||||
|
||||
void Adjuster::spinChanged () {
|
||||
|
||||
sliderChange.block (true);
|
||||
@@ -312,24 +307,6 @@ void Adjuster::setValue (double a) {
|
||||
afterReset = false;
|
||||
}
|
||||
|
||||
// return the value trimmed to the limits at construction time
|
||||
double Adjuster::getValue () {
|
||||
|
||||
return spin->get_value ();
|
||||
}
|
||||
|
||||
// return the value trimmed to the limits at construction time
|
||||
int Adjuster::getIntValue () {
|
||||
|
||||
return spin->get_value_as_int ();
|
||||
}
|
||||
|
||||
// method only used by the history manager
|
||||
Glib::ustring Adjuster::getTextValue () {
|
||||
|
||||
return spin->get_text ();
|
||||
}
|
||||
|
||||
bool Adjuster::notifyListener () {
|
||||
|
||||
if (adjusterListener!=NULL && !blocked) {
|
||||
|
@@ -68,11 +68,16 @@ class Adjuster : public Gtk::VBox {
|
||||
Adjuster (Glib::ustring label, double vmin, double vmax, double vstep, double vdefault, bool editedCheckBox=false);
|
||||
Adjuster (Gtk::Image *imgIcon, double vmin, double vmax, double vstep, double vdefault, bool editedCheckBox=false);
|
||||
virtual ~Adjuster ();
|
||||
void setAdjusterListener (AdjusterListener* alistener);
|
||||
void setAdjusterListener (AdjusterListener* alistener) { adjusterListener = alistener; }
|
||||
|
||||
// return the value trimmed to the limits at construction time
|
||||
double getValue () { return spin->get_value (); }
|
||||
// return the value trimmed to the limits at construction time
|
||||
int getIntValue () { return spin->get_value_as_int (); }
|
||||
// return the value trimmed to the limits at construction time,
|
||||
// method only used by the history manager
|
||||
Glib::ustring getTextValue () { return spin->get_text (); }
|
||||
|
||||
double getValue ();
|
||||
int getIntValue ();
|
||||
Glib::ustring getTextValue ();
|
||||
void setValue (double a);
|
||||
void setLimits (double vmin, double vmax, double vstep, double vdefault);
|
||||
void setEnabled (bool enabled);
|
||||
|
@@ -147,7 +147,6 @@ void BatchToolPanelCoordinator::initSession () {
|
||||
toneCurve->setAdjusterBehavior (options.baBehav[ADDSET_TC_EXPCOMP], options.baBehav[ADDSET_TC_HLCOMPAMOUNT],options.baBehav[ADDSET_TC_HLCOMPTHRESH], options.baBehav[ADDSET_TC_BRIGHTNESS], options.baBehav[ADDSET_TC_BLACKLEVEL],options.baBehav[ADDSET_TC_SHCOMP], options.baBehav[ADDSET_TC_CONTRAST], options.baBehav[ADDSET_TC_SATURATION]);
|
||||
lcurve->setAdjusterBehavior (options.baBehav[ADDSET_LC_BRIGHTNESS], options.baBehav[ADDSET_LC_CONTRAST], options.baBehav[ADDSET_LC_SATURATION]);
|
||||
whitebalance->setAdjusterBehavior (options.baBehav[ADDSET_WB_TEMPERATURE], options.baBehav[ADDSET_WB_GREEN]);
|
||||
vibrance->setAdjusterBehavior (options.baBehav[ADDSET_VIBRANCE_PASTELS], options.baBehav[ADDSET_VIBRANCE_SATURATED], options.baBehav[ADDSET_VIBRANCE_PSTHRESHOLD]);
|
||||
vignetting->setAdjusterBehavior (options.baBehav[ADDSET_VIGN_AMOUNT]);
|
||||
rotate->setAdjusterBehavior (options.baBehav[ADDSET_ROTATE_DEGREE]);
|
||||
distortion->setAdjusterBehavior (options.baBehav[ADDSET_DIST_AMOUNT]);
|
||||
|
@@ -196,4 +196,20 @@ public:
|
||||
void switchTo(TOITypes type);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Define a gradient milestone
|
||||
*/
|
||||
class GradientMilestone {
|
||||
public:
|
||||
double position;
|
||||
double r;
|
||||
double g;
|
||||
double b;
|
||||
double a;
|
||||
|
||||
GradientMilestone(double _p=0., double _r=0., double _g=0., double _b=0., double _a=0.) {
|
||||
position = _p; r = _r; g = _g; b = _b; a = _a;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -36,7 +36,9 @@
|
||||
#include <Shlobj.h>
|
||||
#endif
|
||||
|
||||
// User's settings directory, including images' profiles if used
|
||||
Glib::ustring Options::rtdir;
|
||||
// User's cached datas' directory
|
||||
Glib::ustring Options::cacheBaseDir;
|
||||
|
||||
Options options;
|
||||
@@ -385,9 +387,8 @@ void Options::setDefaults () {
|
||||
0, // ADDSET_SHARPENMICRO_UNIFORMITY
|
||||
0, // ADDSET_VIBRANCE_PASTELS
|
||||
0, // ADDSET_VIBRANCE_SATURATED
|
||||
0, // ADDSET_VIBRANCE_PSTHRESHOLD
|
||||
0, // ADDSET_FREE_OUPUT_GAMMA
|
||||
0, // ADDSET_FREE_OUTPUT_SLOPE
|
||||
0, // ADDSET_FREE_OUPUT_GAMMA
|
||||
0, // ADDSET_FREE_OUTPUT_SLOPE
|
||||
|
||||
};
|
||||
baBehav = std::vector<int> (babehav, babehav+ADDSET_PARAM_NUM);
|
||||
|
@@ -454,7 +454,15 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
|
||||
if (sharpening.enabled) toEdit.sharpening.enabled = mods.sharpening.enabled;
|
||||
if (sharpening.radius) toEdit.sharpening.radius = mods.sharpening.radius;
|
||||
if (sharpening.amount) toEdit.sharpening.amount = dontforceSet && options.baBehav[ADDSET_SHARP_AMOUNT] ? toEdit.sharpening.amount + mods.sharpening.amount : mods.sharpening.amount;
|
||||
if (sharpening.threshold) toEdit.sharpening.threshold = mods.sharpening.threshold;
|
||||
if (sharpening.threshold) toEdit.sharpening.threshold = mods.sharpening.threshold;
|
||||
|
||||
for (int i=0; i<3; i++) {
|
||||
if (chmixer.red[i]) toEdit.chmixer.red[i] = dontforceSet && options.baBehav[ADDSET_CHMIXER] ? toEdit.chmixer.red[i] + mods.chmixer.red[i] : mods.chmixer.red[i];
|
||||
if (chmixer.green[i]) toEdit.chmixer.green[i] = dontforceSet && options.baBehav[ADDSET_CHMIXER] ? toEdit.chmixer.green[i] + mods.chmixer.green[i] : mods.chmixer.green[i];
|
||||
if (chmixer.blue[i]) toEdit.chmixer.blue[i] = dontforceSet && options.baBehav[ADDSET_CHMIXER] ? toEdit.chmixer.blue[i] + mods.chmixer.blue[i] : mods.chmixer.blue[i];
|
||||
}
|
||||
|
||||
|
||||
if (sharpening.edgesonly) toEdit.sharpening.edgesonly = mods.sharpening.edgesonly;
|
||||
if (sharpening.edges_radius) toEdit.sharpening.edges_radius = mods.sharpening.edges_radius;
|
||||
if (sharpening.edges_tolerance) toEdit.sharpening.edges_tolerance = mods.sharpening.edges_tolerance;
|
||||
@@ -468,7 +476,7 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
|
||||
if (vibrance.enabled) toEdit.vibrance.enabled = mods.vibrance.enabled;
|
||||
if (vibrance.pastels) toEdit.vibrance.pastels = dontforceSet && options.baBehav[ADDSET_VIBRANCE_PASTELS] ? toEdit.vibrance.pastels + mods.vibrance.pastels : mods.vibrance.pastels;
|
||||
if (vibrance.saturated) toEdit.vibrance.saturated = dontforceSet && options.baBehav[ADDSET_VIBRANCE_SATURATED] ? toEdit.vibrance.saturated + mods.vibrance.saturated : mods.vibrance.saturated;
|
||||
if (vibrance.psthreshold) toEdit.vibrance.psthreshold = dontforceSet && options.baBehav[ADDSET_VIBRANCE_PSTHRESHOLD] ? toEdit.vibrance.psthreshold + mods.vibrance.psthreshold : mods.vibrance.psthreshold;
|
||||
if (vibrance.psthreshold) toEdit.vibrance.psthreshold = mods.vibrance.psthreshold;
|
||||
if (vibrance.protectskins) toEdit.vibrance.protectskins = mods.vibrance.protectskins;
|
||||
if (vibrance.avoidcolorshift) toEdit.vibrance.avoidcolorshift = mods.vibrance.avoidcolorshift;
|
||||
if (vibrance.pastsattog) toEdit.vibrance.pastsattog = mods.vibrance.pastsattog;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#define _PPVERSION_
|
||||
|
||||
// This number have to be incremented whenever the PP3 file format is modified
|
||||
#define PPVERSION 301
|
||||
#define PPVERSION 302
|
||||
#define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified
|
||||
|
||||
#endif
|
||||
|
@@ -195,7 +195,6 @@ Gtk::Widget* Preferences::getBatchProcPanel () {
|
||||
mi->set_value (behavColumns.label, M("TP_VIBRANCE_LABEL"));
|
||||
appendBehavList (mi, M("TP_VIBRANCE_PASTELS"), ADDSET_VIBRANCE_PASTELS, false);
|
||||
appendBehavList (mi, M("TP_VIBRANCE_SATURATED"), ADDSET_VIBRANCE_SATURATED, false);
|
||||
appendBehavList (mi, M("TP_VIBRANCE_PSTHRESHOLD"), ADDSET_VIBRANCE_PSTHRESHOLD, false);
|
||||
|
||||
mi = behModel->append ();
|
||||
mi->set_value (behavColumns.label, M("TP_GAMMA_OUTPUT"));
|
||||
|
@@ -26,6 +26,10 @@ using namespace rtengine::procparams;
|
||||
|
||||
Sharpening::Sharpening () : Gtk::VBox(), FoldableToolPanel(this) {
|
||||
|
||||
std::vector<GradientMilestone> milestones;
|
||||
milestones.push_back( GradientMilestone(0.0, 0.0, 0.0, 0.0) );
|
||||
milestones.push_back( GradientMilestone(1.0, 1.0, 1.0, 1.0) );
|
||||
|
||||
enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED")));
|
||||
enabled->set_active (true);
|
||||
pack_start(*enabled);
|
||||
@@ -69,7 +73,8 @@ Sharpening::Sharpening () : Gtk::VBox(), FoldableToolPanel(this) {
|
||||
Gtk::HSeparator *hsep6a = Gtk::manage (new Gtk::HSeparator());
|
||||
amount = Gtk::manage (new Adjuster (M("TP_SHARPENING_AMOUNT"), 1, 1000, 1, 150));
|
||||
radius = Gtk::manage (new Adjuster (M("TP_SHARPENING_RADIUS"), 0.3, 3, 0.01, 0.8));
|
||||
threshold = Gtk::manage (new Adjuster (M("TP_SHARPENING_THRESHOLD"), 0, 16384, 50, 1));
|
||||
threshold = Gtk::manage (new ThresholdAdjuster (M("TP_SHARPENING_THRESHOLD"), 0., 2000., 20., 80., 2000., 1200., 0, false));
|
||||
threshold->setBgGradient(milestones);
|
||||
pack_start(*hsep6a, Gtk::PACK_SHRINK, 2);
|
||||
|
||||
pack_start (*usm);
|
||||
@@ -186,7 +191,7 @@ void Sharpening::read (const ProcParams* pp, const ParamsEdited* pedited) {
|
||||
|
||||
amount->setValue (pp->sharpening.amount);
|
||||
radius->setValue (pp->sharpening.radius);
|
||||
threshold->setValue (pp->sharpening.threshold);
|
||||
threshold->setValue<int>(pp->sharpening.threshold);
|
||||
eradius->setValue (pp->sharpening.edges_radius);
|
||||
etolerance->setValue (pp->sharpening.edges_tolerance);
|
||||
hcamount->setValue (pp->sharpening.halocontrol_amount);
|
||||
@@ -221,7 +226,7 @@ void Sharpening::write (ProcParams* pp, ParamsEdited* pedited) {
|
||||
pp->sharpening.amount = (int)amount->getValue();
|
||||
pp->sharpening.enabled = enabled->get_active ();
|
||||
pp->sharpening.radius = radius->getValue ();
|
||||
pp->sharpening.threshold = (int)threshold->getValue ();
|
||||
pp->sharpening.threshold = threshold->getValue<int> ();
|
||||
pp->sharpening.edgesonly = edgesonly->get_active ();
|
||||
pp->sharpening.edges_radius = eradius->getValue ();
|
||||
pp->sharpening.edges_tolerance = (int)etolerance->getValue ();
|
||||
@@ -259,7 +264,7 @@ void Sharpening::setDefaults (const ProcParams* defParams, const ParamsEdited* p
|
||||
|
||||
amount->setDefault (defParams->sharpening.amount);
|
||||
radius->setDefault (defParams->sharpening.radius);
|
||||
threshold->setDefault (defParams->sharpening.threshold);
|
||||
threshold->setDefault<int> (defParams->sharpening.threshold);
|
||||
eradius->setDefault (defParams->sharpening.edges_radius);
|
||||
etolerance->setDefault (defParams->sharpening.edges_tolerance);
|
||||
hcamount->setDefault (defParams->sharpening.halocontrol_amount);
|
||||
@@ -310,8 +315,6 @@ void Sharpening::adjusterChanged (Adjuster* a, double newval) {
|
||||
listener->panelChanged (EvShrAmount, costr);
|
||||
else if (a==radius)
|
||||
listener->panelChanged (EvShrRadius, costr);
|
||||
else if (a==threshold)
|
||||
listener->panelChanged (EvShrThresh, costr);
|
||||
else if (a==eradius)
|
||||
listener->panelChanged (EvShrEdgeRadius, costr);
|
||||
else if (a==etolerance)
|
||||
@@ -329,6 +332,13 @@ void Sharpening::adjusterChanged (Adjuster* a, double newval) {
|
||||
}
|
||||
}
|
||||
|
||||
//void Sharpening::adjusterChanged (ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight) {
|
||||
void Sharpening::adjusterChanged (ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight) {
|
||||
if (listener && enabled->get_active()) {
|
||||
listener->panelChanged (EvShrThresh, threshold->getHistoryString());
|
||||
}
|
||||
}
|
||||
|
||||
void Sharpening::enabled_toggled () {
|
||||
|
||||
if (batchMode) {
|
||||
|
@@ -21,10 +21,10 @@
|
||||
|
||||
#include <gtkmm.h>
|
||||
#include "adjuster.h"
|
||||
#include "guiutils.h"
|
||||
#include "thresholdadjuster.h"
|
||||
#include "toolpanel.h"
|
||||
|
||||
class Sharpening : public Gtk::VBox, public AdjusterListener, public FoldableToolPanel {
|
||||
class Sharpening : public Gtk::VBox, public ThresholdAdjusterListener, public AdjusterListener, public FoldableToolPanel {
|
||||
|
||||
protected:
|
||||
MyComboBoxText* method;
|
||||
@@ -37,7 +37,6 @@ class Sharpening : public Gtk::VBox, public AdjusterListener, public FoldableToo
|
||||
|
||||
Adjuster* radius;
|
||||
Adjuster* amount;
|
||||
Adjuster* threshold;
|
||||
Adjuster* eradius;
|
||||
Adjuster* etolerance;
|
||||
Adjuster* hcamount;
|
||||
@@ -45,6 +44,7 @@ class Sharpening : public Gtk::VBox, public AdjusterListener, public FoldableToo
|
||||
Gtk::VBox* hcbin;
|
||||
Gtk::VBox* edgebox;
|
||||
Gtk::VBox* hcbox;
|
||||
ThresholdAdjuster* threshold;
|
||||
Gtk::CheckButton* enabled;
|
||||
bool lastEnabled;
|
||||
sigc::connection enaConn;
|
||||
@@ -68,6 +68,7 @@ class Sharpening : public Gtk::VBox, public AdjusterListener, public FoldableToo
|
||||
void setBatchMode (bool batchMode);
|
||||
|
||||
void adjusterChanged (Adjuster* a, double newval);
|
||||
void adjusterChanged (ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight);
|
||||
void enabled_toggled ();
|
||||
void edgesonly_toggled ();
|
||||
void halocontrol_toggled ();
|
||||
|
301
rtgui/thresholdadjuster.cc
Normal file
301
rtgui/thresholdadjuster.cc
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
#include "thresholdadjuster.h"
|
||||
#include <sigc++/class_slot.h>
|
||||
#include <cmath>
|
||||
#include "multilangmgr.h"
|
||||
#include "../rtengine/rtengine.h"
|
||||
#include "options.h"
|
||||
#include "guiutils.h"
|
||||
#include "rtimage.h"
|
||||
|
||||
#define MIN_RESET_BUTTON_HEIGHT 17
|
||||
|
||||
ThresholdAdjuster::ThresholdAdjuster (Glib::ustring label, double minValue, double maxValue, double defBottom,
|
||||
double defTop, unsigned int precision, bool startAtOne, bool editedCheckBox)
|
||||
: tSelector(minValue, maxValue, defBottom, defTop, precision, startAtOne)
|
||||
{
|
||||
initialDefaultVal[ThresholdSelector::TS_BOTTOMLEFT] = defBottom;
|
||||
initialDefaultVal[ThresholdSelector::TS_TOPLEFT] = defTop;
|
||||
initialDefaultVal[ThresholdSelector::TS_BOTTOMRIGHT] = maxValue;
|
||||
initialDefaultVal[ThresholdSelector::TS_TOPRIGHT] = maxValue;
|
||||
|
||||
initObject (label, editedCheckBox);
|
||||
}
|
||||
|
||||
ThresholdAdjuster::ThresholdAdjuster (Glib::ustring label, double minValue, double maxValue,
|
||||
double defBottomLeft, double defTopLeft, double defBottomRight, double defTopRight,
|
||||
unsigned int precision, bool startAtOne, bool editedCheckBox)
|
||||
: tSelector(minValue, maxValue, defBottomLeft, defTopLeft,
|
||||
defBottomRight, defTopRight, precision, startAtOne)
|
||||
{
|
||||
initialDefaultVal[ThresholdSelector::TS_BOTTOMLEFT] = defBottomLeft;
|
||||
initialDefaultVal[ThresholdSelector::TS_TOPLEFT] = defTopLeft;
|
||||
initialDefaultVal[ThresholdSelector::TS_BOTTOMRIGHT] = defBottomRight;
|
||||
initialDefaultVal[ThresholdSelector::TS_TOPRIGHT] = defTopRight;
|
||||
|
||||
initObject (label, editedCheckBox);
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::initObject (Glib::ustring label, bool editedcb) {
|
||||
|
||||
adjusterListener = NULL;
|
||||
afterReset = false;
|
||||
blocked = false;
|
||||
|
||||
addMode = false;
|
||||
|
||||
// TODO: let the user chose the default value of ThresholdAdjuster::delay, for slow machines
|
||||
delay = options.adjusterDelay; // delay is no more static, so we can set the delay individually (useful for the RAW editor tab)
|
||||
|
||||
set_border_width (2);
|
||||
|
||||
hbox = Gtk::manage (new Gtk::HBox ());
|
||||
|
||||
this->label = Gtk::manage (new Gtk::Label (label, Gtk::ALIGN_LEFT));
|
||||
|
||||
if (editedcb) {
|
||||
editedCheckBox = Gtk::manage (new Gtk::CheckButton ());
|
||||
editedChange = editedCheckBox->signal_toggled().connect( sigc::mem_fun(*this, &ThresholdAdjuster::editedToggled) );
|
||||
hbox->pack_start (*editedCheckBox);
|
||||
}
|
||||
else
|
||||
editedCheckBox = NULL;
|
||||
|
||||
hbox->pack_start (*this->label);
|
||||
|
||||
reset = Gtk::manage (new Gtk::Button ());
|
||||
reset->add (*Gtk::manage (new RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.png")));
|
||||
reset->set_relief (Gtk::RELIEF_NONE);
|
||||
reset->set_border_width (0);
|
||||
reset->set_tooltip_text (M("ADJUSTER_RESET_TO_DEFAULT"));
|
||||
|
||||
hbox->pack_end (*reset, Gtk::PACK_SHRINK, 0);
|
||||
|
||||
reset->set_size_request (-1, this->label->get_height() > MIN_RESET_BUTTON_HEIGHT ? this->label->get_height(): MIN_RESET_BUTTON_HEIGHT);
|
||||
|
||||
pack_start (*hbox, false, false);
|
||||
pack_start (tSelector, false, false);
|
||||
|
||||
editedState = defEditedState = Irrelevant;
|
||||
|
||||
selectorChange = tSelector.signal_value_changed().connect( sigc::mem_fun(*this, &ThresholdAdjuster::selectorChanged) );
|
||||
reset->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &ThresholdAdjuster::resetPressed) );
|
||||
|
||||
show_all ();
|
||||
}
|
||||
|
||||
ThresholdAdjuster::~ThresholdAdjuster () {
|
||||
|
||||
selectorChange.disconnect();
|
||||
delayConnection.block(true);
|
||||
adjusterListener = NULL;
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::setDefault (double bottom, double top) {
|
||||
|
||||
selectorChange.block (true);
|
||||
tSelector.setPositions(shapeValue(bottom), shapeValue(top));
|
||||
selectorChange.block (false);
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::setDefault (double bottomLeft, double topLeft, double bottomRight, double topRight) {
|
||||
|
||||
selectorChange.block (true);
|
||||
tSelector.setPositions(shapeValue(bottomLeft), shapeValue(topLeft), shapeValue(bottomRight), shapeValue(topRight));
|
||||
selectorChange.block (false);
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::setDefaultEditedState (EditedState eState) {
|
||||
|
||||
defEditedState = eState;
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::resetPressed (GdkEventButton* event) {
|
||||
|
||||
if (editedState!=Irrelevant) {
|
||||
editedState = defEditedState;
|
||||
if (editedCheckBox) {
|
||||
editedChange.block (true);
|
||||
editedCheckBox->set_active (defEditedState==Edited);
|
||||
editedChange.block (false);
|
||||
}
|
||||
refreshLabelStyle ();
|
||||
}
|
||||
afterReset = true;
|
||||
if ((event != NULL) && (event->state & GDK_CONTROL_MASK) && (event->button == 1))
|
||||
// CTRL pressed : resetting to current default value
|
||||
tSelector.reset();
|
||||
else
|
||||
// no modifier key or addMode=true : resetting to initial default value
|
||||
tSelector.setPositions(initialDefaultVal[ThresholdSelector::TS_BOTTOMLEFT],
|
||||
initialDefaultVal[ThresholdSelector::TS_TOPLEFT],
|
||||
initialDefaultVal[ThresholdSelector::TS_BOTTOMRIGHT],
|
||||
initialDefaultVal[ThresholdSelector::TS_TOPRIGHT]);
|
||||
}
|
||||
|
||||
double ThresholdAdjuster::shapeValue (double a) {
|
||||
|
||||
unsigned int digit = tSelector.getPrecision();
|
||||
return round(a*pow(double(10), digit)) / pow(double(10), digit);
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::selectorChanged () {
|
||||
|
||||
if (delayConnection.connected())
|
||||
delayConnection.disconnect ();
|
||||
|
||||
if (delay==0) {
|
||||
if (adjusterListener && !blocked)
|
||||
sendToListener ();
|
||||
}
|
||||
else
|
||||
delayConnection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ThresholdAdjuster::notifyListener), delay);
|
||||
|
||||
if (!afterReset && editedState==UnEdited) {
|
||||
editedState = Edited;
|
||||
if (editedCheckBox) {
|
||||
editedChange.block (true);
|
||||
editedCheckBox->set_active (true);
|
||||
editedChange.block (false);
|
||||
}
|
||||
refreshLabelStyle ();
|
||||
}
|
||||
afterReset = false;
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::setValue (double bottom, double top) {
|
||||
|
||||
selectorChange.block (true);
|
||||
tSelector.setPositions(bottom, top);
|
||||
selectorChange.block (false);
|
||||
afterReset = false;
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::setValue (double bottomLeft, double topLeft, double bottomRight, double topRight) {
|
||||
|
||||
selectorChange.block (true);
|
||||
tSelector.setPositions(bottomLeft, topLeft, bottomRight, topRight);
|
||||
selectorChange.block (false);
|
||||
afterReset = false;
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::getValue (Glib::ustring& bottom, Glib::ustring& top) {
|
||||
tSelector.getPositions (bottom, top);
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::getValue (Glib::ustring& bottomLeft, Glib::ustring& topLeft, Glib::ustring& bottomRight, Glib::ustring& topRight) {
|
||||
tSelector.getPositions (bottomLeft, topLeft, bottomRight, topRight);
|
||||
}
|
||||
|
||||
bool ThresholdAdjuster::notifyListener () {
|
||||
|
||||
if (adjusterListener!=NULL && !blocked) {
|
||||
GThreadLock lock;
|
||||
sendToListener();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::setEnabled (bool enabled) {
|
||||
|
||||
tSelector.set_sensitive (enabled);
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::setEditedState (EditedState eState) {
|
||||
|
||||
if (editedState!=eState) {
|
||||
if (editedCheckBox) {
|
||||
editedChange.block (true);
|
||||
editedCheckBox->set_active (eState==Edited);
|
||||
editedChange.block (false);
|
||||
}
|
||||
editedState = eState;
|
||||
refreshLabelStyle ();
|
||||
}
|
||||
}
|
||||
|
||||
EditedState ThresholdAdjuster::getEditedState () {
|
||||
|
||||
if (editedState!=Irrelevant && editedCheckBox)
|
||||
editedState = editedCheckBox->get_active () ? Edited : UnEdited;
|
||||
return editedState;
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::showEditedCB () {
|
||||
|
||||
if (!editedCheckBox) {
|
||||
editedCheckBox = Gtk::manage(new Gtk::CheckButton ());
|
||||
hbox->pack_start (*editedCheckBox, Gtk::PACK_SHRINK, 2);
|
||||
hbox->reorder_child (*editedCheckBox, 0);
|
||||
editedChange = editedCheckBox->signal_toggled().connect( sigc::mem_fun(*this, &ThresholdAdjuster::editedToggled) );
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::refreshLabelStyle () {
|
||||
|
||||
/* Glib::RefPtr<Gtk::Style> style = label->get_style ();
|
||||
Pango::FontDescription fd = style->get_font ();
|
||||
fd.set_weight (editedState==Edited ? Pango::WEIGHT_BOLD : Pango::WEIGHT_NORMAL);
|
||||
style->set_font (fd);
|
||||
label->set_style (style);
|
||||
label->queue_draw ();*/
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::editedToggled () {
|
||||
|
||||
if (adjusterListener && !blocked)
|
||||
sendToListener ();
|
||||
}
|
||||
|
||||
void ThresholdAdjuster::sendToListener () {
|
||||
if (tSelector.getPrecision() > 0) {
|
||||
// if precision is >0, then we assume that the listener is waiting for doubles
|
||||
rtengine::procparams::Threshold<double> t = tSelector.getPositions<double>();
|
||||
if (tSelector.isDouble())
|
||||
adjusterListener->adjusterChanged (this, t.value[0], t.value[1], t.value[2], t.value[3]);
|
||||
else
|
||||
adjusterListener->adjusterChanged (this, t.value[0], t.value[1]);
|
||||
}
|
||||
else {
|
||||
// if precision is equal to 0, then we assume that the listener is waiting for integers
|
||||
rtengine::procparams::Threshold<int> t = tSelector.getPositions<int>();
|
||||
if (tSelector.isDouble())
|
||||
adjusterListener->adjusterChanged (this, t.value[0], t.value[1], t.value[2], t.value[3]);
|
||||
else
|
||||
adjusterListener->adjusterChanged (this, t.value[0], t.value[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* For better readability, this method create the history string of the parameter column,
|
||||
* so that the parameters list can be read in a more logical way (i.e. corresponding
|
||||
* to the startAtOne field)
|
||||
*/
|
||||
Glib::ustring ThresholdAdjuster::getHistoryString () {
|
||||
if (tSelector.isDouble()) {
|
||||
Glib::ustring bl, tl, br, tr;
|
||||
tSelector.getPositions(bl, tl, br, tr);
|
||||
return Glib::ustring::compose(tSelector.isStartAtOne()?"%2, %1, %3, %4":"%1, %2, %4, %3", bl, tl, br, tr);
|
||||
}
|
||||
else {
|
||||
Glib::ustring b, t;
|
||||
tSelector.getPositions(b, t);
|
||||
return Glib::ustring::compose(tSelector.isStartAtOne()?"%2, %1":"%1, %2", b, t);
|
||||
}
|
||||
}
|
119
rtgui/thresholdadjuster.h
Normal file
119
rtgui/thresholdadjuster.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
#ifndef _THRESHOLDADJUSTER_H_
|
||||
#define _THRESHOLDADJUSTER_H_
|
||||
|
||||
#include <gtkmm.h>
|
||||
#include "editedstate.h"
|
||||
#include "guiutils.h"
|
||||
#include "thresholdselector.h"
|
||||
|
||||
class ThresholdAdjuster;
|
||||
|
||||
/*
|
||||
* TODO: Maybe we could just send back the history string instead of the individual values?
|
||||
*/
|
||||
class ThresholdAdjusterListener {
|
||||
|
||||
public:
|
||||
// to be used by listener that has created a ThresholdAdjuster with with single threshold and precision > 0
|
||||
virtual void adjusterChanged (ThresholdAdjuster* a, double newBottom, double newTop) {}
|
||||
// to be used by listener that has created a ThresholdAdjuster with with double threshold and precision > 0
|
||||
virtual void adjusterChanged (ThresholdAdjuster* a, double newBottomLeft, double newTopLeft, double newBottomRight, double newTopRight) {}
|
||||
// to be used by listener that has created a ThresholdAdjuster with with single threshold and precision == 0
|
||||
virtual void adjusterChanged (ThresholdAdjuster* a, int newBottom, int newTop) {}
|
||||
// to be used by listener that has created a ThresholdAdjuster with with double threshold and precision == 0
|
||||
virtual void adjusterChanged (ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight) {}
|
||||
};
|
||||
|
||||
|
||||
class ThresholdAdjuster : public Gtk::VBox {
|
||||
|
||||
protected:
|
||||
Gtk::HBox* hbox;
|
||||
Gtk::Label* label;
|
||||
ThresholdSelector tSelector;
|
||||
//MySpinButton* spin;
|
||||
Gtk::Button* reset;
|
||||
ThresholdAdjusterListener* adjusterListener;
|
||||
sigc::connection delayConnection;
|
||||
//sigc::connection spinChange;
|
||||
sigc::connection selectorChange;
|
||||
sigc::connection editedChange;
|
||||
bool listenerReady;
|
||||
double initialDefaultVal[4]; // default value at construction time
|
||||
EditedState editedState;
|
||||
EditedState defEditedState;
|
||||
Gtk::CheckButton* editedCheckBox;
|
||||
bool afterReset;
|
||||
bool blocked;
|
||||
bool addMode;
|
||||
int delay;
|
||||
|
||||
double shapeValue (double a);
|
||||
void refreshLabelStyle ();
|
||||
void initObject (Glib::ustring label, bool editedcb);
|
||||
void sendToListener ();
|
||||
|
||||
public:
|
||||
|
||||
ThresholdAdjuster (Glib::ustring label, double minValue, double maxValue, double defBottom,
|
||||
double defTop, unsigned int precision, bool startAtOne, bool editedCheckBox=false);
|
||||
ThresholdAdjuster (Glib::ustring label, double minValue, double maxValue, double defBottomLeft,
|
||||
double defTopLeft, double defBottomRight, double defTopRight, unsigned int precision,
|
||||
bool startAtOne, bool editedCheckBox=false);
|
||||
|
||||
virtual ~ThresholdAdjuster ();
|
||||
void setAdjusterListener (ThresholdAdjusterListener* alistener) { adjusterListener = alistener; }
|
||||
|
||||
template <typename T>
|
||||
rtengine::procparams::Threshold<T> getValue () { return tSelector.getPositions<T>(); }
|
||||
void getValue (double& bottom, double& top);
|
||||
void getValue (double& bottomLeft, double& topLeft, double& bottomRight, double& topRight);
|
||||
void getValue (int& bottom, int& top);
|
||||
void getValue (int& bottomLeft, int& topLeft, int& bottomRight, int& topRight);
|
||||
void getValue (Glib::ustring& bottom, Glib::ustring& top);
|
||||
void getValue (Glib::ustring& bottomLeft, Glib::ustring& topLeft, Glib::ustring& bottomRight, Glib::ustring& topRight);
|
||||
template <class T>
|
||||
void setValue (const rtengine::procparams::Threshold<T> &tValues) {
|
||||
tSelector.setPositions<T>(tValues);
|
||||
}
|
||||
void setValue (double bottom, double top);
|
||||
void setValue (double bottomLeft, double topLeft, double bottomRight, double topRight);
|
||||
void setEnabled (bool enabled);
|
||||
template <typename T>
|
||||
void setDefault (const rtengine::procparams::Threshold<T> &tresh) { tSelector.setDefaults<T>(tresh); }
|
||||
void setDefault (double defBottom, double defTop);
|
||||
void setDefault (double defBottomLeft, double defTopLeft, double defBottomRight, double defTopRight);
|
||||
void setEditedState (EditedState eState);
|
||||
EditedState getEditedState ();
|
||||
void setDefaultEditedState (EditedState eState);
|
||||
void showEditedCB ();
|
||||
void block(bool isBlocked) { blocked = isBlocked; }
|
||||
void setBgGradient (const std::vector<GradientMilestone> &milestones) { tSelector.setBgGradient (milestones); }
|
||||
|
||||
//void spinChanged ();
|
||||
void selectorChanged ();
|
||||
bool notifyListener ();
|
||||
void resetPressed (GdkEventButton* event);
|
||||
void editedToggled ();
|
||||
Glib::ustring getHistoryString ();
|
||||
};
|
||||
|
||||
#endif
|
570
rtgui/thresholdselector.cc
Normal file
570
rtgui/thresholdselector.cc
Normal file
@@ -0,0 +1,570 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "thresholdselector.h"
|
||||
#include "multilangmgr.h"
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#include "mycurve.h"
|
||||
|
||||
ThresholdSelector::ThresholdSelector(double minValue, double maxValue, double defBottom, double defTop, unsigned int precision, bool startAtOne) {
|
||||
positions[TS_BOTTOMLEFT] = defPos[TS_BOTTOMLEFT] = defBottom;
|
||||
positions[TS_TOPLEFT] = defPos[TS_TOPLEFT] = defTop;
|
||||
positions[TS_BOTTOMRIGHT] = defPos[TS_BOTTOMRIGHT] = maxValue;
|
||||
positions[TS_TOPRIGHT] = defPos[TS_TOPRIGHT] = maxValue;
|
||||
this->precision = precision;
|
||||
doubleThresh = false;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (startAtOne) {
|
||||
assert (defBottom >= defTop);
|
||||
assert (defTop >= minValue);
|
||||
assert (defBottom <= maxValue);
|
||||
}
|
||||
else {
|
||||
assert (defTop >= defBottom);
|
||||
assert (defBottom >= minValue);
|
||||
assert (defTop <= maxValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
initValues (minValue, maxValue, startAtOne);
|
||||
}
|
||||
|
||||
ThresholdSelector::ThresholdSelector(double minValue, double maxValue, double defBottomLeft, double defTopLeft, double defBottomRight, double defTopRight, unsigned int precision, bool startAtOne) {
|
||||
positions[TS_BOTTOMLEFT] = defPos[TS_BOTTOMLEFT] = defBottomLeft;
|
||||
positions[TS_TOPLEFT] = defPos[TS_TOPLEFT] = defTopLeft;
|
||||
positions[TS_BOTTOMRIGHT] = defPos[TS_BOTTOMRIGHT] = defBottomRight;
|
||||
positions[TS_TOPRIGHT] = defPos[TS_TOPRIGHT] = defTopRight;
|
||||
this->precision = precision;
|
||||
doubleThresh = true;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (startAtOne) {
|
||||
assert (minValue <= defTopLeft);
|
||||
assert (defTopLeft <= defBottomLeft);
|
||||
assert (defBottomLeft <= defBottomRight);
|
||||
assert (defBottomRight <= defTopRight);
|
||||
assert (defTopRight <= maxValue);
|
||||
}
|
||||
else {
|
||||
assert (minValue <= defBottomLeft);
|
||||
assert (defBottomLeft <= defTopLeft);
|
||||
assert (defTopLeft <= defTopRight);
|
||||
assert (defTopRight <= defBottomRight);
|
||||
assert (defBottomRight <= maxValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
initValues (minValue, maxValue, startAtOne);
|
||||
}
|
||||
|
||||
void ThresholdSelector::initValues (double minValue, double maxValue, bool startAtOne) {
|
||||
assert(minValue <= maxValue);
|
||||
initalEq1 = startAtOne;
|
||||
minVal = minValue;
|
||||
maxVal = maxValue;
|
||||
oldLitCursor = litCursor = TS_UNDEFINED;
|
||||
movedCursor = TS_UNDEFINED;
|
||||
secondaryMovedCursor = TS_UNDEFINED;
|
||||
set_size_request (-1, 20);
|
||||
add_events(Gdk::LEAVE_NOTIFY_MASK);
|
||||
set_name("ThresholdSelector");
|
||||
set_can_focus(false);
|
||||
set_app_paintable(true);
|
||||
updateTooltip();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the position of the sliders without telling it to the listener
|
||||
*/
|
||||
void ThresholdSelector::setPositions (double bottom, double top) {
|
||||
|
||||
setPositions(bottom, top, maxVal, maxVal);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the position of the sliders without telling it to the listener
|
||||
*/
|
||||
void ThresholdSelector::setPositions (double bottomLeft, double topLeft, double bottomRight, double topRight) {
|
||||
|
||||
bool different = ( (positions[TS_TOPLEFT] != topLeft) || (positions[TS_TOPRIGHT] != topRight) ||
|
||||
(positions[TS_BOTTOMLEFT] != bottomLeft) || (positions[TS_BOTTOMRIGHT] != bottomRight) );
|
||||
positions[TS_BOTTOMLEFT] = bottomLeft;
|
||||
positions[TS_TOPLEFT] = topLeft;
|
||||
positions[TS_BOTTOMRIGHT] = bottomRight;
|
||||
positions[TS_TOPRIGHT] = topRight;
|
||||
|
||||
if (different) {
|
||||
sig_val_changed.emit();
|
||||
updateTooltip();
|
||||
queue_draw ();
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdSelector::setDefaults (double bottom, double top) {
|
||||
|
||||
setDefaults(bottom, top, maxVal, maxVal);
|
||||
}
|
||||
|
||||
void ThresholdSelector::setDefaults (double bottomLeft, double topLeft, double bottomRight, double topRight) {
|
||||
|
||||
defPos[TS_BOTTOMLEFT] = bottomLeft;
|
||||
defPos[TS_TOPLEFT] = topLeft;
|
||||
if (doubleThresh) {
|
||||
defPos[TS_BOTTOMRIGHT] = bottomRight;
|
||||
defPos[TS_TOPRIGHT] = topRight;
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdSelector::getPositions (Glib::ustring& bottom, Glib::ustring& top) {
|
||||
|
||||
|
||||
bottom = Glib::ustring::format(std::fixed, std::setprecision(precision),positions[TS_BOTTOMLEFT]);
|
||||
top = Glib::ustring::format(std::fixed, std::setprecision(precision),positions[TS_TOPLEFT]);
|
||||
}
|
||||
|
||||
void ThresholdSelector::getPositions (Glib::ustring& bottomLeft, Glib::ustring& topLeft, Glib::ustring& bottomRight, Glib::ustring& topRight) {
|
||||
|
||||
bottomLeft = Glib::ustring::format(std::fixed, std::setprecision(precision),positions[TS_BOTTOMLEFT]);
|
||||
topLeft = Glib::ustring::format(std::fixed, std::setprecision(precision),positions[TS_TOPLEFT]);
|
||||
bottomRight = Glib::ustring::format(std::fixed, std::setprecision(precision),positions[TS_BOTTOMRIGHT]);
|
||||
topRight = Glib::ustring::format(std::fixed, std::setprecision(precision),positions[TS_TOPRIGHT]);
|
||||
}
|
||||
|
||||
void ThresholdSelector::setBgGradient (const std::vector<GradientMilestone> &milestones) {
|
||||
bgGradient.clear();
|
||||
bgGradient = milestones;
|
||||
}
|
||||
|
||||
void ThresholdSelector::on_realize() {
|
||||
|
||||
Gtk::DrawingArea::on_realize();
|
||||
|
||||
add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
|
||||
}
|
||||
|
||||
bool ThresholdSelector::on_expose_event(GdkEventExpose* event) {
|
||||
|
||||
Gdk::Color c;
|
||||
Glib::RefPtr<Gdk::Window> win = get_window();
|
||||
Cairo::RefPtr<Cairo::Context> cr = win->create_cairo_context();
|
||||
|
||||
double positions01[4];
|
||||
int w = get_width ();
|
||||
int h = get_height ();
|
||||
|
||||
wslider = std::max(int(h / 5), 10);
|
||||
int hwslider = wslider/2;
|
||||
|
||||
int iw = w-wslider-2*hb; // inner width (excluding padding for tabs)
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
positions01[i] = to01(positions[i]);
|
||||
}
|
||||
|
||||
Gtk::StateType state = !is_sensitive() ? Gtk::STATE_INSENSITIVE : Gtk::STATE_NORMAL;
|
||||
Glib::RefPtr<Gtk::Style> style = get_style();
|
||||
|
||||
// set the box's colors
|
||||
cr->set_line_width (1.0);
|
||||
cr->set_line_cap(Cairo::LINE_CAP_BUTT);
|
||||
if (is_sensitive() && bgGradient.size()>1) {
|
||||
// gradient background
|
||||
Cairo::RefPtr< Cairo::LinearGradient > bggradient = Cairo::LinearGradient::create (hwslider, 0, hwslider+iw, 0);
|
||||
for (std::vector<GradientMilestone>::iterator i=bgGradient.begin(); i!=bgGradient.end(); i++) {
|
||||
bggradient->add_color_stop_rgb (i->position, i->r, i->g, i->b);
|
||||
}
|
||||
cr->set_source (bggradient);
|
||||
|
||||
// draw the box's background
|
||||
cr->rectangle (hb+hwslider-0.5, double(int(float(h)*1.5f/7.f))+0.5, iw+1, double(int(float(h)*4.f/7.f)));
|
||||
cr->fill();
|
||||
}
|
||||
else if (is_sensitive()) {
|
||||
// solid background
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.85, c.get_green_p()*0.85, c.get_blue_p()*0.85);
|
||||
|
||||
// draw the box's background
|
||||
cr->rectangle (hb+hwslider-0.5, double(int(float(h)*1.5f/7.f))+0.5, iw+1, double(int(float(h)*4.f/7.f)));
|
||||
cr->fill();
|
||||
}
|
||||
|
||||
// draw curve
|
||||
double yStart = initalEq1 ? double(int(float(h)*1.5f/7.f))+1.5 : double(int(float(h)*5.5f/7.f))-0.5;
|
||||
double yEnd = initalEq1 ? double(int(float(h)*5.5f/7.f))-0.5 : double(int(float(h)*1.5f/7.f))+1.5;
|
||||
ThreshCursorId p[4];
|
||||
if (initalEq1) { p[0] = TS_TOPLEFT; p[1] = TS_BOTTOMLEFT; p[2] = TS_BOTTOMRIGHT; p[3] = TS_TOPRIGHT; }
|
||||
else { p[0] = TS_BOTTOMLEFT; p[1] = TS_TOPLEFT; p[2] = TS_TOPRIGHT; p[3] = TS_BOTTOMRIGHT; }
|
||||
if (positions[p[1]] > minVal)
|
||||
cr->move_to (hb+hwslider, yStart);
|
||||
else
|
||||
cr->move_to (hb+hwslider, yEnd);
|
||||
if (positions[p[0]] > minVal)
|
||||
cr->line_to (hb+hwslider+iw*positions01[p[0]]+0.5, yStart);
|
||||
if (positions[p[1]] > minVal)
|
||||
cr->line_to (hb+hwslider+iw*positions01[p[1]]+0.5, yEnd);
|
||||
cr->line_to (hb+hwslider+iw*positions01[p[2]]+0.5, yEnd);
|
||||
if (doubleThresh && positions[p[2]] < maxVal) {
|
||||
cr->line_to (hb+hwslider+iw*positions01[p[3]]+0.5, yStart);
|
||||
if (positions[p[3]] < maxVal)
|
||||
cr->line_to (hb+hwslider+iw+0.5, yStart);
|
||||
}
|
||||
if (is_sensitive() && bgGradient.size()>1) {
|
||||
// draw surrounding curve
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.85, c.get_green_p()*0.85, c.get_blue_p()*0.85);
|
||||
cr->set_line_width (5.0);
|
||||
cr->stroke_preserve();
|
||||
}
|
||||
// draw curve
|
||||
if (is_sensitive()) {
|
||||
c = style->get_fg (movedCursor!=TS_UNDEFINED || litCursor!=TS_UNDEFINED ? Gtk::STATE_PRELIGHT : Gtk::STATE_ACTIVE);
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
}
|
||||
else {
|
||||
c = style->get_bg (Gtk::STATE_INSENSITIVE);
|
||||
cr->set_source_rgb (c.get_red_p()*0.7, c.get_green_p()*0.7, c.get_blue_p()*0.7);
|
||||
}
|
||||
cr->set_line_width (1.5);
|
||||
cr->stroke ();
|
||||
|
||||
// draw the box's borders
|
||||
cr->set_line_width (1.);
|
||||
cr->rectangle (hb+hwslider-0.5, double(int(float(h)*1.5f/7.f))+0.5, iw+1, double(int(float(h)*4.f/7.f)));
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.7, c.get_green_p()*0.7, c.get_blue_p()*0.7);
|
||||
cr->stroke ();
|
||||
|
||||
// draw sliders
|
||||
//if (!(litCursor == TS_UNDEFINED && movedCursor == TS_UNDEFINED)) {
|
||||
cr->set_line_width (1.);
|
||||
for (int i=0; i<(doubleThresh?4:2); i++) {
|
||||
double posX = hb+hwslider+iw*positions01[i]+0.5;
|
||||
double arrowY = i==0 || i==2 ? h-(h*2.5/7.-0.5)-vb : h*2.5/7.-0.5+vb;
|
||||
double baseY = i==0 || i==2 ? h-0.5-vb : 0.5+vb;
|
||||
double centerY = (arrowY+baseY)/2.;
|
||||
cr->move_to (posX, arrowY);
|
||||
cr->line_to (posX+hwslider, centerY);
|
||||
cr->line_to (posX+hwslider, baseY);
|
||||
cr->line_to (posX-hwslider, baseY);
|
||||
cr->line_to (posX-hwslider, centerY);
|
||||
cr->close_path();
|
||||
if (i==movedCursor) {
|
||||
// moved (selected)
|
||||
c = style->get_bg (Gtk::STATE_SELECTED);
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
cr->fill_preserve ();
|
||||
//c = style->get_dark (Gtk::STATE_SELECTED);
|
||||
//cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.55, c.get_green_p()*0.55, c.get_blue_p()*0.55);
|
||||
cr->stroke ();
|
||||
}
|
||||
else if (i==secondaryMovedCursor || (movedCursor==TS_UNDEFINED && i==litCursor)) {
|
||||
// prelight
|
||||
c = style->get_bg (Gtk::STATE_PRELIGHT);
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
cr->fill_preserve ();
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.55, c.get_green_p()*0.55, c.get_blue_p()*0.55);
|
||||
cr->stroke ();
|
||||
}
|
||||
else {
|
||||
// normal
|
||||
c = style->get_bg (is_sensitive() ? Gtk::STATE_ACTIVE : Gtk::STATE_INSENSITIVE);
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
cr->fill_preserve ();
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.7, c.get_green_p()*0.7, c.get_blue_p()*0.7);
|
||||
cr->stroke ();
|
||||
}
|
||||
}
|
||||
//}
|
||||
//printf("\n\n");
|
||||
|
||||
// draw text for the slider that is being moved
|
||||
/*
|
||||
* Original code from shcselector.cc
|
||||
*
|
||||
Glib::RefPtr<Pango::Context> context = get_pango_context () ;
|
||||
cr->set_line_width (0.5);
|
||||
if (litCursor != TS_UNDEFINED) {
|
||||
int offset;
|
||||
int layout_width, layout_height;
|
||||
Glib::RefPtr<Pango::Layout> layout = create_pango_layout(Glib::ustring::format(std::setprecision(2), positions01[litCursor]));
|
||||
layout->get_pixel_size(layout_width, layout_height);
|
||||
offset = positions01[litCursor] > 0.5 ? -layout_width-1-wslider/2 : 1+wslider/2;
|
||||
cr->move_to (w*positions01[litCursor]+offset-0.5, 0);
|
||||
cr->set_source_rgb (bgnc.get_red_p(), bgnc.get_green_p(), bgnc.get_blue_p());
|
||||
layout->add_to_cairo_context (cr);
|
||||
cr->fill_preserve ();
|
||||
cr->stroke ();
|
||||
cr->move_to (w*positions01[litCursor]+offset+0.5, 1);
|
||||
layout->add_to_cairo_context (cr);
|
||||
cr->fill_preserve ();
|
||||
cr->stroke ();
|
||||
cr->set_source_rgb (fgnc.get_red_p(), fgnc.get_green_p(), fgnc.get_blue_p());
|
||||
cr->move_to (w*positions01[litCursor]+offset, 0.5);
|
||||
layout->add_to_cairo_context (cr);
|
||||
cr->fill_preserve ();
|
||||
cr->stroke ();
|
||||
}*/
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThresholdSelector::on_button_press_event (GdkEventButton* event) {
|
||||
|
||||
if (event->button == 1) {
|
||||
movedCursor = litCursor;
|
||||
findSecondaryMovedCursor(event->state);
|
||||
tmpX = event->x;
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
grab_focus();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThresholdSelector::on_button_release_event (GdkEventButton* event) {
|
||||
|
||||
if (event->button == 1) {
|
||||
findLitCursor(event->x, event->y);
|
||||
movedCursor = TS_UNDEFINED;
|
||||
secondaryMovedCursor = TS_UNDEFINED;
|
||||
queue_draw ();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThresholdSelector::on_leave_notify_event (GdkEventCrossing* event) {
|
||||
if (movedCursor == TS_UNDEFINED) {
|
||||
litCursor = TS_UNDEFINED;
|
||||
oldLitCursor = TS_UNDEFINED;
|
||||
queue_draw();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThresholdSelector::on_motion_notify_event (GdkEventMotion* event) {
|
||||
|
||||
int w = get_width ();
|
||||
|
||||
findLitCursor(event->x, event->y);
|
||||
|
||||
if (movedCursor != TS_UNDEFINED) {
|
||||
// user is moving a cursor or two
|
||||
double minBound, maxBound;
|
||||
|
||||
findSecondaryMovedCursor(event->state);
|
||||
|
||||
// computing the boundaries
|
||||
findBoundaries(minBound, maxBound);
|
||||
|
||||
double dX = ( (event->x-tmpX)*(maxVal-minVal) )/( w-2*hb );
|
||||
// slow motion if CTRL is pressed
|
||||
if (event->state & Gdk::CONTROL_MASK)
|
||||
dX *= 0.05;
|
||||
|
||||
// get the new X value, inside bounds
|
||||
double newX = positions[movedCursor] + dX;
|
||||
|
||||
if (newX > maxBound) newX = maxBound;
|
||||
else if (newX < minBound) newX = minBound;
|
||||
|
||||
// compute the effective dX
|
||||
dX = newX - positions[movedCursor];
|
||||
// set the new position of the moved cursor
|
||||
positions[movedCursor] = newX;
|
||||
|
||||
// apply the decay to the secondary moved cursor, if necessary
|
||||
if (secondaryMovedCursor != TS_UNDEFINED) {
|
||||
positions[secondaryMovedCursor] += dX;
|
||||
}
|
||||
|
||||
// set the new reference value for the next move
|
||||
tmpX = event->x;
|
||||
|
||||
// update the tooltip
|
||||
updateTooltip();
|
||||
|
||||
sig_val_changed.emit();
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
else {
|
||||
if (litCursor != oldLitCursor)
|
||||
queue_draw ();
|
||||
oldLitCursor = litCursor;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ThresholdSelector::findLitCursor(int posX, int posY) {
|
||||
int w = get_width ();
|
||||
int h = get_height ();
|
||||
|
||||
litCursor = TS_UNDEFINED;
|
||||
if (posY >=0 && posY <= h/2) {
|
||||
if (posX > 0 && posX < w) {
|
||||
litCursor = TS_TOPLEFT;
|
||||
|
||||
if (doubleThresh) {
|
||||
double cursorX = (posX-hb)*(maxVal-minVal)/(w-2*hb)+minVal;
|
||||
|
||||
if (cursorX>positions[TS_TOPRIGHT] || abs(cursorX-positions[TS_TOPRIGHT]) < abs(cursorX-positions[TS_TOPLEFT]))
|
||||
litCursor = TS_TOPRIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (posY > h/2 && posY < h) {
|
||||
if (posX > 0 && posX < w) {
|
||||
litCursor = TS_BOTTOMLEFT;
|
||||
if (doubleThresh) {
|
||||
double cursorX = (posX-hb)*(maxVal-minVal)/(w-2*hb)+minVal;
|
||||
|
||||
if (cursorX>positions[TS_BOTTOMRIGHT] || abs(cursorX-positions[TS_BOTTOMRIGHT]) < abs(cursorX-positions[TS_BOTTOMLEFT]))
|
||||
litCursor = TS_BOTTOMRIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdSelector::findBoundaries(double &min, double &max) {
|
||||
|
||||
switch (movedCursor) {
|
||||
case (TS_BOTTOMLEFT):
|
||||
if (initalEq1) {
|
||||
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPLEFT] : minVal+(positions[TS_BOTTOMLEFT]-positions[TS_TOPLEFT]);
|
||||
max = positions[TS_BOTTOMRIGHT];
|
||||
}
|
||||
else {
|
||||
min = minVal;
|
||||
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPLEFT] : positions[TS_TOPRIGHT]-(positions[TS_TOPLEFT]-positions[TS_BOTTOMLEFT]);
|
||||
}
|
||||
break;
|
||||
case (TS_TOPLEFT):
|
||||
if (initalEq1) {
|
||||
min = minVal;
|
||||
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMLEFT] : positions[TS_BOTTOMRIGHT]-(positions[TS_BOTTOMLEFT]-positions[TS_TOPLEFT]);
|
||||
}
|
||||
else {
|
||||
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMLEFT] : minVal+(positions[TS_TOPLEFT]-positions[TS_BOTTOMLEFT]);
|
||||
max = positions[TS_TOPRIGHT];
|
||||
}
|
||||
break;
|
||||
case (TS_BOTTOMRIGHT):
|
||||
if (initalEq1) {
|
||||
min = positions[TS_BOTTOMLEFT];
|
||||
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPRIGHT] : maxVal-(positions[TS_TOPRIGHT]-positions[TS_BOTTOMRIGHT]);
|
||||
}
|
||||
else {
|
||||
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPRIGHT] : positions[TS_TOPLEFT]+(positions[TS_BOTTOMRIGHT]-positions[TS_TOPRIGHT]);
|
||||
max = maxVal;
|
||||
}
|
||||
break;
|
||||
case (TS_TOPRIGHT):
|
||||
if (initalEq1) {
|
||||
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMRIGHT] : positions[TS_BOTTOMLEFT]+(positions[TS_TOPRIGHT]-positions[TS_BOTTOMRIGHT]);
|
||||
max = maxVal;
|
||||
}
|
||||
else {
|
||||
min = positions[TS_TOPLEFT];
|
||||
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMRIGHT] : maxVal-(positions[TS_BOTTOMRIGHT]-positions[TS_TOPRIGHT]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
min = minVal;
|
||||
max = maxVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdSelector::findSecondaryMovedCursor(guint state) {
|
||||
secondaryMovedCursor = TS_UNDEFINED;
|
||||
if (!(state & Gdk::SHIFT_MASK)) {
|
||||
switch (movedCursor) {
|
||||
case (TS_BOTTOMLEFT):
|
||||
secondaryMovedCursor = TS_TOPLEFT;
|
||||
break;
|
||||
case (TS_TOPLEFT):
|
||||
secondaryMovedCursor = TS_BOTTOMLEFT;
|
||||
break;
|
||||
case (TS_BOTTOMRIGHT):
|
||||
secondaryMovedCursor = TS_TOPRIGHT;
|
||||
break;
|
||||
case (TS_TOPRIGHT):
|
||||
secondaryMovedCursor = TS_BOTTOMRIGHT;
|
||||
break;
|
||||
default:
|
||||
secondaryMovedCursor = TS_UNDEFINED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdSelector::styleChanged (const Glib::RefPtr<Gtk::Style>& style) {
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
void ThresholdSelector::reset () {
|
||||
|
||||
positions[0] = defPos[0];
|
||||
positions[1] = defPos[1];
|
||||
positions[2] = defPos[2];
|
||||
positions[2] = defPos[3];
|
||||
updateTooltip();
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
inline double ThresholdSelector::to01(double value) {
|
||||
|
||||
double rVal = (value-minVal)/(maxVal-minVal);
|
||||
if (rVal < 0.) rVal = 0.;
|
||||
else if (rVal > 1.) rVal = 1.;
|
||||
return rVal;
|
||||
}
|
||||
|
||||
void ThresholdSelector::updateTooltip() {
|
||||
|
||||
Glib::ustring tTip;
|
||||
if (doubleThresh)
|
||||
tTip = Glib::ustring::compose("<b>%1:</b> %2 <b>%3:</b> %4\n<b>%5:</b> %6 <b>%7:</b> %8\n%9",
|
||||
M("THRESHOLDSELECTOR_TL"), Glib::ustring::format(std::fixed, std::setprecision(precision), positions[TS_TOPLEFT]),
|
||||
M("THRESHOLDSELECTOR_TR"), Glib::ustring::format(std::fixed, std::setprecision(precision), positions[TS_TOPRIGHT]),
|
||||
M("THRESHOLDSELECTOR_BL"), Glib::ustring::format(std::fixed, std::setprecision(precision), positions[TS_BOTTOMLEFT]),
|
||||
M("THRESHOLDSELECTOR_BR"), Glib::ustring::format(std::fixed, std::setprecision(precision), positions[TS_BOTTOMRIGHT]),
|
||||
M("THRESHOLDSELECTOR_HINT")
|
||||
);
|
||||
else
|
||||
tTip = Glib::ustring::compose("<b>%1:</b> %2\n<b>%3:</b> %4\n%5",
|
||||
M("THRESHOLDSELECTOR_T"), Glib::ustring::format(std::fixed, std::setprecision(precision), positions[TS_TOPLEFT]),
|
||||
M("THRESHOLDSELECTOR_B"), Glib::ustring::format(std::fixed, std::setprecision(precision), positions[TS_BOTTOMLEFT]),
|
||||
M("THRESHOLDSELECTOR_HINT")
|
||||
);
|
||||
set_tooltip_markup(tTip);
|
||||
}
|
||||
|
||||
sigc::signal<void> ThresholdSelector::signal_value_changed() {
|
||||
return sig_val_changed;
|
||||
}
|
161
rtgui/thresholdselector.h
Normal file
161
rtgui/thresholdselector.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
#ifndef _THRESHOLDSELECTOR_
|
||||
#define _THRESHOLDSELECTOR_
|
||||
|
||||
#include "guiutils.h"
|
||||
#include "../rtengine/procparams.h"
|
||||
|
||||
/*
|
||||
* This widget will let you select a linearly variable threshold, creating a ramp up
|
||||
* if you want to go from a null effect to a full effect
|
||||
* 0-0-ramp up-1-1
|
||||
* or a ramp down if you want the contrary
|
||||
* 1-1-ramp down-0-0
|
||||
*
|
||||
* You can optionally create a double threshold
|
||||
* 0-0-ramp up-1-1-ramp down-0-0
|
||||
* or
|
||||
* 1-1-ramp down-0-0-ramp up-1-1
|
||||
*
|
||||
* Please note that the values are related to the cursors, depending on their position
|
||||
* on the graph. E.g. the "bottomLeft" value is related to the bottom left cursor.
|
||||
*/
|
||||
class ThresholdSelector : public Gtk::DrawingArea {
|
||||
|
||||
public:
|
||||
|
||||
enum ThreshCursorId {
|
||||
TS_UNDEFINED=-1,
|
||||
TS_BOTTOMLEFT,
|
||||
TS_TOPLEFT,
|
||||
TS_BOTTOMRIGHT,
|
||||
TS_TOPRIGHT
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
sigc::signal<void> sig_val_changed;
|
||||
|
||||
Glib::RefPtr<Gdk::GC> gc_;
|
||||
Glib::RefPtr<Gdk::Pixmap> backBuffer;
|
||||
std::vector<GradientMilestone> bgGradient;
|
||||
|
||||
bool doubleThresh; // If true: there curve is a double threshold (0 to 1 to 0, or 1 to 0 to 1).
|
||||
bool initalEq1; // If true: the curve start at 1 (top); if false: the curve start at 0 (bottom)
|
||||
unsigned int precision; // Decimal number if this object has to handle "double" values
|
||||
ThreshCursorId litCursor;
|
||||
ThreshCursorId oldLitCursor;
|
||||
double boundary1[2], boundary2[2];
|
||||
double tmpX, tmpPos;
|
||||
|
||||
ThreshCursorId movedCursor, secondaryMovedCursor;
|
||||
double minVal, maxVal;
|
||||
double defPos[4];
|
||||
double positions[4];
|
||||
unsigned short wslider;
|
||||
|
||||
const static int hb = 3; // horizontal border
|
||||
const static int vb = 2; // vertical border
|
||||
|
||||
void initValues (double minValue, double maxValue, bool startAtOne);
|
||||
void findLitCursor(int posX, int posY);
|
||||
void findSecondaryMovedCursor(guint state);
|
||||
void findBoundaries(double &min, double &max);
|
||||
double to01(double value);
|
||||
void updateTooltip();
|
||||
|
||||
public:
|
||||
|
||||
sigc::signal<void> signal_value_changed();
|
||||
|
||||
ThresholdSelector(double minValue, double maxValue, double defBottom, double defTop, unsigned int precision, bool startAtOne);
|
||||
ThresholdSelector(double minValue, double maxValue, double defBottomLeft, double defTopLeft, double defBottomRight, double defTopRight, unsigned int precision, bool startAtOne);
|
||||
|
||||
double shapeValue (double value) { return round(value*pow(double(10), precision)) / pow(double(10), precision); }
|
||||
|
||||
template <typename T>
|
||||
void setDefaults (const rtengine::procparams::Threshold<T> &t) {
|
||||
defPos[TS_BOTTOMLEFT] = double(t.value[0]); // should we use shapeValue() ?
|
||||
defPos[TS_TOPLEFT] = double(t.value[1]);
|
||||
if (doubleThresh) {
|
||||
defPos[TS_BOTTOMRIGHT] = double(t.value[2]);
|
||||
defPos[TS_TOPRIGHT] = double(t.value[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void setDefaults (double bottom, double top);
|
||||
void setDefaults (double bottomLeft, double topLeft, double bottomRight, double topRight);
|
||||
|
||||
template <typename T>
|
||||
void setPositions (const rtengine::procparams::Threshold<T> &tValues) {
|
||||
positions[TS_BOTTOMLEFT] = static_cast<double>(tValues.value[TS_BOTTOMLEFT]);
|
||||
positions[TS_TOPLEFT] = static_cast<double>(tValues.value[TS_TOPLEFT]);
|
||||
if (tValues.isDouble()) {
|
||||
positions[TS_BOTTOMRIGHT] = static_cast<double>(tValues.value[TS_BOTTOMRIGHT]);
|
||||
positions[TS_TOPRIGHT] = static_cast<double>(tValues.value[TS_TOPRIGHT]);
|
||||
}
|
||||
updateTooltip();
|
||||
queue_draw();
|
||||
}
|
||||
void setPositions (double bottom, double top);
|
||||
void setPositions (double bottomLeft, double topLeft, double bottomRight, double topRight);
|
||||
|
||||
template <typename T>
|
||||
rtengine::procparams::Threshold<T> getPositions () {
|
||||
if (doubleThresh) {
|
||||
rtengine::procparams::Threshold<T> rThresh(
|
||||
static_cast<T>(shapeValue(positions[TS_BOTTOMLEFT])),
|
||||
static_cast<T>(shapeValue(positions[TS_TOPLEFT])),
|
||||
static_cast<T>(shapeValue(positions[TS_BOTTOMRIGHT])),
|
||||
static_cast<T>(shapeValue(positions[TS_TOPRIGHT])),
|
||||
initalEq1
|
||||
);
|
||||
return rThresh;
|
||||
}
|
||||
else {
|
||||
rtengine::procparams::Threshold<T> rThresh(
|
||||
static_cast<T>(shapeValue(positions[TS_BOTTOMLEFT])),
|
||||
static_cast<T>(shapeValue(positions[TS_TOPLEFT])),
|
||||
initalEq1
|
||||
);
|
||||
return rThresh;
|
||||
}
|
||||
}
|
||||
|
||||
void getPositions (Glib::ustring& bottom, Glib::ustring& top);
|
||||
void getPositions (Glib::ustring& bottomLeft, Glib::ustring& topLeft, Glib::ustring& bottomRight, Glib::ustring& topRight);
|
||||
|
||||
void setBgGradient (const std::vector<GradientMilestone> &milestones);
|
||||
bool isStartAtOne() { return initalEq1; }
|
||||
bool isDouble() { return doubleThresh; }
|
||||
void on_realize ();
|
||||
bool on_expose_event(GdkEventExpose* event);
|
||||
bool on_button_press_event (GdkEventButton* event);
|
||||
bool on_button_release_event (GdkEventButton* event);
|
||||
bool on_motion_notify_event (GdkEventMotion* event);
|
||||
bool on_leave_notify_event (GdkEventCrossing* event);
|
||||
void styleChanged (const Glib::RefPtr<Gtk::Style>& style);
|
||||
unsigned int getPrecision () { return precision; }
|
||||
void reset ();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -327,6 +327,11 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh
|
||||
Glib::Mutex::Lock lock(mutex);
|
||||
#endif
|
||||
|
||||
if (pparams.sharpening.threshold.isDouble() != pp.sharpening.threshold.isDouble())
|
||||
printf("WARNING: Sharpening different!\n");
|
||||
if (pparams.vibrance.psthreshold.isDouble() != pp.vibrance.psthreshold.isDouble())
|
||||
printf("WARNING: Vibrance different!\n");
|
||||
|
||||
if (pparams!=pp)
|
||||
cfs.recentlySaved = false;
|
||||
|
||||
|
@@ -23,6 +23,7 @@ using namespace rtengine;
|
||||
using namespace rtengine::procparams;
|
||||
|
||||
Vibrance::Vibrance () : Gtk::VBox(), FoldableToolPanel(this) {
|
||||
|
||||
enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED")));
|
||||
enabled->set_active (false);
|
||||
pack_start(*enabled, Gtk::PACK_SHRINK, 0);
|
||||
@@ -38,7 +39,7 @@ Vibrance::Vibrance () : Gtk::VBox(), FoldableToolPanel(this) {
|
||||
//if (saturated->delay < 1000) saturated->delay = 1000;
|
||||
pack_start( *saturated, Gtk::PACK_SHRINK, 0);
|
||||
|
||||
psThreshold = Gtk::manage(new Adjuster (M("TP_VIBRANCE_PSTHRESHOLD"),0,100,5,75));
|
||||
psThreshold = Gtk::manage (new ThresholdAdjuster (M("TP_VIBRANCE_PSTHRESHOLD"), 0., 100., 75., 75., 0, false));
|
||||
psThreshold->setAdjusterListener (this);
|
||||
psThreshold->set_sensitive(false);
|
||||
//if (psThreshold->delay < 1000) psThreshold->delay = 1000;
|
||||
@@ -98,7 +99,7 @@ void Vibrance::read(const ProcParams* pp, const ParamsEdited* pedited) {
|
||||
lastPastSatTog = pp->vibrance.pastsattog;
|
||||
|
||||
pastels->setValue (pp->vibrance.pastels);
|
||||
psThreshold->setValue (pp->vibrance.psthreshold);
|
||||
psThreshold->setValue<int> (pp->vibrance.psthreshold);
|
||||
|
||||
if (lastPastSatTog) {
|
||||
// Link both slider, so we set saturated and psThresholds unsensitive
|
||||
@@ -120,7 +121,7 @@ void Vibrance::write( ProcParams* pp, ParamsEdited* pedited) {
|
||||
pp->vibrance.enabled = enabled->get_active ();
|
||||
pp->vibrance.pastels = pastels->getIntValue();
|
||||
pp->vibrance.saturated = pastSatTog->get_active() ? pp->vibrance.pastels : saturated->getIntValue ();
|
||||
pp->vibrance.psthreshold = psThreshold->getIntValue ();
|
||||
pp->vibrance.psthreshold = psThreshold->getValue<int> ();
|
||||
pp->vibrance.protectskins = protectSkins->get_active ();
|
||||
pp->vibrance.avoidcolorshift = avoidColorShift->get_active ();
|
||||
pp->vibrance.pastsattog = pastSatTog->get_active ();
|
||||
@@ -249,12 +250,16 @@ void Vibrance::adjusterChanged (Adjuster* a, double newval) {
|
||||
listener->panelChanged (EvVibrancePastels, value );
|
||||
else if (a == saturated && !pastSatTog->get_active())
|
||||
listener->panelChanged (EvVibranceSaturated, value );
|
||||
else if (a == psThreshold){
|
||||
listener->panelChanged (EvVibrancePastSatThreshold, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Vibrance::adjusterChanged (ThresholdAdjuster* a, int newBottom, int newTop) {
|
||||
if (listener && enabled->get_active()) {
|
||||
listener->panelChanged (EvVibrancePastSatThreshold, psThreshold->getHistoryString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Vibrance::setBatchMode(bool batchMode) {
|
||||
|
||||
ToolPanel::setBatchMode (batchMode);
|
||||
@@ -267,7 +272,7 @@ void Vibrance::setBatchMode(bool batchMode) {
|
||||
void Vibrance::setDefaults(const ProcParams* defParams, const ParamsEdited* pedited) {
|
||||
pastels->setDefault (defParams->vibrance.pastels);
|
||||
saturated->setDefault (defParams->vibrance.saturated);
|
||||
psThreshold->setDefault (defParams->vibrance.psthreshold);
|
||||
psThreshold->setDefault<int> (defParams->vibrance.psthreshold);
|
||||
|
||||
if (pedited) {
|
||||
pastels->setDefaultEditedState (pedited->vibrance.pastels ? Edited : UnEdited);
|
||||
@@ -284,11 +289,9 @@ void Vibrance::setDefaults(const ProcParams* defParams, const ParamsEdited* pedi
|
||||
void Vibrance::setAdjusterBehavior (bool pastelsadd, bool saturatedadd, bool psthreshdadd) {
|
||||
pastels->setAddMode (pastelsadd);
|
||||
saturated->setAddMode (saturatedadd);
|
||||
psThreshold->setAddMode (psthreshdadd);
|
||||
}
|
||||
|
||||
void Vibrance::trimValues (ProcParams* pp) {
|
||||
pastels->trimValue (pp->vibrance.pastels);
|
||||
saturated->trimValue (pp->vibrance.saturated);
|
||||
psThreshold->trimValue (pp->vibrance.psthreshold);
|
||||
}
|
||||
|
@@ -21,16 +21,16 @@
|
||||
|
||||
#include <gtkmm.h>
|
||||
#include "adjuster.h"
|
||||
//#include "guiutils.h"
|
||||
#include "thresholdadjuster.h"
|
||||
#include "toolpanel.h"
|
||||
|
||||
class Vibrance : public Gtk::VBox, public AdjusterListener, public FoldableToolPanel {
|
||||
class Vibrance : public Gtk::VBox, public AdjusterListener, public ThresholdAdjusterListener, public FoldableToolPanel {
|
||||
|
||||
protected:
|
||||
Gtk::CheckButton* enabled;
|
||||
Adjuster* pastels;
|
||||
Adjuster* saturated;
|
||||
Adjuster* psThreshold;
|
||||
ThresholdAdjuster* psThreshold;
|
||||
Gtk::CheckButton* protectSkins;
|
||||
Gtk::CheckButton* avoidColorShift;
|
||||
Gtk::CheckButton* pastSatTog;
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
void trimValues (rtengine::procparams::ProcParams* pp);
|
||||
void setAdjusterBehavior (bool amountadd, bool passadd, bool psthreshdadd);
|
||||
void adjusterChanged (Adjuster* a, double newval);
|
||||
void adjusterChanged (ThresholdAdjuster* a, int newBottom, int newTop);
|
||||
|
||||
void enabled_toggled ();
|
||||
void protectskins_toggled ();
|
||||
|
Reference in New Issue
Block a user