Solving issue 1444: " Better Vibrance tool's threshold handling"

This commit is contained in:
natureh
2012-07-03 23:49:45 +02:00
parent dba91ea39e
commit 02c12d5259
9 changed files with 446 additions and 148 deletions

View File

@@ -1064,7 +1064,10 @@ TP_VIBRANCE_LABEL;Vibrance
TP_VIBRANCE_PASTELS;Tons pastels
TP_VIBRANCE_PASTSATTOG;Lier Pastels et Saturés
TP_VIBRANCE_PROTECTSKINS;Protéger les tons chairs
TP_VIBRANCE_PSTHRESHOLD;Seuil différentiel entre Pastels/Saturés
TP_VIBRANCE_PSTHRESHOLD;Seuil entre tons pastels/saturés
TP_VIBRANCE_PSTHRESHOLD_SATTHRESH;Seuil de saturation
TP_VIBRANCE_PSTHRESHOLD_WEIGTHING;Pondération de la transition pastels/saturés
TP_VIBRANCE_PSTHRESHOLD_TOOLTIP;L'axe vertical represente les tons pastel en bas et le tons saturés en haut.\nL'axe horizontal represente l'échelle de la saturation.
TP_VIBRANCE_SATURATED;Tons saturés
TP_VIGNETTING_AMOUNT;Quantité
TP_VIGNETTING_CENTER;Centre

View File

@@ -1075,7 +1075,10 @@ TP_VIBRANCE_LABEL;Vibrance
TP_VIBRANCE_PASTELS;Pastel tones
TP_VIBRANCE_PASTSATTOG;Link pastel and saturated tones
TP_VIBRANCE_PROTECTSKINS;Protect skin tones
TP_VIBRANCE_PSTHRESHOLD;Pastel/Saturated tone differential threshold
TP_VIBRANCE_PSTHRESHOLD;Pastel/saturated tones threshold
TP_VIBRANCE_PSTHRESHOLD_SATTHRESH;Saturation threshold
TP_VIBRANCE_PSTHRESHOLD_WEIGTHING;Pastel/saturated transition's weighting
TP_VIBRANCE_PSTHRESHOLD_TOOLTIP;The vertical axis represents pastel tones at the bottom and saturated tones at the top.\nThe horizontal axis represents the saturation range.
TP_VIBRANCE_SATURATED;Saturated tones
TP_VIGNETTING_AMOUNT;Amount
TP_VIGNETTING_CENTER;Center

View File

@@ -2005,10 +2005,17 @@ void ImProcFunctions::vibrance (LabImage* lab) {
HH = new float[width*height];
*/
float chromaPastel = float(params->vibrance.pastels) / 100.0f;
float chromaSatur = float(params->vibrance.saturated) / 100.0f;
float limitpastelsatur = static_cast<float>(params->vibrance.psthreshold.value[ThresholdSelector::TS_TOPLEFT]) / 100.0f;
float transitionweighting = static_cast<float>(params->vibrance.psthreshold.value[ThresholdSelector::TS_BOTTOMLEFT]) / 100.0f;
bool highlight = params->hlrecovery.enabled;//Get the value if "highlight reconstruction" is activated
#ifdef _DEBUG
#pragma omp parallel default(shared) reduction(+: negat, moreRGB, negsat ,moresat, Munspb, Munsry, Munsgy, Munsrp, depass) if (multiThread)
#pragma omp parallel default(shared) firstprivate(lab, width, chromaPastel, chromaSatur, highlight, limitpastelsatur, transitionweighting) reduction(+: negat, moreRGB, negsat ,moresat, Munspb, Munsry, Munsgy, Munsrp, depass) if (multiThread)
#else
#pragma omp parallel default(shared) if (multiThread)
#pragma omp parallel default(shared) firstprivate(lab, width, chromaPastel, chromaSatur, highlight, limitpastelsatur, transitionweighting) if (multiThread)
#endif
{
@@ -2017,9 +2024,6 @@ void ImProcFunctions::vibrance (LabImage* lab) {
float fy,fx,fz,x_,y_,z_,Lprov,Lprov1,aprov1,bprov1,aprovn,bprovn,fxx,fyy,fzz,xx_,yy_,zz_;
float saturation;
TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working);
float chromaPastel= (float) params->vibrance.pastels / 100.0f;//
float chromaSatur = (float) params->vibrance.saturated / 100.0f;//
bool highlight = params->hlrecovery.enabled;//Get the value if "highlight reconstruction" is activated
//inverse matrix user select
double wip[3][3] = {
{wiprof[0][0],wiprof[0][1],wiprof[0][2]},
@@ -2030,26 +2034,16 @@ void ImProcFunctions::vibrance (LabImage* lab) {
float satredu;//reduct sat in function of skin
float sathue[5],sathue2[4];// adjust sat in function of hue
float correctionHue; // Munsell's correction
float limitpastelsatur;
float limitpastelsaturbottom;//TS_TOPRIGHT
int zone=0;
bool allwaysingamut=true;
// sur la ligne ci-dessous, on a acces aux valeurs du seuil via le champs 'value'
// psthreshold est un seuil simple commencant en bas, ce qui signifie que seuls TS_BOTTOMLEFT et TS_TOPLEFT
// sont exploitables
limitpastelsaturbottom=static_cast<float>(params->vibrance.psthreshold.value[ThresholdSelector::TS_BOTTOMLEFT]) / 100.0f;
limitpastelsatur=static_cast<float>(params->vibrance.psthreshold.value[ThresholdSelector::TS_TOPLEFT]) / 100.0f;
if (limitpastelsatur < 0.07) limitpastelsatur=0.07;
// if (limitpastelsaturbottom < 0.07) limitpastelsaturbottom=0.07;
// Fitting limitpastelsatur into the real 0.07->1.0 range
limitpastelsatur = limitpastelsatur*0.93f + 0.07f;
float p0,p1,p2;//adapt limit of pyramid to psThreshold
float s0,s1,s2;
float maxdp=(limitpastelsatur-0.07)/4.0;
// float maxdp=(limitpastelsaturbottom-0.07)/4.0;
float maxds=(1.0-limitpastelsatur)/4.0;
p0=0.07+maxdp;
p1=0.07+2.0*maxdp;
@@ -2058,8 +2052,25 @@ void ImProcFunctions::vibrance (LabImage* lab) {
s1=limitpastelsatur + 2.0*maxds;
s2=limitpastelsatur + 3.0*maxds;
float chromamean=0.;
if(chromaPastel != chromaSatur){
//if sliders pastels and saturated are different: transition with a double linear interpolation: between p2 and limitpastelsatur, and between limitpastelsatur and s0
//modify the "mean" point in function of double threshold => differential transition
chromamean = maxdp * (chromaSatur-chromaPastel) / (s0-p2) + chromaPastel;
// move chromaMean up or down depending on transitionCtrl
if (transitionweighting > 0.0) {
float _chromamean = chromamean;
chromamean = (chromaSatur-chromamean) * transitionweighting + chromamean;
}
else if (transitionweighting < 0.0) {
float _chromamean = chromamean;
chromamean = (chromamean-chromaPastel) * transitionweighting + chromamean;
}
}
if (settings->verbose) printf("vibrance: p0=%1.2f p1=%1.2f p2=%1.2f s0=%1.2f s1=%1.2f s2=%1.2f\n", p0,p1,p2,s0,s1,s2);
if (settings->verbose) printf("vibrance: pastel=%f satur=%f limit= %1.2f\n",1.0+chromaPastel,1.0+chromaSatur, limitpastelsatur);
if (settings->verbose) printf("vibrance: pastel=%f satur=%f limit= %1.2f chromamean=%0.5f \n",1.0+chromaPastel,1.0+chromaSatur, limitpastelsatur, chromamean);
#pragma omp for schedule(dynamic, 10)
for (int i=0; i<height; i++)
@@ -2214,21 +2225,21 @@ void ImProcFunctions::vibrance (LabImage* lab) {
else { pa=(chs2- chs3)/(s2-s3);pb=chs2-pa*s2; chmodsat = pa*saturation + pb; }
if(chromaPastel != chromaSatur){
//if sliders pastels and saturated differents: tansition with linear interpolation between p2 and s0
float chromaPastel_a, chromaPastel_b, chromamean, chromaSatur_a, chromaSatur_b, newchromaPastel, newchromaSatur;
//modify the "mean" point in function of double threshold => differential transition
chromamean = (chromaSatur*limitpastelsatur + chromaPastel*limitpastelsaturbottom)/(limitpastelsaturbottom+limitpastelsatur);
chromaPastel_a = (chromaPastel-chromamean)/(p2-limitpastelsatur);
chromaPastel_b = chromaPastel-chromaPastel_a*p2;
if(saturation > p2 && saturation < limitpastelsatur) {
newchromaPastel = chromaPastel_a*saturation + chromaPastel_b;
float chromaPastel_a = (chromaPastel-chromamean)/(p2-limitpastelsatur);
float chromaPastel_b = chromaPastel-chromaPastel_a*p2;
float newchromaPastel = chromaPastel_a*saturation + chromaPastel_b;
chmodpastel = newchromaPastel*satredu*sathue[3];
}
chromaSatur_a=(chromaSatur-chromamean)/(s0-limitpastelsatur);
chromaSatur_b=chromaSatur-chromaSatur_a*s0;
if(saturation < s0 && saturation >=limitpastelsatur) {newchromaSatur=chromaSatur_a*saturation + chromaSatur_b; chmodsat = newchromaSatur*satredu*sathue2[0];}
}// end transition
if(saturation < s0 && saturation >=limitpastelsatur) {
float chromaSatur_a=(chromaSatur-chromamean)/(s0-limitpastelsatur);
float chromaSatur_b=chromaSatur-chromaSatur_a*s0;
float newchromaSatur=chromaSatur_a*saturation + chromaSatur_b;
chmodsat = newchromaSatur*satredu*sathue2[0];
}
}// end transition
if (saturation <= limitpastelsatur) {
if(chmodpastel > 2.0 ) chmodpastel = 2.0; //avoid too big values
if(chmodpastel < -0.93) chmodpastel =-0.93; //avoid negative values

View File

@@ -27,6 +27,21 @@
#define MIN_RESET_BUTTON_HEIGHT 17
ThresholdAdjuster::ThresholdAdjuster (Glib::ustring label,
double minValueBottom, double maxValueBottom, double defBottom, Glib::ustring labelBottom, unsigned int precisionBottom,
double minValueTop, double maxValueTop, double defTop, Glib::ustring labelTop, unsigned int precisionTop,
ThresholdCurveProvider* curveProvider, bool editedCheckBox)
: tSelector(minValueBottom, maxValueBottom, defBottom, labelBottom, precisionBottom, minValueTop, maxValueTop, defTop, labelTop, precisionTop, curveProvider)
{
initialDefaultVal[ThresholdSelector::TS_BOTTOMLEFT] = defBottom;
initialDefaultVal[ThresholdSelector::TS_TOPLEFT] = defTop;
initialDefaultVal[ThresholdSelector::TS_BOTTOMRIGHT] = 0.; // unused
initialDefaultVal[ThresholdSelector::TS_TOPRIGHT] = 0.; // unused
initObject (label, editedCheckBox);
}
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)
@@ -196,11 +211,11 @@ void ThresholdAdjuster::setValue (double bottomLeft, double topLeft, double bott
afterReset = false;
}
void ThresholdAdjuster::getValue (Glib::ustring& bottom, Glib::ustring& top) {
inline 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) {
inline void ThresholdAdjuster::getValue (Glib::ustring& bottomLeft, Glib::ustring& topLeft, Glib::ustring& bottomRight, Glib::ustring& topRight) {
tSelector.getPositions (bottomLeft, topLeft, bottomRight, topRight);
}
@@ -213,6 +228,11 @@ bool ThresholdAdjuster::notifyListener () {
return false;
}
inline void ThresholdAdjuster::setBgCurveProvider (ThresholdCurveProvider* provider) {
tSelector.setBgCurveProvider(provider);
}
void ThresholdAdjuster::setEnabled (bool enabled) {
tSelector.set_sensitive (enabled);
@@ -283,9 +303,19 @@ void ThresholdAdjuster::sendToListener () {
}
}
void ThresholdAdjuster::set_tooltip_markup(const Glib::ustring& markup) {
tSelector.set_tooltip_markup(markup);
}
void ThresholdAdjuster::set_tooltip_text(const Glib::ustring& text) {
tSelector.set_tooltip_text(text);
}
/* 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)
*
* If separatedMode==true, the top slider is assumed to be the primary slider, then the bottom slider as the second one
*/
Glib::ustring ThresholdAdjuster::getHistoryString () {
if (tSelector.isDouble()) {
@@ -296,6 +326,6 @@ Glib::ustring ThresholdAdjuster::getHistoryString () {
else {
Glib::ustring b, t;
tSelector.getPositions(b, t);
return Glib::ustring::compose(tSelector.isStartAtOne()?"%2, %1":"%1, %2", b, t);
return Glib::ustring::compose(tSelector.isStartAtOne()||separatedMode?"%2, %1":"%1, %2", b, t);
}
}

View File

@@ -64,6 +64,7 @@ class ThresholdAdjuster : public Gtk::VBox {
bool afterReset;
bool blocked;
bool addMode;
bool separatedMode;
int delay;
double shapeValue (double a);
@@ -73,8 +74,16 @@ class ThresholdAdjuster : public Gtk::VBox {
public:
// Custom Threshold widget with 2 cursors (Top and Bottom) and a custom curve provided by the instanciator,
// each cursor having his own range, default value and precision
ThresholdAdjuster (Glib::ustring label,
double minValueBottom, double maxValueBottom, double defBottom, Glib::ustring labelBottom, unsigned int precisionBottom,
double minValueTop, double maxValueTop, double defTop, Glib::ustring labelTop, unsigned int precisionTop,
ThresholdCurveProvider* curveProvider, bool editedCheckBox=false);
// Simple Threshold widget with 2 linked sliders (0->1 or 1->0)
ThresholdAdjuster (Glib::ustring label, double minValue, double maxValue, double defBottom,
double defTop, unsigned int precision, bool startAtOne, bool editedCheckBox=false);
// Simple Threshold widget with 4 linked sliders by pairs (0->1->0 or 1->0->1)
ThresholdAdjuster (Glib::ustring label, double minValue, double maxValue, double defBottomLeft,
double defTopLeft, double defBottomRight, double defTopRight, unsigned int precision,
bool startAtOne, bool editedCheckBox=false);
@@ -82,8 +91,13 @@ class ThresholdAdjuster : public Gtk::VBox {
virtual ~ThresholdAdjuster ();
void setAdjusterListener (ThresholdAdjusterListener* alistener) { adjusterListener = alistener; }
void setBgCurveProvider (ThresholdCurveProvider* provider);
ThresholdSelector* getThresholdSelector() { return &tSelector; };
template <typename T>
rtengine::procparams::Threshold<T> getValue () { return tSelector.getPositions<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);
@@ -91,9 +105,7 @@ class ThresholdAdjuster : public Gtk::VBox {
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 (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);
@@ -114,6 +126,9 @@ class ThresholdAdjuster : public Gtk::VBox {
void resetPressed (GdkEventButton* event);
void editedToggled ();
Glib::ustring getHistoryString ();
void set_tooltip_markup(const Glib::ustring& markup);
// this set_tooltip_text method is to set_tooltip_markup, and text can contain markups
void set_tooltip_text(const Glib::ustring& text);
};
#endif

View File

@@ -20,17 +20,45 @@
#include "thresholdselector.h"
#include "multilangmgr.h"
#include <cassert>
#include <iomanip>
#include "mycurve.h"
ThresholdSelector::ThresholdSelector(double minValueBottom, double maxValueBottom, double defBottom, Glib::ustring labelBottom, unsigned int precisionBottom,
double minValueTop, double maxValueTop, double defTop, Glib::ustring labelTop, unsigned int precisionTop,
ThresholdCurveProvider* curveProvider) {
positions[TS_BOTTOMLEFT] = defPos[TS_BOTTOMLEFT] = defBottom;
positions[TS_TOPLEFT] = defPos[TS_TOPLEFT] = defTop;
positions[TS_BOTTOMRIGHT] = defPos[TS_BOTTOMRIGHT] = 0; // unused
positions[TS_TOPRIGHT] = defPos[TS_TOPRIGHT] = 0; // unused
this->precisionTop = precisionTop;
this->precisionBottom = precisionBottom;
doubleThresh = false;
separatedLabelBottom = labelBottom;
separatedLabelTop = labelTop;
bgCurveProvider = curveProvider;
separatedSliders = true;
initalEq1 = false; // unused
minValBottom = minValueBottom;
maxValBottom = maxValueBottom;
minValTop = minValueTop;
maxValTop = maxValueTop;
initValues ();
}
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;
this->precisionTop = precision;
this->precisionBottom = precision;
doubleThresh = false;
separatedLabelBottom = "";
separatedLabelTop = "";
#ifndef NDEBUG
if (startAtOne) {
assert (defBottom >= defTop);
@@ -42,9 +70,17 @@ ThresholdSelector::ThresholdSelector(double minValue, double maxValue, double de
assert (defBottom >= minValue);
assert (defTop <= maxValue);
}
assert(minValue < maxValue);
#endif
initValues (minValue, maxValue, startAtOne);
bgCurveProvider = NULL;
separatedSliders = false;
initalEq1 = startAtOne;
minValTop = minValBottom = minValue;
maxValTop = maxValBottom = maxValue;
initValues ();
}
ThresholdSelector::ThresholdSelector(double minValue, double maxValue, double defBottomLeft, double defTopLeft, double defBottomRight, double defTopRight, unsigned int precision, bool startAtOne) {
@@ -52,9 +88,13 @@ ThresholdSelector::ThresholdSelector(double minValue, double maxValue, double de
positions[TS_TOPLEFT] = defPos[TS_TOPLEFT] = defTopLeft;
positions[TS_BOTTOMRIGHT] = defPos[TS_BOTTOMRIGHT] = defBottomRight;
positions[TS_TOPRIGHT] = defPos[TS_TOPRIGHT] = defTopRight;
this->precision = precision;
this->precisionTop = precision;
this->precisionBottom = precision;
doubleThresh = true;
separatedLabelBottom = "";
separatedLabelTop = "";
#ifndef NDEBUG
if (startAtOne) {
assert (minValue <= defTopLeft);
@@ -70,20 +110,25 @@ ThresholdSelector::ThresholdSelector(double minValue, double maxValue, double de
assert (defTopRight <= defBottomRight);
assert (defBottomRight <= maxValue);
}
assert(minValue < maxValue);
#endif
initValues (minValue, maxValue, startAtOne);
bgCurveProvider = NULL;
separatedSliders = false;
initalEq1 = startAtOne;
minValTop = minValBottom = minValue;
maxValTop = maxValBottom = maxValue;
initValues ();
}
void ThresholdSelector::initValues (double minValue, double maxValue, bool startAtOne) {
assert(minValue <= maxValue);
initalEq1 = startAtOne;
minVal = minValue;
maxVal = maxValue;
void ThresholdSelector::initValues () {
additionalTTip = "";
oldLitCursor = litCursor = TS_UNDEFINED;
movedCursor = TS_UNDEFINED;
secondaryMovedCursor = TS_UNDEFINED;
set_size_request (-1, 20);
set_size_request (-1, 30);
add_events(Gdk::LEAVE_NOTIFY_MASK);
set_name("ThresholdSelector");
set_can_focus(false);
@@ -96,7 +141,7 @@ void ThresholdSelector::initValues (double minValue, double maxValue, bool start
*/
void ThresholdSelector::setPositions (double bottom, double top) {
setPositions(bottom, top, maxVal, maxVal);
setPositions(bottom, top, maxValBottom, maxValTop);
}
/*
@@ -120,7 +165,7 @@ void ThresholdSelector::setPositions (double bottomLeft, double topLeft, double
void ThresholdSelector::setDefaults (double bottom, double top) {
setDefaults(bottom, top, maxVal, maxVal);
setDefaults(bottom, top, maxValBottom, maxValTop);
}
void ThresholdSelector::setDefaults (double bottomLeft, double topLeft, double bottomRight, double topRight) {
@@ -133,21 +178,6 @@ void ThresholdSelector::setDefaults (double bottomLeft, double topLeft, double b
}
}
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;
@@ -175,9 +205,10 @@ bool ThresholdSelector::on_expose_event(GdkEventExpose* event) {
int iw = w-wslider-2*hb; // inner width (excluding padding for tabs)
for (int i=0; i<4; i++) {
positions01[i] = to01(positions[i]);
}
positions01[TS_BOTTOMLEFT] = to01(TS_BOTTOMLEFT);
positions01[TS_TOPLEFT] = to01(TS_TOPLEFT);
positions01[TS_BOTTOMRIGHT] = to01(TS_BOTTOMRIGHT);
positions01[TS_TOPRIGHT] = to01(TS_TOPRIGHT);
Gtk::StateType state = !is_sensitive() ? Gtk::STATE_INSENSITIVE : Gtk::STATE_NORMAL;
Glib::RefPtr<Gtk::Style> style = get_style();
@@ -208,24 +239,52 @@ bool ThresholdSelector::on_expose_event(GdkEventExpose* event) {
}
// 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)
if (bgCurveProvider) {
double yStart = double(int(float(h)*5.5f/7.f))-0.5;
double yEnd = double(int(float(h)*1.5f/7.f))+1.5;
std::vector<double> pts = bgCurveProvider->getCurvePoints(this); // the values sent by the provider are not checked (assumed to be correct)
if (pts.size() >= 4) {
std::vector<double>::iterator i=pts.begin();
double x = *i; i++;
double y = *i; i++;
cr->move_to (hb+hwslider+iw*x+0.5, (yEnd-yStart)*y+yStart);
for (; i<pts.end(); ) {
x = *i; i++;
y = *i; i++;
cr->line_to (hb+hwslider+iw*x+0.5, (yEnd-yStart)*y+yStart);
}
}
else {
// Draw a straight line because not enough points has been sent
double yStart = double(int(float(h)*5.5f/7.f))-0.5;
cr->move_to (hb+hwslider+0.5, yStart);
cr->line_to (hb+hwslider+iw+0.5, yStart);
}
}
else {
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]] > minValTop) // we use minValTop since if this block is executed, it means that we are in a simple Threshold where both bottom and top range are the same
cr->move_to (hb+hwslider, yStart);
else
cr->move_to (hb+hwslider, yEnd);
if (positions[p[0]] > minValTop)
cr->line_to (hb+hwslider+iw*positions01[p[0]]+0.5, yStart);
if (positions[p[1]] > minValTop)
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]] < maxValTop) {
cr->line_to (hb+hwslider+iw*positions01[p[3]]+0.5, yStart);
if (positions[p[3]] < maxValTop)
cr->line_to (hb+hwslider+iw+0.5, yStart);
}
}
if (is_sensitive() && bgGradient.size()>1) {
// draw surrounding curve
@@ -371,14 +430,18 @@ bool ThresholdSelector::on_motion_notify_event (GdkEventMotion* event) {
if (movedCursor != TS_UNDEFINED) {
// user is moving a cursor or two
double minBound, maxBound;
double minBound, maxBound, dRange;
findSecondaryMovedCursor(event->state);
// computing the boundaries
findBoundaries(minBound, maxBound);
double dX = ( (event->x-tmpX)*(maxVal-minVal) )/( w-2*hb );
if (movedCursor==TS_BOTTOMLEFT || movedCursor==TS_BOTTOMRIGHT)
dRange = maxValBottom-minValBottom;
else
dRange = maxValTop-minValTop;
double dX = ( (event->x-tmpX)*dRange )/( w-2*hb );
// slow motion if CTRL is pressed
if (event->state & Gdk::CONTROL_MASK)
dX *= 0.05;
@@ -429,7 +492,8 @@ void ThresholdSelector::findLitCursor(int posX, int posY) {
litCursor = TS_TOPLEFT;
if (doubleThresh) {
double cursorX = (posX-hb)*(maxVal-minVal)/(w-2*hb)+minVal;
// we use minValTop since if this block is executed, it means that we are in a simple Threshold where both bottom and top range are the same
double cursorX = (posX-hb)*(maxValTop-minValTop)/(w-2*hb)+minValTop;
if (cursorX>positions[TS_TOPRIGHT] || abs(cursorX-positions[TS_TOPRIGHT]) < abs(cursorX-positions[TS_TOPLEFT]))
litCursor = TS_TOPRIGHT;
@@ -440,7 +504,8 @@ void ThresholdSelector::findLitCursor(int posX, int posY) {
if (posX > 0 && posX < w) {
litCursor = TS_BOTTOMLEFT;
if (doubleThresh) {
double cursorX = (posX-hb)*(maxVal-minVal)/(w-2*hb)+minVal;
// we use minValTop since if this block is executed, it means that we are in a simple Threshold where both bottom and top range are the same
double cursorX = (posX-hb)*(maxValTop-minValTop)/(w-2*hb)+minValTop;
if (cursorX>positions[TS_BOTTOMRIGHT] || abs(cursorX-positions[TS_BOTTOMRIGHT]) < abs(cursorX-positions[TS_BOTTOMLEFT]))
litCursor = TS_BOTTOMRIGHT;
@@ -453,55 +518,75 @@ 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]);
if (separatedSliders) {
if (movedCursor == TS_BOTTOMLEFT) {
min = minValBottom;
max = maxValBottom;
}
else if (movedCursor == TS_TOPLEFT) {
min = minValTop;
max = maxValTop;
}
}
else if (initalEq1) {
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPLEFT] : minValTop+(positions[TS_BOTTOMLEFT]-positions[TS_TOPLEFT]);
max = positions[TS_BOTTOMRIGHT];
}
else {
min = minVal;
min = minValTop;
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPLEFT] : positions[TS_TOPRIGHT]-(positions[TS_TOPLEFT]-positions[TS_BOTTOMLEFT]);
}
break;
case (TS_TOPLEFT):
if (initalEq1) {
min = minVal;
if (separatedSliders) {
if (movedCursor == TS_BOTTOMLEFT) {
min = minValBottom;
max = maxValBottom;
}
else if (movedCursor == TS_TOPLEFT) {
min = minValTop;
max = maxValTop;
}
}
else if (initalEq1) {
min = minValTop;
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]);
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMLEFT] : minValTop+(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]);
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPRIGHT] : maxValTop-(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;
max = maxValTop;
}
break;
case (TS_TOPRIGHT):
if (initalEq1) {
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMRIGHT] : positions[TS_BOTTOMLEFT]+(positions[TS_TOPRIGHT]-positions[TS_BOTTOMRIGHT]);
max = maxVal;
max = maxValTop;
}
else {
min = positions[TS_TOPLEFT];
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMRIGHT] : maxVal-(positions[TS_BOTTOMRIGHT]-positions[TS_TOPRIGHT]);
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMRIGHT] : maxValTop-(positions[TS_BOTTOMRIGHT]-positions[TS_TOPRIGHT]);
}
break;
default:
min = minVal;
max = maxVal;
min = minValTop;
max = maxValTop;
break;
}
}
void ThresholdSelector::findSecondaryMovedCursor(guint state) {
secondaryMovedCursor = TS_UNDEFINED;
if (!(state & Gdk::SHIFT_MASK)) {
if (!separatedSliders && !(state & Gdk::SHIFT_MASK)) {
switch (movedCursor) {
case (TS_BOTTOMLEFT):
secondaryMovedCursor = TS_TOPLEFT;
@@ -537,34 +622,79 @@ void ThresholdSelector::reset () {
queue_draw ();
}
inline double ThresholdSelector::to01(double value) {
inline double ThresholdSelector::to01(ThreshCursorId cursorId) {
double rVal = (value-minVal)/(maxVal-minVal);
double rVal;
if (cursorId==TS_BOTTOMLEFT || cursorId==TS_BOTTOMRIGHT)
rVal = (positions[cursorId]-minValBottom)/(maxValBottom-minValBottom);
else
rVal = (positions[cursorId]-minValTop)/(maxValTop-minValTop);
if (rVal < 0.) rVal = 0.;
else if (rVal > 1.) rVal = 1.;
return rVal;
}
inline void ThresholdSelector::setBgCurveProvider (ThresholdCurveProvider* provider) {
bgCurveProvider = provider;
}
inline void ThresholdSelector::setSeparatedSliders(bool separated) {
separatedSliders = separated;
}
inline bool ThresholdSelector::getSeparatedSliders() {
return separatedSliders;
}
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")
if (doubleThresh) {
tTip = Glib::ustring::compose("<b>%1:</b> %2 <b>%3:</b> %4\n<b>%5:</b> %6 <b>%7:</b> %8",
M("THRESHOLDSELECTOR_TL"), Glib::ustring::format(std::fixed, std::setprecision(precisionTop), positions[TS_TOPLEFT]),
M("THRESHOLDSELECTOR_TR"), Glib::ustring::format(std::fixed, std::setprecision(precisionTop), positions[TS_TOPRIGHT]),
M("THRESHOLDSELECTOR_BL"), Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), positions[TS_BOTTOMLEFT]),
M("THRESHOLDSELECTOR_BR"), Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), positions[TS_BOTTOMRIGHT])
);
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")
if (!additionalTTip.empty())
tTip += Glib::ustring::compose("\n\n%1", additionalTTip);
tTip += Glib::ustring::compose("\n\n%1", M("THRESHOLDSELECTOR_HINT"));
}
else if (separatedSliders) {
tTip = Glib::ustring::compose("<b>%1:</b> %2\n<b>%3:</b> %4",
separatedLabelTop, Glib::ustring::format(std::fixed, std::setprecision(precisionTop), positions[TS_TOPLEFT]),
separatedLabelBottom, Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), positions[TS_BOTTOMLEFT])
);
set_tooltip_markup(tTip);
if (!additionalTTip.empty())
tTip += Glib::ustring::compose("\n\n%1", additionalTTip);
}
else {
tTip = Glib::ustring::compose("<b>%1:</b> %2\n<b>%3:</b> %4",
M("THRESHOLDSELECTOR_T"), Glib::ustring::format(std::fixed, std::setprecision(precisionTop), positions[TS_TOPLEFT]),
M("THRESHOLDSELECTOR_B"), Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), positions[TS_BOTTOMLEFT])
);
if (!additionalTTip.empty())
tTip += Glib::ustring::compose("\n\n%1", additionalTTip);
tTip += Glib::ustring::compose("\n\n%1", M("THRESHOLDSELECTOR_HINT"));
}
Gtk::Widget::set_tooltip_markup(tTip);
}
sigc::signal<void> ThresholdSelector::signal_value_changed() {
return sig_val_changed;
}
double ThresholdSelector::shapePositionValue (ThreshCursorId cursorId) {
unsigned int precision = (cursorId==TS_BOTTOMLEFT || cursorId==TS_BOTTOMRIGHT) ? precisionBottom : precisionTop;
return round(positions[cursorId]*pow(double(10), precision)) / pow(double(10), precision);
}
void ThresholdSelector::set_tooltip_markup(const Glib::ustring& markup) {
additionalTTip = markup;
updateTooltip();
}
void ThresholdSelector::set_tooltip_text(const Glib::ustring& text) {
additionalTTip = text;
updateTooltip();
}

View File

@@ -21,6 +21,21 @@
#include "guiutils.h"
#include "../rtengine/procparams.h"
#include <iomanip>
class ThresholdSelector;
/*
* This class let the instanciator to provide the background curve
*/
class ThresholdCurveProvider {
public:
/*
* The curve provider has to send back a list of point (at least 2 points) in the [0.0 ; 1.0] range
* for both X and Y axis; X and Y values are streamlined ( X1, Y1, X2, Y2, X3, Y3, ...)
*/
virtual std::vector<double> getCurvePoints(ThresholdSelector* tAdjuster) const = 0;
};
/*
* This widget will let you select a linearly variable threshold, creating a ramp up
@@ -36,6 +51,11 @@
*
* 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.
*
* It is also possible to have a threshold with 2 totally independent cursors, each one having his own range,
* man/max/default values and precision. This let developers create their own threshold curve, that they will
* have to provide through the
*
*/
class ThresholdSelector : public Gtk::DrawingArea {
@@ -57,17 +77,24 @@ class ThresholdSelector : public Gtk::DrawingArea {
Glib::RefPtr<Gdk::GC> gc_;
Glib::RefPtr<Gdk::Pixmap> backBuffer;
std::vector<GradientMilestone> bgGradient;
ThresholdCurveProvider* bgCurveProvider;
Glib::ustring additionalTTip;
Glib::ustring separatedLabelBottom; // Label for the bottom cursor, displayed if separatedSliders==true only
Glib::ustring separatedLabelTop; // Label for the top cursor, displayed if separatedSliders==true only
bool separatedSliders; // If true, the Top and Bottom sliders are totally separate and can be drag through the full range; for simple threshold only!
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
unsigned int precisionTop; // Decimal number if this object has to handle "double" values, for the Top slider
unsigned int precisionBottom; // Decimal number if this object has to handle "double" values, for the Bottom slider
ThreshCursorId litCursor;
ThreshCursorId oldLitCursor;
double boundary1[2], boundary2[2];
double tmpX, tmpPos;
ThreshCursorId movedCursor, secondaryMovedCursor;
double minVal, maxVal;
double minValTop, maxValTop;
double minValBottom, maxValBottom;
double defPos[4];
double positions[4];
unsigned short wslider;
@@ -75,22 +102,24 @@ class ThresholdSelector : public Gtk::DrawingArea {
const static int hb = 3; // horizontal border
const static int vb = 2; // vertical border
void initValues (double minValue, double maxValue, bool startAtOne);
void initValues ();
void findLitCursor(int posX, int posY);
void findSecondaryMovedCursor(guint state);
void findBoundaries(double &min, double &max);
double to01(double value);
double to01(ThreshCursorId cursorId);
void updateTooltip();
public:
sigc::signal<void> signal_value_changed();
ThresholdSelector(double minValueBottom, double maxValueBottom, double defBottom, Glib::ustring labelBottom, unsigned int precisionBottom,
double minValueTop, double maxValueTop, double defTop, Glib::ustring labelTop, unsigned int precisionTop,
ThresholdCurveProvider* curveProvider);
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); }
double shapePositionValue (ThreshCursorId cursorId);
template <typename T>
void setDefaults (const rtengine::procparams::Threshold<T> &t) {
defPos[TS_BOTTOMLEFT] = double(t.value[0]); // should we use shapeValue() ?
@@ -100,10 +129,8 @@ class ThresholdSelector : public Gtk::DrawingArea {
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]);
@@ -122,28 +149,42 @@ class ThresholdSelector : public Gtk::DrawingArea {
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])),
static_cast<T>(shapePositionValue(TS_BOTTOMLEFT)),
static_cast<T>(shapePositionValue(TS_TOPLEFT)),
static_cast<T>(shapePositionValue(TS_BOTTOMRIGHT)),
static_cast<T>(shapePositionValue(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])),
static_cast<T>(shapePositionValue(TS_BOTTOMLEFT)),
static_cast<T>(shapePositionValue(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);
template <typename T>
void getPositions (T &bottom, T &top) {
bottom = static_cast<T>(shapePositionValue(TS_BOTTOMLEFT));
top = static_cast<T>(shapePositionValue(TS_TOPLEFT));
}
template <typename T>
void getPositions (T &bottomLeft, T &topLeft, T &bottomRight, T &topRight) {
bottomLeft = static_cast<T>(shapePositionValue(TS_BOTTOMLEFT));
topLeft = static_cast<T>(shapePositionValue(TS_TOPLEFT));
bottomRight = static_cast<T>(shapePositionValue(TS_BOTTOMRIGHT));
topRight = static_cast<T>(shapePositionValue(TS_TOPRIGHT));
}
void setSeparatedSliders(bool separated);
bool getSeparatedSliders();
void setBgGradient (const std::vector<GradientMilestone> &milestones);
void setBgCurveProvider (ThresholdCurveProvider* provider);
bool isStartAtOne() { return initalEq1; }
bool isDouble() { return doubleThresh; }
void on_realize ();
@@ -153,9 +194,27 @@ class ThresholdSelector : public Gtk::DrawingArea {
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; }
unsigned int getPrecision () { return precisionTop; }
void reset ();
void set_tooltip_markup(const Glib::ustring& markup);
// this set_tooltip_text method is to set_tooltip_markup, and text can contain markups
void set_tooltip_text(const Glib::ustring& text);
};
template<>
inline void ThresholdSelector::getPositions<Glib::ustring> (Glib::ustring& bottom, Glib::ustring& top) {
bottom = Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), shapePositionValue(TS_BOTTOMLEFT));
top = Glib::ustring::format(std::fixed, std::setprecision(precisionTop), shapePositionValue(TS_TOPLEFT));
}
template<>
inline void ThresholdSelector::getPositions<Glib::ustring> (Glib::ustring& bottomLeft, Glib::ustring& topLeft, Glib::ustring& bottomRight, Glib::ustring& topRight) {
bottomLeft = Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), shapePositionValue(TS_BOTTOMLEFT));
topLeft = Glib::ustring::format(std::fixed, std::setprecision(precisionTop), shapePositionValue(TS_TOPLEFT));
bottomRight = Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), shapePositionValue(TS_BOTTOMRIGHT));
topRight = Glib::ustring::format(std::fixed, std::setprecision(precisionTop), shapePositionValue(TS_TOPRIGHT));
}
#endif

View File

@@ -28,19 +28,20 @@ Vibrance::Vibrance () : Gtk::VBox(), FoldableToolPanel(this) {
enabled->set_active (false);
pack_start(*enabled, Gtk::PACK_SHRINK, 0);
pastels = Gtk::manage(new Adjuster (M("TP_VIBRANCE_PASTELS"),-100,100,5,50));
pastels->setAdjusterListener (this);
//if (pastels->delay < 1000) pastels->delay = 1000;
pack_start( *pastels, Gtk::PACK_SHRINK, 0);
saturated = Gtk::manage(new Adjuster (M("TP_VIBRANCE_SATURATED"),-100,100,5,50));
saturated = Gtk::manage(new Adjuster (M("TP_VIBRANCE_SATURATED"),-100,100,1,50));
saturated->setAdjusterListener (this);
saturated->set_sensitive(false);
//if (saturated->delay < 1000) saturated->delay = 1000;
pack_start( *saturated, Gtk::PACK_SHRINK, 0);
psThreshold = Gtk::manage (new ThresholdAdjuster (M("TP_VIBRANCE_PSTHRESHOLD"), 0., 100., 1., 75., 0, false));
pastels = Gtk::manage(new Adjuster (M("TP_VIBRANCE_PASTELS"),-100,100,1,50));
pastels->setAdjusterListener (this);
//if (pastels->delay < 1000) pastels->delay = 1000;
pack_start( *pastels, Gtk::PACK_SHRINK, 0);
psThreshold = Gtk::manage (new ThresholdAdjuster (M("TP_VIBRANCE_PSTHRESHOLD"), -100., 100., 0., M("TP_VIBRANCE_PSTHRESHOLD_WEIGTHING"), 0, 0., 100., 75., M("TP_VIBRANCE_PSTHRESHOLD_SATTHRESH"), 0, this, false));
psThreshold->setAdjusterListener (this);
psThreshold->set_tooltip_markup(M("TP_VIBRANCE_PSTHRESHOLD_TOOLTIP"));
psThreshold->set_sensitive(false);
//if (psThreshold->delay < 1000) psThreshold->delay = 1000;
pack_start( *psThreshold, Gtk::PACK_SHRINK, 0);
@@ -251,12 +252,14 @@ void Vibrance::adjusterChanged (Adjuster* a, double newval) {
else if (a == saturated && !pastSatTog->get_active())
listener->panelChanged (EvVibranceSaturated, value );
}
if (pastSatTog->get_active())
psThreshold->queue_draw();
}
void Vibrance::adjusterChanged (ThresholdAdjuster* a, int newBottom, int newTop) {
if (listener && enabled->get_active()) {
listener->panelChanged (EvVibrancePastSatThreshold, psThreshold->getHistoryString());
}
if (listener && enabled->get_active()) {
listener->panelChanged (EvVibrancePastSatThreshold, psThreshold->getHistoryString());
}
}
@@ -295,3 +298,46 @@ void Vibrance::trimValues (ProcParams* pp) {
pastels->trimValue (pp->vibrance.pastels);
saturated->trimValue (pp->vibrance.saturated);
}
std::vector<double> Vibrance::getCurvePoints(ThresholdSelector* tAdjuster) const {
std::vector<double> points;
double threshold, transitionWeighting;
tAdjuster->getPositions<double>(transitionWeighting, threshold); // ( range -100;+100, range 0;+100 )
transitionWeighting /= 100.; // range -1., +1.
threshold /= 100.; // range 0., +1.
// Initial point
points.push_back(0.); points.push_back(0.);
double p2 = 3.0*threshold/4.0; // same one than in ipvibrance.cc
double s0 = threshold + (1.0-threshold)/4.0; // same one than in ipvibrance.cc
// point at the beginning of the first linear transition
points.push_back(p2); points.push_back(0.);
// Y value of the chroma mean point, calculated to get a straight line between p2 and s0
double chromaMean = (threshold/4.0) / (s0-p2);
// move chromaMean up or down depending on transitionWeighting
if (transitionWeighting > 0.0) {
// positive values -> give more weight to Saturated
chromaMean = (1.0-chromaMean) * transitionWeighting + chromaMean;
}
else if (transitionWeighting < 0.0) {
// negative values -> give more weight to Pastels
chromaMean = chromaMean * transitionWeighting + chromaMean;
}
// point at the location of the Top cursor, at the end of the first linear transition and the beginning of the second one
points.push_back(threshold); points.push_back(chromaMean);
if (threshold < 1.0) {
// point at the end of the second linear transition
points.push_back(s0); points.push_back(1.0);
// end point
points.push_back(1.0); points.push_back(1.0);
}
return points;
}

View File

@@ -24,7 +24,7 @@
#include "thresholdadjuster.h"
#include "toolpanel.h"
class Vibrance : public Gtk::VBox, public AdjusterListener, public ThresholdAdjusterListener, public FoldableToolPanel {
class Vibrance : public Gtk::VBox, public AdjusterListener, public ThresholdAdjusterListener, public FoldableToolPanel, public ThresholdCurveProvider {
protected:
Gtk::CheckButton* enabled;
@@ -60,7 +60,8 @@ public:
void enabled_toggled ();
void protectskins_toggled ();
void avoidcolorshift_toggled ();
void pastsattog_toggled ();
void pastsattog_toggled ();
std::vector<double> getCurvePoints(ThresholdSelector* tAdjuster) const;
};