Solving issue 2610: "Display curve node input/output values" + add a new tone curve mode (Luminance)
This commit is contained in:
parent
06deac5da4
commit
7c0b8e6fe1
@ -9,10 +9,15 @@ ADJUSTER_RESET_TO_DEFAULT;Réglages par défaut
|
||||
BATCHQUEUE_AUTOSTART;Démarrage auto
|
||||
BATCHQUEUE_DESTFILENAME;Chemin et nom de fichier
|
||||
BATCH_PROCESSING;Traitement par lot
|
||||
CURVEEDITOR_AXIS_LEFT_TAN;TG:
|
||||
CURVEEDITOR_AXIS_RIGHT_TAN;TD:
|
||||
CURVEEDITOR_AXIS_IN;E:
|
||||
CURVEEDITOR_AXIS_OUT;S:
|
||||
CURVEEDITOR_CURVES;Courbes
|
||||
CURVEEDITOR_CURVE;Courbe
|
||||
CURVEEDITOR_CUSTOM;Personnalisé
|
||||
CURVEEDITOR_DARKS;Zones sombres
|
||||
CURVEEDITOR_EDITPOINT_HINT;Active l'édition des valeurs d'entrée/sortie.\n\nUn clic droit sur un point le sélectionne.\nUn clic droit dans un espace vide desélectionne le point.
|
||||
CURVEEDITOR_HIGHLIGHTS;Hautes lumières
|
||||
CURVEEDITOR_LIGHTS;Zones claires
|
||||
CURVEEDITOR_LINEAR;Linéaire
|
||||
@ -1171,6 +1176,7 @@ TP_EXPOSURE_SATURATION;Saturation
|
||||
TP_EXPOSURE_TCMODE_FILMLIKE;Similaire Film
|
||||
TP_EXPOSURE_TCMODE_LABEL1;Mode courbe 1
|
||||
TP_EXPOSURE_TCMODE_LABEL2;Mode courbe 2
|
||||
TP_EXPOSURE_TCMODE_LUMINANCE;Luminance
|
||||
TP_EXPOSURE_TCMODE_SATANDVALBLENDING;Mixage Saturation et Valeur
|
||||
TP_EXPOSURE_TCMODE_STANDARD;Standard
|
||||
TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Standard Pondéré
|
||||
|
@ -11,10 +11,15 @@ ADJUSTER_RESET_TO_DEFAULT;Reset to default
|
||||
BATCHQUEUE_AUTOSTART;Auto-start
|
||||
BATCHQUEUE_DESTFILENAME;Path and file name
|
||||
BATCH_PROCESSING;Batch Processing
|
||||
CURVEEDITOR_AXIS_LEFT_TAN;LT:
|
||||
CURVEEDITOR_AXIS_RIGHT_TAN;RT:
|
||||
CURVEEDITOR_AXIS_IN;I:
|
||||
CURVEEDITOR_AXIS_OUT;O:
|
||||
CURVEEDITOR_CURVES;Curves
|
||||
CURVEEDITOR_CURVE;Curve
|
||||
CURVEEDITOR_CUSTOM;Custom
|
||||
CURVEEDITOR_DARKS;Darks
|
||||
CURVEEDITOR_EDITPOINT_HINT;Enable edition of node in/out values.\n\nRight-click on a node to select it.\nRight-click on empty space to de-select the node.
|
||||
CURVEEDITOR_HIGHLIGHTS;Highlights
|
||||
CURVEEDITOR_LIGHTS;Lights
|
||||
CURVEEDITOR_LINEAR;Linear
|
||||
@ -1358,6 +1363,7 @@ TP_EXPOSURE_SATURATION;Saturation
|
||||
TP_EXPOSURE_TCMODE_FILMLIKE;Film-like
|
||||
TP_EXPOSURE_TCMODE_LABEL1;Curve mode 1
|
||||
TP_EXPOSURE_TCMODE_LABEL2;Curve mode 2
|
||||
TP_EXPOSURE_TCMODE_LUMINANCE;Luminance
|
||||
TP_EXPOSURE_TCMODE_SATANDVALBLENDING;Saturation and Value Blending
|
||||
TP_EXPOSURE_TCMODE_STANDARD;Standard
|
||||
TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Weighted Standard
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -880,6 +887,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -537,6 +544,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -520,6 +527,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -153,6 +153,13 @@ style "clearlooks-spinbutton" {
|
||||
}
|
||||
}
|
||||
|
||||
style "clearlooks-axisadjuster" = "clearlooks-spinbutton" {
|
||||
# background
|
||||
base[INSENSITIVE] = @rt_tool_bg
|
||||
# text
|
||||
text[INSENSITIVE] = @rt_fg_color
|
||||
}
|
||||
|
||||
style "clearlooks-framelessspinbutton" {
|
||||
|
||||
# IMPORTANT!
|
||||
@ -515,6 +522,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
|
||||
widget "*.ExpanderBox" style "clearlooks-toolFrame"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
|
||||
widget "*.ExpanderBox.*.MyExpanderTitle.*" style "clearlooks-subexpander"
|
||||
widget "*.AxisAdjuster" style "clearlooks-axisadjuster"
|
||||
|
||||
# The window of the tooltip is called "gtk-tooltip"
|
||||
##################################################################
|
||||
|
@ -84,7 +84,9 @@ protected:
|
||||
unsigned int maxs;
|
||||
float maxsf;
|
||||
T * data;
|
||||
unsigned int clip, size;
|
||||
unsigned int clip;
|
||||
unsigned int size;
|
||||
unsigned int upperBound; // always equals size-1, parameter created for performance reason
|
||||
private:
|
||||
unsigned int owner;
|
||||
#if defined( __SSE2__ ) && defined( __x86_64__ )
|
||||
@ -109,6 +111,7 @@ public:
|
||||
data = new T[s];
|
||||
owner = 1;
|
||||
size = s;
|
||||
upperBound = size-1;
|
||||
maxs=size-2;
|
||||
maxsf = (float)maxs;
|
||||
#if defined( __SSE2__ ) && defined( __x86_64__ )
|
||||
@ -131,6 +134,7 @@ public:
|
||||
data = new T[s];
|
||||
owner = 1;
|
||||
size = s;
|
||||
upperBound = size-1;
|
||||
maxs=size-2;
|
||||
maxsf = (float)maxs;
|
||||
#if defined( __SSE2__ ) && defined( __x86_64__ )
|
||||
@ -155,6 +159,7 @@ public:
|
||||
data = new T[s];
|
||||
owner = 1;
|
||||
size = s;
|
||||
upperBound = size-1;
|
||||
maxs=size-2;
|
||||
maxsf = (float)maxs;
|
||||
#if defined( __SSE2__ ) && defined( __x86_64__ )
|
||||
@ -199,7 +204,7 @@ public:
|
||||
* @return number of element in the array
|
||||
*/
|
||||
int getUpperBound() {
|
||||
return size>0 ? size-1 : 0;
|
||||
return size>0 ? upperBound : 0;
|
||||
}
|
||||
|
||||
LUT<T> & operator=(LUT<T> &rhs) {
|
||||
@ -214,6 +219,7 @@ public:
|
||||
this->owner=1;
|
||||
memcpy(this->data,rhs.data,rhs.size*sizeof(T));
|
||||
this->size=rhs.size;
|
||||
this->upperBound=rhs.upperBound;
|
||||
this->maxs=this->size-2;
|
||||
this->maxsf = (float)this->maxs;
|
||||
#if defined( __SSE2__ ) && defined( __x86_64__ )
|
||||
@ -228,7 +234,7 @@ public:
|
||||
}
|
||||
// use with integer indices
|
||||
T& operator[](int index) const {
|
||||
return data[ rtengine::LIM<int>(index, 0, size-1) ];
|
||||
return data[ rtengine::LIM<int>(index, 0, upperBound) ];
|
||||
}
|
||||
|
||||
#if defined( __SSE2__ ) && defined( __x86_64__ )
|
||||
@ -350,7 +356,7 @@ public:
|
||||
else if (index > maxsf)
|
||||
{
|
||||
if (clip & LUT_CLIP_ABOVE)
|
||||
return data[size - 1];
|
||||
return data[upperBound];
|
||||
idx =maxs;
|
||||
}
|
||||
float diff = index - (float) idx;
|
||||
@ -359,6 +365,27 @@ public:
|
||||
return (p1 + p2*diff);
|
||||
}
|
||||
|
||||
// Return the value for "index" that is in the [0-1] range.
|
||||
T getVal01 (float index) const {
|
||||
index *= float(upperBound);
|
||||
int idx = (int)index; // don't use floor! The difference in negative space is no problems here
|
||||
if (index<0.f)
|
||||
{
|
||||
if (clip & LUT_CLIP_BELOW)
|
||||
return data[0];
|
||||
idx=0;
|
||||
}
|
||||
else if (index > maxsf)
|
||||
{
|
||||
if (clip & LUT_CLIP_ABOVE)
|
||||
return data[upperBound];
|
||||
idx =maxs;
|
||||
}
|
||||
float diff = index - (float) idx;
|
||||
T p1 = data[idx];
|
||||
T p2 = data[idx + 1]-p1;
|
||||
return (p1 + p2*diff);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Debug facility ; dump the content of the LUT in a file. No control of the filename is done
|
||||
@ -393,10 +420,16 @@ public:
|
||||
data = NULL;
|
||||
owner = 1;
|
||||
size = 0;
|
||||
upperBound=0;
|
||||
maxs=0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// TODO: HOMBRE: HueLUT is actually unused, could we delete this class now that LUT::getVal01 has been created?
|
||||
|
||||
|
||||
/** @brief LUT subclass handling hue values specifically.
|
||||
The array has a fixed size of float values and have to be in the [0.; 1.] range in both axis (no error checking implemented) */
|
||||
class HueLUT : public LUTf {
|
||||
@ -413,7 +446,7 @@ class HueLUT : public LUTf {
|
||||
|
||||
// use with integer indices
|
||||
float& operator[](int index) const {
|
||||
return data[ rtengine::LIM<int>(index, 0, size-1) ];
|
||||
return data[ rtengine::LIM<int>(index, 0, upperBound) ];
|
||||
}
|
||||
|
||||
// use with float indices in the [0.;1.] range
|
||||
@ -422,7 +455,7 @@ class HueLUT : public LUTf {
|
||||
if (index<0.f)
|
||||
return data[0];
|
||||
else if (index > 1.f)
|
||||
return data[size - 1];
|
||||
return data[upperBound];
|
||||
|
||||
float balance = index - float(idx/500.f);
|
||||
float h1 = data[idx];
|
||||
|
@ -154,8 +154,14 @@ public:
|
||||
* @return luminance value
|
||||
*/
|
||||
// xyz_sRGBD65 : conversion matrix from XYZ to sRGB for D65 illuminant: we use diagonal values
|
||||
static float rgbLuminance(float r, float g, float b) { return r*float(xyz_sRGBd65[1][0]) + g*float(xyz_sRGBd65[1][1]) + b*float(xyz_sRGBd65[1][2]); }
|
||||
static double rgbLuminance(double r, double g, double b) { return r*xyz_sRGBd65[1][0] + g*xyz_sRGBd65[1][1] + b*xyz_sRGBd65[1][2]; }
|
||||
static float rgbLuminance(float r, float g, float b) {
|
||||
// WArning: The sum of xyz_sRGBd65[1][] is > 1.0 (i.e. 1.0000001), so we use our own adapted values)
|
||||
// 0.2126729, 0.7151521, 0.0721750
|
||||
return r*0.2126729f + g*0.7151521f + b*0.0721750f;
|
||||
}
|
||||
static double rgbLuminance(double r, double g, double b) {
|
||||
return r*0.2126729 + g*0.7151521 + b*0.0721750;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -585,6 +585,11 @@ class WeightedStdToneCurve : public ToneCurve {
|
||||
void Apply(float& r, float& g, float& b) const;
|
||||
};
|
||||
|
||||
class LuminanceToneCurve : public ToneCurve {
|
||||
public:
|
||||
void Apply(float& r, float& g, float& b) const;
|
||||
};
|
||||
|
||||
class WeightedStdToneCurvebw : public ToneCurve {
|
||||
private:
|
||||
float Triangle(float refX, float refY, float X2) const;
|
||||
@ -670,6 +675,18 @@ inline void AdobeToneCurvebw::RGBTone (float& r, float& g, float& b) const {
|
||||
g = b + ((r - b) * (gold - bold) / (rold - bold));
|
||||
}
|
||||
|
||||
// Modifying the Luminance channel only
|
||||
inline void LuminanceToneCurve::Apply(float &r, float &g, float &b) const {
|
||||
assert (lutToneCurve);
|
||||
|
||||
float currLuminance = r*0.2126729f + g*0.7151521f + b*0.0721750f;
|
||||
float newLuminance = lutToneCurve[currLuminance];
|
||||
float coef = newLuminance/currLuminance;
|
||||
r = LIM<float>(r*coef, 0.f, 65535.f);
|
||||
g = LIM<float>(g*coef, 0.f, 65535.f);
|
||||
b = LIM<float>(b*coef, 0.f, 65535.f);
|
||||
}
|
||||
|
||||
inline float WeightedStdToneCurve::Triangle(float a, float a1, float b) const {
|
||||
if (a != b) {
|
||||
float b1;
|
||||
|
@ -30,7 +30,7 @@ const double d50_d65[3][3] = {{ 1.0478112, 0.0228866, -0.0501270},
|
||||
|
||||
// Color space conversion to/from XYZ; color spaces adapted to D65
|
||||
const double xyz_sRGBd65[3][3] = {{0.4124564, 0.3575761, 0.1804375},
|
||||
{0.2126729, 0.7151522, 0.0721750},
|
||||
{0.2126729, 0.7151522, 0.0721750}, // WARNING: the summ of this line is > 1.0
|
||||
{0.0193339, 0.1191920, 0.9503041}};
|
||||
|
||||
const double sRGBd65_xyz[3][3] = {{ 3.2404542, -1.5371385, -0.4985314},
|
||||
|
@ -2658,6 +2658,17 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *e
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (curveMode==ToneCurveParams::TC_MODE_LUMINANCE){ // apply the curve to the luminance channel
|
||||
const LuminanceToneCurve& userToneCurve = static_cast<const LuminanceToneCurve&>(customToneCurve1);
|
||||
for (int i=istart,ti=0; i<tH; i++,ti++) {
|
||||
for (int j=jstart,tj=0; j<tW; j++,tj++) {
|
||||
rtemp[ti*TS+tj] = CLIP<float>(rtemp[ti*TS+tj]);
|
||||
gtemp[ti*TS+tj] = CLIP<float>(gtemp[ti*TS+tj]);
|
||||
btemp[ti*TS+tj] = CLIP<float>(btemp[ti*TS+tj]);
|
||||
userToneCurve.Apply(rtemp[ti*TS+tj], gtemp[ti*TS+tj], btemp[ti*TS+tj]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (editID == EUID_ToneCurve2) { // filling the pipette buffer
|
||||
@ -2703,6 +2714,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *e
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (curveMode2==ToneCurveParams::TC_MODE_LUMINANCE){ // apply the curve to the luminance channel
|
||||
const LuminanceToneCurve& userToneCurve = static_cast<const LuminanceToneCurve&>(customToneCurve2);
|
||||
for (int i=istart,ti=0; i<tH; i++,ti++) {
|
||||
for (int j=jstart,tj=0; j<tW; j++,tj++) {
|
||||
userToneCurve.Apply(rtemp[ti*TS+tj], gtemp[ti*TS+tj], btemp[ti*TS+tj]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iGammaLUTf) {
|
||||
|
@ -1065,6 +1065,9 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol
|
||||
case (ToneCurveParams::TC_MODE_WEIGHTEDSTD):
|
||||
method = "WeightedStd";
|
||||
break;
|
||||
case (ToneCurveParams::TC_MODE_LUMINANCE):
|
||||
method = "Luminance";
|
||||
break;
|
||||
}
|
||||
keyFile.set_string ("Exposure", "CurveMode", method);
|
||||
}
|
||||
@ -1083,6 +1086,9 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol
|
||||
case (ToneCurveParams::TC_MODE_WEIGHTEDSTD):
|
||||
method = "WeightedStd";
|
||||
break;
|
||||
case (ToneCurveParams::TC_MODE_LUMINANCE):
|
||||
method = "Luminance";
|
||||
break;
|
||||
}
|
||||
keyFile.set_string ("Exposure", "CurveMode2", method);
|
||||
}
|
||||
@ -1909,6 +1915,7 @@ if (keyFile.has_group ("Exposure")) {
|
||||
else if (sMode == "FilmLike") toneCurve.curveMode = ToneCurveParams::TC_MODE_FILMLIKE;
|
||||
else if (sMode == "SatAndValueBlending") toneCurve.curveMode = ToneCurveParams::TC_MODE_SATANDVALBLENDING;
|
||||
else if (sMode == "WeightedStd") toneCurve.curveMode = ToneCurveParams::TC_MODE_WEIGHTEDSTD;
|
||||
else if (sMode == "Luminance") toneCurve.curveMode = ToneCurveParams::TC_MODE_LUMINANCE;
|
||||
if (pedited) pedited->toneCurve.curveMode = true;
|
||||
}
|
||||
if (keyFile.has_key ("Exposure", "CurveMode2")) {
|
||||
@ -1916,7 +1923,7 @@ if (keyFile.has_group ("Exposure")) {
|
||||
if (sMode == "Standard") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD;
|
||||
else if (sMode == "FilmLike") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_FILMLIKE;
|
||||
else if (sMode == "SatAndValueBlending") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_SATANDVALBLENDING;
|
||||
else if (sMode == "WeightedStd") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_WEIGHTEDSTD;
|
||||
else if (sMode == "Luminance") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_LUMINANCE;
|
||||
if (pedited) pedited->toneCurve.curveMode2 = true;
|
||||
}
|
||||
if (ppVersion>200) {
|
||||
|
@ -193,7 +193,8 @@ class ToneCurveParams {
|
||||
TC_MODE_STD, // Standard modes, the curve is applied on all component individually
|
||||
TC_MODE_WEIGHTEDSTD, // Weighted standard mode
|
||||
TC_MODE_FILMLIKE, // Film-like mode, as defined in Adobe's reference code
|
||||
TC_MODE_SATANDVALBLENDING // Modify the Saturation and Value channel
|
||||
TC_MODE_SATANDVALBLENDING, // Modify the Saturation and Value channel
|
||||
TC_MODE_LUMINANCE // Modify the Luminance channel with coefficients from Rec 709's
|
||||
};
|
||||
|
||||
bool autoexp;
|
||||
|
@ -4,7 +4,7 @@ set (BASESOURCEFILES
|
||||
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 thresholdselector.cc thresholdadjuster.cc
|
||||
clipboard.cc thumbimageupdater.cc bqentryupdater.cc lensgeom.cc coloredbar.cc edit.cc
|
||||
clipboard.cc thumbimageupdater.cc bqentryupdater.cc lensgeom.cc coloredbar.cc edit.cc coordinateadjuster.cc
|
||||
coarsepanel.cc cacorrection.cc chmixer.cc blackwhite.cc
|
||||
resize.cc icmpanel.cc crop.cc shadowshighlights.cc
|
||||
impulsedenoise.cc dirpyrdenoise.cc epd.cc
|
||||
|
198
rtgui/coordinateadjuster.cc
Normal file
198
rtgui/coordinateadjuster.cc
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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 "coordinateadjuster.h"
|
||||
#include "multilangmgr.h"
|
||||
#include <cassert>
|
||||
#include "curveeditorgroup.h"
|
||||
|
||||
Axis::Axis()
|
||||
: label(""), decimal(5), increment(0.001), pageIncrement(0.01), rangeLowerBound(0.), rangeUpperBound(1.)
|
||||
{}
|
||||
|
||||
Axis::Axis(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin=0.0, double valMax=1.0)
|
||||
: label(label), decimal(decimal), increment(increment), pageIncrement(pageIncrement), rangeLowerBound(valMin), rangeUpperBound(valMax)
|
||||
{}
|
||||
|
||||
void Axis::setValues(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax) {
|
||||
this->label = label;
|
||||
this->decimal = decimal;
|
||||
this->increment = increment;
|
||||
this->pageIncrement = pageIncrement;
|
||||
this->rangeLowerBound = valMin;
|
||||
this->rangeUpperBound = valMax;
|
||||
}
|
||||
|
||||
CoordinateAdjuster::AxisAdjuster::AxisAdjuster(CoordinateAdjuster *parent, const Axis *axis, char index) : idx(index), parent(parent) {
|
||||
label = Gtk::manage( new Gtk::Label(axis->label) );
|
||||
spinButton = Gtk::manage( new Gtk::SpinButton() );
|
||||
|
||||
label = Gtk::manage (new Gtk::Label(axis->label));
|
||||
//label->set_alignment(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
|
||||
|
||||
spinButton = Gtk::manage (new Gtk::SpinButton());
|
||||
spinButton->set_name("AxisAdjuster");
|
||||
spinButton->set_digits(axis->decimal);
|
||||
spinButton->set_increments(axis->increment, axis->pageIncrement);
|
||||
spinButton->set_range(axis->rangeLowerBound, axis->rangeUpperBound);
|
||||
spinButton->set_sensitive(false);
|
||||
spinButtonConn = spinButton->signal_value_changed().connect( sigc::mem_fun(*this, &CoordinateAdjuster::AxisAdjuster::valueChanged) );
|
||||
//spinButton->signal_key_press_event().connect( sigc::mem_fun(*this, &CoordinateAdjuster::AxisAdjuster::keyPressed) );
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::AxisAdjuster::updateGUI(const Axis &axis) {
|
||||
label->set_text(axis.label);
|
||||
spinButton->set_digits(axis.decimal);
|
||||
spinButton->set_increments(axis.increment, axis.pageIncrement);
|
||||
spinButton->set_range(axis.rangeLowerBound, axis.rangeUpperBound);
|
||||
spinButton->set_sensitive(false);
|
||||
rangeLowerBound = axis.rangeLowerBound;
|
||||
rangeUpperBound = axis.rangeUpperBound;
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::AxisAdjuster::setValue(double newValue) {
|
||||
float range = rangeUpperBound-rangeLowerBound;
|
||||
spinButtonConn.block(true);
|
||||
spinButton->set_value(newValue*range+rangeLowerBound);
|
||||
spinButtonConn.block(false);
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::AxisAdjuster::valueChanged() {
|
||||
float range = rangeUpperBound-rangeLowerBound;
|
||||
parent->updatePos(idx, (spinButton->get_value()-rangeLowerBound)/range);
|
||||
}
|
||||
|
||||
CoordinateAdjuster::CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent, const std::vector<Axis> &axis)
|
||||
: status(CA_STATUS_IDLE), parent(parent), coordinateProvider(provider)
|
||||
{
|
||||
provider->setListener(this);
|
||||
createWidgets(axis);
|
||||
}
|
||||
|
||||
CoordinateAdjuster::CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent)
|
||||
: status(CA_STATUS_IDLE), parent(parent), coordinateProvider(provider)
|
||||
{
|
||||
std::vector<Axis> defaultAxis;
|
||||
Axis X(M("CURVEEDITOR_AXIS_IN"), 3, 0.1, 1., 0., 100.);
|
||||
Axis Y(M("CURVEEDITOR_AXIS_OUT"), 3, 0.1, 1., 0., 100.);
|
||||
defaultAxis.push_back(X);
|
||||
defaultAxis.push_back(Y);
|
||||
|
||||
provider->setListener(this);
|
||||
createWidgets(defaultAxis);
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::createWidgets(const std::vector<Axis> &axis) {
|
||||
unsigned int count = axis.size();
|
||||
if (!count) {
|
||||
printf("CoordinateAdjuster - Error: the Axis list is empty!\n");
|
||||
return;
|
||||
}
|
||||
assert (count <= 4);
|
||||
|
||||
axisAdjusters.resize(axis.size());
|
||||
|
||||
set_spacing(3);
|
||||
|
||||
AxisAdjuster *currAdjuster = NULL;
|
||||
|
||||
for (unsigned int i=0; i<count; ++i) {
|
||||
const Axis *currAxis = &(axis.at(i));
|
||||
axisAdjusters.at(i) = new AxisAdjuster(this, currAxis, i);
|
||||
currAdjuster = axisAdjusters.at(i);
|
||||
currAdjuster->rangeLowerBound = currAxis->rangeLowerBound;
|
||||
currAdjuster->rangeUpperBound = currAxis->rangeUpperBound;
|
||||
|
||||
pack_start(*(currAdjuster->label), Gtk::PACK_SHRINK, 0);
|
||||
pack_start(*(currAdjuster->spinButton), Gtk::PACK_SHRINK, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::updatePos(char index, double value) {
|
||||
coordinateProvider->setPos(value, index);
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::setAxis(const std::vector<Axis> &axis) {
|
||||
assert (axis.size() == axisAdjusters.size());
|
||||
for (size_t i = 0; i<axisAdjusters.size(); ++i) {
|
||||
axisAdjusters.at(i)->updateGUI(axis.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::setPos(std::vector<double> &pos) {
|
||||
if (is_visible()) {
|
||||
for (size_t i=0; i<pos.size(); ++i) {
|
||||
axisAdjusters.at(i)->setValue(pos.at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::startNumericalAdjustment(const std::vector<Boundaries> &newBoundaries) {
|
||||
for (size_t i=0; i<axisAdjusters.size(); ++i) {
|
||||
Gtk::SpinButton *currSpinButton = axisAdjusters.at(i)->spinButton;
|
||||
currSpinButton->set_sensitive(true);
|
||||
float range = axisAdjusters.at(i)->rangeUpperBound-axisAdjusters.at(i)->rangeLowerBound;
|
||||
currSpinButton->set_range(newBoundaries.at(i).minVal*range+axisAdjusters.at(i)->rangeLowerBound, newBoundaries.at(i).maxVal*range+axisAdjusters.at(i)->rangeUpperBound);
|
||||
}
|
||||
axisAdjusters.at(0)->spinButton->grab_focus();
|
||||
status = CA_STATUS_EDITING;
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::switchAdjustedPoint(std::vector<double> &pos, const std::vector<Boundaries> &newBoundaries) {
|
||||
if (status != CA_STATUS_EDITING)
|
||||
return;
|
||||
|
||||
for (size_t i=0; i<axisAdjusters.size(); ++i) {
|
||||
AxisAdjuster *currAxis = axisAdjusters.at(i);
|
||||
|
||||
// disable events
|
||||
currAxis->spinButtonConn.block(true);
|
||||
|
||||
// To avoid trimmed values, we have to...
|
||||
|
||||
// ...enlarge range to the maximum
|
||||
currAxis->spinButton->set_range(axisAdjusters.at(i)->rangeLowerBound, axisAdjusters.at(i)->rangeUpperBound);
|
||||
|
||||
// ...set the new value
|
||||
currAxis->setValue(pos.at(i));
|
||||
|
||||
// ...narrow the range to the new interval
|
||||
float range = axisAdjusters.at(i)->rangeUpperBound-axisAdjusters.at(i)->rangeLowerBound;
|
||||
currAxis->spinButton->set_range(newBoundaries.at(i).minVal*range+axisAdjusters.at(i)->rangeLowerBound, newBoundaries.at(i).maxVal*range+axisAdjusters.at(i)->rangeUpperBound);
|
||||
|
||||
// enable events
|
||||
currAxis->spinButtonConn.block(false);
|
||||
}
|
||||
axisAdjusters.at(0)->spinButton->grab_focus();
|
||||
status = CA_STATUS_EDITING;
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::showMe(CoordinateProvider *provider) {
|
||||
parent->showCoordinateAdjuster(provider);
|
||||
}
|
||||
|
||||
void CoordinateAdjuster::stopNumericalAdjustment() {
|
||||
for (size_t i=0; i<axisAdjusters.size(); ++i) {
|
||||
axisAdjusters.at(i)->spinButtonConn.block(true);
|
||||
axisAdjusters.at(i)->spinButton->set_sensitive(false);
|
||||
axisAdjusters.at(i)->spinButton->set_range(axisAdjusters.at(i)->rangeLowerBound, axisAdjusters.at(i)->rangeUpperBound);
|
||||
axisAdjusters.at(i)->spinButtonConn.block(false);
|
||||
}
|
||||
status = CA_STATUS_IDLE;
|
||||
}
|
157
rtgui/coordinateadjuster.h
Normal file
157
rtgui/coordinateadjuster.h
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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 _COORDINATEADJUSTER_
|
||||
#define _COORDINATEADJUSTER_
|
||||
|
||||
#include <gtkmm.h>
|
||||
|
||||
class CurveEditorSubGroup;
|
||||
|
||||
class Axis {
|
||||
public:
|
||||
Glib::ustring label;
|
||||
unsigned int decimal;
|
||||
double increment;
|
||||
double pageIncrement;
|
||||
double rangeLowerBound;
|
||||
double rangeUpperBound;
|
||||
|
||||
Axis();
|
||||
Axis(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax);
|
||||
void setValues(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax);
|
||||
};
|
||||
|
||||
class CoordinateAdjuster;
|
||||
/**
|
||||
* @brief Object that will emit NewCoordinates events
|
||||
*/
|
||||
class CoordinateProvider {
|
||||
protected:
|
||||
CoordinateAdjuster *coordinateAdjuster;
|
||||
public:
|
||||
CoordinateProvider() : coordinateAdjuster(NULL) {}
|
||||
virtual ~CoordinateProvider() {}
|
||||
void setListener(CoordinateAdjuster *adjuster) { coordinateAdjuster = adjuster; }
|
||||
|
||||
/** @brief Update the position of the edited point ; will trigger events
|
||||
*
|
||||
* @param pos New position
|
||||
* @param chanIdx Chanel index as given in the std::vector upon instantiation
|
||||
*/
|
||||
virtual void setPos(double pos, int chanIdx)=0;
|
||||
virtual void stopNumericalAdjustment()=0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Widget that displays spin buttons to adjust coordinates
|
||||
*
|
||||
* You can set up to 4 axis that will be displayed on a single line, so keep the labels short!
|
||||
*
|
||||
* The position of the Axis in the vector will be used in the communication between the Adjuster and the Provider to identify the Axis
|
||||
*/
|
||||
class CoordinateAdjuster : public Gtk::HBox {
|
||||
|
||||
public:
|
||||
//-------------------------------- AxisAdjuster -------------------
|
||||
class AxisAdjuster {
|
||||
private:
|
||||
char idx;
|
||||
public:
|
||||
CoordinateAdjuster *parent;
|
||||
Gtk::Label *label;
|
||||
Gtk::SpinButton *spinButton;
|
||||
sigc::connection spinButtonConn;
|
||||
float rangeLowerBound;
|
||||
float rangeUpperBound;
|
||||
|
||||
AxisAdjuster(CoordinateAdjuster *parent, const Axis *axis, char index);
|
||||
|
||||
// used to update the AxisAdjuster's parameters
|
||||
void updateGUI(const Axis &axis);
|
||||
// useed to update the displayed value
|
||||
void setValue(double newValue);
|
||||
//bool keyPressed(GdkEventKey* event);
|
||||
void valueChanged();
|
||||
};
|
||||
//----------------------------------------------------------------
|
||||
|
||||
//-------------------------------- Boundaries -------------------
|
||||
class Boundaries {
|
||||
public:
|
||||
double minVal;
|
||||
double maxVal;
|
||||
};
|
||||
//---------------------------------------------------------------
|
||||
|
||||
private:
|
||||
typedef enum {
|
||||
CA_STATUS_IDLE,
|
||||
CA_STATUS_EDITING,
|
||||
CA_STATUS_END_EDITING
|
||||
} Status;
|
||||
|
||||
std::vector<AxisAdjuster*> axisAdjusters;
|
||||
Status status;
|
||||
CurveEditorSubGroup *parent;
|
||||
|
||||
void createWidgets(const std::vector<Axis> &axis);
|
||||
|
||||
protected:
|
||||
|
||||
friend class AxisAdjuster;
|
||||
|
||||
CoordinateProvider *coordinateProvider;
|
||||
|
||||
void updatePos(char index, double value);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// Basic X/Y adjuster, in the [0-1] range
|
||||
CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent);
|
||||
/// For more complex adjuster
|
||||
CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent, const std::vector<Axis> &axis);
|
||||
|
||||
virtual ~CoordinateAdjuster() {}
|
||||
|
||||
// Update the Axis list, e.g. on Curve change, but MUST have the same axis count
|
||||
void setAxis(const std::vector<Axis> &axis);
|
||||
|
||||
/** @brief Update the numbers in the spin buttons ; doesn't trigger any event
|
||||
*
|
||||
* @param pos Vector that gives the values of each channels
|
||||
*/
|
||||
void setPos(std::vector<double> &pos);
|
||||
|
||||
/// Start the adjustment session (enable the widget)
|
||||
void startNumericalAdjustment(const std::vector<Boundaries> &newBoundaries);
|
||||
|
||||
/// Edit another point
|
||||
void switchAdjustedPoint(std::vector<double> &pos, const std::vector<Boundaries> &newBoundaries);
|
||||
|
||||
/// Trigger the event to show the CoordinateAdjuster
|
||||
void showMe(CoordinateProvider *provider);
|
||||
|
||||
/// Stop the adjustment session (disable the widget, i.e. you won't be able to edit the values)
|
||||
void stopNumericalAdjustment();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -46,6 +46,10 @@ CurveEditorGroup::~CurveEditorGroup() {
|
||||
|
||||
void CurveEditorGroup::hideCurrentCurve() {
|
||||
// Setting the curve type to 'Unchanged' hide the CurveEditor
|
||||
if (diagonalSubGroup)
|
||||
diagonalSubGroup->stopNumericalAdjustment();
|
||||
if (flatSubGroup)
|
||||
flatSubGroup->stopNumericalAdjustment();
|
||||
if (displayedCurve)
|
||||
displayedCurve->curveType->set_active(false);
|
||||
}
|
||||
@ -280,10 +284,10 @@ void CurveEditorGroup::curveChanged () {
|
||||
/*
|
||||
* Listener called when the user has modified the curve
|
||||
*/
|
||||
float CurveEditorGroup::blendPipetteValues (float chan1, float chan2, float chan3) {
|
||||
float CurveEditorGroup::blendPipetteValues (CurveEditor* ce, float chan1, float chan2, float chan3) {
|
||||
|
||||
if (cl)
|
||||
return cl->blendPipetteValues(chan1, chan2, chan3);
|
||||
return cl->blendPipetteValues(ce, chan1, chan2, chan3);
|
||||
|
||||
return -1.f;
|
||||
}
|
||||
|
@ -89,10 +89,12 @@ protected:
|
||||
void updateGUI (CurveEditor* ce);
|
||||
void curveResetPressed ();
|
||||
void curveChanged ();
|
||||
float blendPipetteValues(float chan1, float chan2, float chan3);
|
||||
float blendPipetteValues(CurveEditor* ce, float chan1, float chan2, float chan3);
|
||||
void setUnChanged (bool uc, CurveEditor* ce);
|
||||
};
|
||||
|
||||
class CoordinateProvider;
|
||||
|
||||
class CurveEditorSubGroup {
|
||||
|
||||
friend class CurveEditorGroup;
|
||||
@ -105,6 +107,7 @@ protected:
|
||||
int valLinear;
|
||||
int valUnchanged;
|
||||
CurveEditorGroup *parent;
|
||||
int curveBBoxPos; // 0=above, 1=right, 2=below, 3=left
|
||||
|
||||
ColoredBar* leftBar;
|
||||
ColoredBar* bottomBar;
|
||||
@ -120,6 +123,9 @@ public:
|
||||
virtual void refresh(CurveEditor *curveToRefresh) = 0;
|
||||
virtual void editModeSwitchedOff() = 0;
|
||||
|
||||
virtual void showCoordinateAdjuster(CoordinateProvider *provider) = 0;
|
||||
virtual void stopNumericalAdjustment() = 0;
|
||||
|
||||
virtual void pipetteMouseOver(EditDataProvider *provider, int modifierKey) =0;
|
||||
virtual void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) =0;
|
||||
virtual void pipetteButton1Released(EditDataProvider *provider) =0;
|
||||
|
@ -19,6 +19,8 @@
|
||||
#ifndef _CURVELISTENER_
|
||||
#define _CURVELISTENER_
|
||||
|
||||
#include <vector>
|
||||
|
||||
class CurveEditor;
|
||||
|
||||
class CurveListener {
|
||||
@ -37,7 +39,7 @@ class CurveListener {
|
||||
* @param ce CurveEditor that we want to reset
|
||||
* @param curve Actual curve for the return value. The actual curve type (given by the first value of the vector)
|
||||
* should be kept the same. Change the curve type if REALLY necessary! */
|
||||
virtual bool getResetCurve(CurveEditor *ce, std::vector<double> &curve) { return false; };
|
||||
virtual bool getResetCurve(CurveEditor *ce, std::vector<double> &curve) { return false; }
|
||||
|
||||
/** @brief Blend pipette values from its different channels into a single value
|
||||
If the buffer has more than one channel and one channel, this method will blend them together.
|
||||
@ -45,7 +47,7 @@ class CurveListener {
|
||||
@param chan2 second channel's value
|
||||
@param chan3 third channel's value
|
||||
@return the blended value */
|
||||
virtual float blendPipetteValues(float chan1, float chan2, float chan3) {
|
||||
virtual float blendPipetteValues(CurveEditor *ce, float chan1, float chan2, float chan3) {
|
||||
float retVal = 0.f;
|
||||
int n = 0;
|
||||
if (chan1 != -1.f) {
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "shcselector.h"
|
||||
#include "adjuster.h"
|
||||
#include "mycurve.h"
|
||||
#include "mydiagonalcurve.h"
|
||||
#include "curveeditor.h"
|
||||
#include "diagonalcurveeditorsubgroup.h"
|
||||
|
||||
@ -35,6 +36,8 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
|
||||
editedAdjuster = NULL;
|
||||
editedAdjusterValue = 0;
|
||||
|
||||
curveBBoxPos = options.curvebboxpos;
|
||||
|
||||
valLinear = (int)DCT_Linear;
|
||||
valUnchanged = (int)DCT_Unchanged;
|
||||
parent = prt;
|
||||
@ -66,6 +69,9 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
|
||||
saveCustom->add (*Gtk::manage (new RTImage ("gtk-save-large.png")));
|
||||
loadCustom = Gtk::manage (new Gtk::Button ());
|
||||
loadCustom->add (*Gtk::manage (new RTImage ("gtk-open.png")));
|
||||
editPointCustom = Gtk::manage (new Gtk::ToggleButton ());
|
||||
editPointCustom->add (*Gtk::manage (new RTImage ("gtk-edit.png")));
|
||||
editPointCustom->set_tooltip_text(M("CURVEEDITOR_EDITPOINT_HINT"));
|
||||
editCustom = Gtk::manage (new Gtk::ToggleButton());
|
||||
editCustom->add (*Gtk::manage (new RTImage ("editmodehand.png")));
|
||||
editCustom->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP"));
|
||||
@ -75,6 +81,7 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
|
||||
custombbox->pack_end (*copyCustom, Gtk::PACK_SHRINK, 0);
|
||||
custombbox->pack_end (*saveCustom, Gtk::PACK_SHRINK, 0);
|
||||
custombbox->pack_end (*loadCustom, Gtk::PACK_SHRINK, 0);
|
||||
custombbox->pack_start(*editPointCustom, Gtk::PACK_SHRINK, 0);
|
||||
custombbox->pack_start(*editCustom, Gtk::PACK_SHRINK, 0);
|
||||
|
||||
customCurveAndButtons->pack_start (*customCurve, Gtk::PACK_EXPAND_WIDGET, 0);
|
||||
@ -90,12 +97,21 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
|
||||
} else if (options.curvebboxpos==3) {
|
||||
customCurveAndButtons->reorder_child(*custombbox, 0);
|
||||
}
|
||||
|
||||
customCoordAdjuster = Gtk::manage (new CoordinateAdjuster(customCurve, this));
|
||||
customCurveBox->pack_start(*customCoordAdjuster, Gtk::PACK_SHRINK, 0);
|
||||
if (options.curvebboxpos == 2)
|
||||
customCurveBox->reorder_child(*customCoordAdjuster, 2);
|
||||
customCoordAdjuster->show_all();
|
||||
|
||||
customCurveBox->show_all ();
|
||||
customCoordAdjuster->hide();
|
||||
|
||||
saveCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) );
|
||||
loadCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) );
|
||||
copyCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) );
|
||||
pasteCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) );
|
||||
editPointCustomConn = editPointCustom->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editPointToggled), editPointCustom) );
|
||||
editCustomConn = editCustom->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editToggled), editCustom) );
|
||||
|
||||
saveCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE"));
|
||||
@ -130,6 +146,9 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
|
||||
saveNURBS->add (*Gtk::manage (new RTImage ("gtk-save-large.png")));
|
||||
loadNURBS = Gtk::manage (new Gtk::Button ());
|
||||
loadNURBS->add (*Gtk::manage (new RTImage ("gtk-open.png")));
|
||||
editPointNURBS = Gtk::manage (new Gtk::ToggleButton ());
|
||||
editPointNURBS->add (*Gtk::manage (new RTImage ("gtk-edit.png")));
|
||||
editPointNURBS->set_tooltip_text(M("CURVEEDITOR_EDITPOINT_HINT"));
|
||||
editNURBS = Gtk::manage (new Gtk::ToggleButton());
|
||||
editNURBS->add (*Gtk::manage (new RTImage ("editmodehand.png")));
|
||||
editNURBS->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP"));
|
||||
@ -138,6 +157,7 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
|
||||
NURBSbbox->pack_end (*copyNURBS, Gtk::PACK_SHRINK, 0);
|
||||
NURBSbbox->pack_end (*saveNURBS, Gtk::PACK_SHRINK, 0);
|
||||
NURBSbbox->pack_end (*loadNURBS, Gtk::PACK_SHRINK, 0);
|
||||
NURBSbbox->pack_start(*editPointNURBS, Gtk::PACK_SHRINK, 0);
|
||||
NURBSbbox->pack_start(*editNURBS, Gtk::PACK_SHRINK, 0);
|
||||
|
||||
NURBSCurveAndButtons->pack_start (*NURBSCurve, Gtk::PACK_EXPAND_WIDGET, 0);
|
||||
@ -153,12 +173,21 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
|
||||
} else if (options.curvebboxpos==3) {
|
||||
NURBSCurveAndButtons->reorder_child(*NURBSbbox, 0);
|
||||
}
|
||||
|
||||
NURBSCoordAdjuster = Gtk::manage (new CoordinateAdjuster(NURBSCurve, this));
|
||||
NURBSCurveBox->pack_start(*NURBSCoordAdjuster, Gtk::PACK_SHRINK, 0);
|
||||
if (options.curvebboxpos == 2)
|
||||
NURBSCurveBox->reorder_child(*NURBSCoordAdjuster, 2);
|
||||
NURBSCoordAdjuster->show_all();
|
||||
|
||||
NURBSCurveBox->show_all ();
|
||||
NURBSCoordAdjuster->hide();
|
||||
|
||||
saveNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) );
|
||||
loadNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) );
|
||||
pasteNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) );
|
||||
copyNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) );
|
||||
editPointNURBSConn = editPointNURBS->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editPointToggled), editPointNURBS) );
|
||||
editNURBSConn = editNURBS->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editToggled), editNURBS) );
|
||||
|
||||
saveNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE"));
|
||||
@ -320,17 +349,17 @@ void DiagonalCurveEditorSubGroup::editModeSwitchedOff () {
|
||||
bool prevState;
|
||||
prevState = editCustomConn.block(true);
|
||||
editCustom->set_active(false);
|
||||
customCurve->pipetteMouseOver(NULL, 0);
|
||||
customCurve->pipetteMouseOver(NULL, NULL, 0);
|
||||
customCurve->setDirty(true);
|
||||
if (!prevState) editCustomConn.block(false);
|
||||
prevState = editNURBSConn.block(true);
|
||||
editNURBS->set_active(false);
|
||||
NURBSCurve->pipetteMouseOver(NULL, 0);
|
||||
NURBSCurve->pipetteMouseOver(NULL, NULL, 0);
|
||||
NURBSCurve->setDirty(true);
|
||||
if (!prevState) editNURBSConn.block(false);
|
||||
prevState = editParamConn.block(true);
|
||||
editParam->set_active(false);
|
||||
paramCurve->pipetteMouseOver(NULL, 0);
|
||||
paramCurve->pipetteMouseOver(NULL, NULL, 0);
|
||||
paramCurve->setDirty(true);
|
||||
if (!prevState) editParamConn.block(false);
|
||||
}
|
||||
@ -339,12 +368,12 @@ void DiagonalCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, i
|
||||
CurveEditor *curveEditor = static_cast<DiagonalCurveEditor*>(parent->displayedCurve);
|
||||
switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) {
|
||||
case (DCT_Spline):
|
||||
customCurve->pipetteMouseOver(provider, modifierKey);
|
||||
customCurve->pipetteMouseOver(curveEditor, provider, modifierKey);
|
||||
customCurve->setDirty(true);
|
||||
break;
|
||||
case (DCT_Parametric):
|
||||
{
|
||||
paramCurve->pipetteMouseOver(provider, modifierKey);
|
||||
paramCurve->pipetteMouseOver(curveEditor, provider, modifierKey);
|
||||
paramCurve->setDirty(true);
|
||||
float pipetteVal = 0.f;
|
||||
editedAdjuster = NULL;
|
||||
@ -392,7 +421,7 @@ void DiagonalCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, i
|
||||
}
|
||||
break;
|
||||
case (DCT_NURBS):
|
||||
NURBSCurve->pipetteMouseOver(provider, modifierKey);
|
||||
NURBSCurve->pipetteMouseOver(curveEditor, provider, modifierKey);
|
||||
NURBSCurve->setDirty(true);
|
||||
break;
|
||||
default: // (DCT_Linear, DCT_Unchanged)
|
||||
@ -462,6 +491,20 @@ void DiagonalCurveEditorSubGroup::pipetteDrag(EditDataProvider *provider, int mo
|
||||
}
|
||||
}
|
||||
|
||||
void DiagonalCurveEditorSubGroup::showCoordinateAdjuster(CoordinateProvider *provider) {
|
||||
if (provider == customCurve) {
|
||||
if (!editPointCustom->get_active()) editPointCustom->set_active(true);
|
||||
}
|
||||
else if (provider == NURBSCurve) {
|
||||
if (!editPointNURBS->get_active()) editPointNURBS->set_active(true);
|
||||
}
|
||||
}
|
||||
|
||||
void DiagonalCurveEditorSubGroup::stopNumericalAdjustment() {
|
||||
customCurve->stopNumericalAdjustment();
|
||||
NURBSCurve->stopNumericalAdjustment();
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the resize of the curve editor, if the displayed one is the requested one
|
||||
*/
|
||||
@ -773,6 +816,31 @@ void DiagonalCurveEditorSubGroup::pastePressed () {
|
||||
return;
|
||||
}
|
||||
|
||||
void DiagonalCurveEditorSubGroup::editPointToggled(Gtk::ToggleButton *button) {
|
||||
if (button->get_active()) {
|
||||
customCoordAdjuster->show();
|
||||
NURBSCoordAdjuster->show();
|
||||
}
|
||||
else {
|
||||
if (customCoordAdjuster) {
|
||||
customCurve->stopNumericalAdjustment();
|
||||
customCoordAdjuster->hide();
|
||||
NURBSCurve->stopNumericalAdjustment();
|
||||
NURBSCoordAdjuster->hide();
|
||||
}
|
||||
}
|
||||
if (button == editPointCustom) {
|
||||
editPointNURBSConn.block(true);
|
||||
editPointNURBS->set_active(!editPointNURBS->get_active());
|
||||
editPointNURBSConn.block(false);
|
||||
}
|
||||
else {
|
||||
editPointCustomConn.block(true);
|
||||
editPointCustom->set_active(!editPointCustom->get_active());
|
||||
editPointCustomConn.block(false);
|
||||
}
|
||||
}
|
||||
|
||||
void DiagonalCurveEditorSubGroup::editToggled (Gtk::ToggleButton *button) {
|
||||
DiagonalCurveEditor* dCurve = static_cast<DiagonalCurveEditor*>(parent->displayedCurve);
|
||||
if (!dCurve)
|
||||
|
@ -46,18 +46,23 @@ protected:
|
||||
Adjuster *editedAdjuster;
|
||||
int editedAdjusterValue;
|
||||
|
||||
CoordinateAdjuster *customCoordAdjuster;
|
||||
CoordinateAdjuster *NURBSCoordAdjuster;
|
||||
|
||||
Gtk::Button* saveCustom;
|
||||
Gtk::Button* loadCustom;
|
||||
Gtk::Button* copyCustom;
|
||||
Gtk::Button* pasteCustom;
|
||||
Gtk::ToggleButton* editPointCustom;
|
||||
Gtk::ToggleButton* editCustom;
|
||||
sigc::connection editCustomConn;
|
||||
sigc::connection editCustomConn, editPointCustomConn;
|
||||
Gtk::Button* saveNURBS;
|
||||
Gtk::Button* loadNURBS;
|
||||
Gtk::Button* copyNURBS;
|
||||
Gtk::Button* pasteNURBS;
|
||||
Gtk::ToggleButton* editPointNURBS;
|
||||
Gtk::ToggleButton* editNURBS;
|
||||
sigc::connection editNURBSConn;
|
||||
sigc::connection editNURBSConn, editPointNURBSConn;
|
||||
Gtk::Button* saveParam;
|
||||
Gtk::Button* loadParam;
|
||||
Gtk::Button* copyParam;
|
||||
@ -80,6 +85,8 @@ public:
|
||||
void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey);
|
||||
void pipetteButton1Released(EditDataProvider *provider);
|
||||
void pipetteDrag(EditDataProvider *provider, int modifierKey);
|
||||
void showCoordinateAdjuster(CoordinateProvider *provider);
|
||||
void stopNumericalAdjustment();
|
||||
|
||||
bool curveReset (CurveEditor *ce);
|
||||
|
||||
@ -91,6 +98,7 @@ protected:
|
||||
void loadPressed ();
|
||||
void copyPressed ();
|
||||
void pastePressed ();
|
||||
void editPointToggled(Gtk::ToggleButton *button);
|
||||
void editToggled (Gtk::ToggleButton *button);
|
||||
void removeEditor ();
|
||||
const std::vector<double> getCurveFromGUI (int type);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "shcselector.h"
|
||||
#include "adjuster.h"
|
||||
#include "mycurve.h"
|
||||
#include "myflatcurve.h"
|
||||
#include "curveeditor.h"
|
||||
#include "flatcurveeditorsubgroup.h"
|
||||
|
||||
@ -37,6 +38,8 @@ FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::u
|
||||
valUnchanged = (int)FCT_Unchanged;
|
||||
parent = prt;
|
||||
|
||||
curveBBoxPos = options.curvebboxpos;
|
||||
|
||||
// ControlPoints curve
|
||||
CPointsCurveBox = new Gtk::VBox ();
|
||||
CPointsCurveBox->set_spacing(4);
|
||||
@ -63,6 +66,9 @@ FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::u
|
||||
loadCPoints = Gtk::manage (new Gtk::Button ());
|
||||
loadCPoints->add (*Gtk::manage (new RTImage ("gtk-open.png")));
|
||||
editCPoints = Gtk::manage (new Gtk::ToggleButton());
|
||||
editPointCPoints = Gtk::manage (new Gtk::ToggleButton ());
|
||||
editPointCPoints->add (*Gtk::manage (new RTImage ("gtk-edit.png")));
|
||||
editPointCPoints->set_tooltip_text(M("CURVEEDITOR_EDITPOINT_HINT"));
|
||||
editCPoints->add (*Gtk::manage (new RTImage ("editmodehand.png")));
|
||||
editCPoints->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP"));
|
||||
editCPoints->hide();
|
||||
@ -71,6 +77,7 @@ FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::u
|
||||
CPointsbbox->pack_end (*copyCPoints, Gtk::PACK_SHRINK, 0);
|
||||
CPointsbbox->pack_end (*saveCPoints, Gtk::PACK_SHRINK, 0);
|
||||
CPointsbbox->pack_end (*loadCPoints, Gtk::PACK_SHRINK, 0);
|
||||
CPointsbbox->pack_start(*editPointCPoints, Gtk::PACK_SHRINK, 0);
|
||||
CPointsbbox->pack_start(*editCPoints, Gtk::PACK_SHRINK, 0);
|
||||
|
||||
CPointsCurveAndButtons->pack_start (*CPointsCurve, Gtk::PACK_EXPAND_WIDGET, 0);
|
||||
@ -86,12 +93,29 @@ FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::u
|
||||
} else if (options.curvebboxpos==3) {
|
||||
CPointsCurveAndButtons->reorder_child(*CPointsbbox, 0);
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<Axis> axis;
|
||||
axis.resize(4);
|
||||
axis.at(0).setValues(M("CURVEEDITOR_AXIS_IN"), 5, 0.001, 0.01, 0., 1.);
|
||||
axis.at(1).setValues(M("CURVEEDITOR_AXIS_OUT"), 5, 0.001, 0.01, 0., 1.);
|
||||
axis.at(2).setValues(M("CURVEEDITOR_AXIS_LEFT_TAN"), 5, 0.01, 0.1, 0., 1.);
|
||||
axis.at(3).setValues(M("CURVEEDITOR_AXIS_RIGHT_TAN"), 5, 0.01, 0.1, 0., 1.);
|
||||
CPointsCoordAdjuster = Gtk::manage (new CoordinateAdjuster(CPointsCurve, this, axis));
|
||||
CPointsCurveBox->pack_start(*CPointsCoordAdjuster, Gtk::PACK_SHRINK, 0);
|
||||
if (options.curvebboxpos == 2)
|
||||
CPointsCurveBox->reorder_child(*CPointsCoordAdjuster, 2);
|
||||
CPointsCoordAdjuster->show_all();
|
||||
}
|
||||
|
||||
CPointsCurveBox->show_all ();
|
||||
CPointsCoordAdjuster->hide();
|
||||
|
||||
saveCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::savePressed) );
|
||||
loadCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::loadPressed) );
|
||||
copyCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::copyPressed) );
|
||||
pasteCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::pastePressed) );
|
||||
editPointCPointsConn = editPointCPoints->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &FlatCurveEditorSubGroup::editPointToggled), editPointCPoints) );
|
||||
editCPointsConn = editCPoints->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &FlatCurveEditorSubGroup::editToggled), editCPoints) );
|
||||
|
||||
saveCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE"));
|
||||
@ -117,6 +141,17 @@ FlatCurveEditor* FlatCurveEditorSubGroup::addCurve(Glib::ustring curveLabel, boo
|
||||
return newCE;
|
||||
}
|
||||
|
||||
void FlatCurveEditorSubGroup::showCoordinateAdjuster(CoordinateProvider *provider) {
|
||||
if (provider == CPointsCurve) {
|
||||
if (!editPointCPoints->get_active()) editPointCPoints->set_active(true);
|
||||
}
|
||||
}
|
||||
|
||||
void FlatCurveEditorSubGroup::stopNumericalAdjustment() {
|
||||
CPointsCurve->stopNumericalAdjustment();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Force the resize of the curve editor, if the displayed one is the requested one
|
||||
*/
|
||||
@ -140,7 +175,7 @@ void FlatCurveEditorSubGroup::editModeSwitchedOff () {
|
||||
// toggling off all edit buttons, even if only one is toggle on
|
||||
bool prevState = editCPointsConn.block(true);
|
||||
editCPoints->set_active(false);
|
||||
CPointsCurve->pipetteMouseOver(NULL, 0);
|
||||
CPointsCurve->pipetteMouseOver(NULL, NULL, 0);
|
||||
CPointsCurve->setDirty(true);
|
||||
if (!prevState) editCPointsConn.block(false);
|
||||
}
|
||||
@ -149,7 +184,7 @@ void FlatCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, int m
|
||||
CurveEditor *curveEditor = static_cast<FlatCurveEditor*>(parent->displayedCurve);
|
||||
switch((FlatCurveType)(curveEditor->curveType->getSelected())) {
|
||||
case (FCT_MinMaxCPoints):
|
||||
CPointsCurve->pipetteMouseOver(provider, modifierKey);
|
||||
CPointsCurve->pipetteMouseOver(curveEditor, provider, modifierKey);
|
||||
CPointsCurve->setDirty(true);
|
||||
break;
|
||||
default: // (DCT_Linear, DCT_Unchanged)
|
||||
@ -380,6 +415,15 @@ void FlatCurveEditorSubGroup::pastePressed () {
|
||||
return;
|
||||
}
|
||||
|
||||
void FlatCurveEditorSubGroup::editPointToggled(Gtk::ToggleButton *button) {
|
||||
if (button->get_active())
|
||||
CPointsCoordAdjuster->show();
|
||||
else {
|
||||
CPointsCurve->stopNumericalAdjustment();
|
||||
CPointsCoordAdjuster->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void FlatCurveEditorSubGroup::editToggled (Gtk::ToggleButton *button) {
|
||||
FlatCurveEditor* dCurve = static_cast<FlatCurveEditor*>(parent->displayedCurve);
|
||||
if (!dCurve)
|
||||
|
@ -33,12 +33,15 @@ protected:
|
||||
|
||||
MyFlatCurve* CPointsCurve;
|
||||
|
||||
CoordinateAdjuster *CPointsCoordAdjuster;
|
||||
|
||||
Gtk::Button* saveCPoints;
|
||||
Gtk::Button* loadCPoints;
|
||||
Gtk::Button* copyCPoints;
|
||||
Gtk::Button* pasteCPoints;
|
||||
Gtk::ToggleButton* editPointCPoints;
|
||||
Gtk::ToggleButton* editCPoints;
|
||||
sigc::connection editCPointsConn;
|
||||
sigc::connection editCPointsConn, editPointCPointsConn;
|
||||
|
||||
public:
|
||||
FlatCurveEditorSubGroup(CurveEditorGroup* prt, Glib::ustring& curveDir);
|
||||
@ -53,6 +56,8 @@ public:
|
||||
void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey);
|
||||
void pipetteButton1Released(EditDataProvider *provider);
|
||||
void pipetteDrag(EditDataProvider *provider, int modifierKey);
|
||||
void showCoordinateAdjuster(CoordinateProvider *provider);
|
||||
void stopNumericalAdjustment();
|
||||
|
||||
bool curveReset (CurveEditor *ce);
|
||||
|
||||
@ -66,6 +71,7 @@ protected:
|
||||
void pastePressed ();
|
||||
void removeEditor ();
|
||||
const std::vector<double> getCurveFromGUI (int type);
|
||||
void editPointToggled(Gtk::ToggleButton *button);
|
||||
void editToggled (Gtk::ToggleButton *button);
|
||||
};
|
||||
|
||||
|
@ -36,6 +36,7 @@ MyCurve::MyCurve () : pipetteR(-1.f), pipetteG(-1.f), pipetteB(-1.f), pipetteVal
|
||||
sized = RS_Pending;
|
||||
snapToElmt = -100;
|
||||
curveIsDirty = true;
|
||||
edited_point = -1;
|
||||
|
||||
set_extension_events(Gdk::EXTENSION_EVENTS_ALL);
|
||||
#if defined (__APPLE__)
|
||||
@ -114,6 +115,15 @@ bool MyCurve::snapCoordinateY(double testedVal, double realVal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float MyCurve::getVal(LUTf &curve, int x) {
|
||||
if ((graphW-2) == curve.getSize()) {
|
||||
return curve[x];
|
||||
}
|
||||
else {
|
||||
return curve.getVal01(float(x)/(graphW-3));
|
||||
}
|
||||
}
|
||||
|
||||
void MyCurve::on_style_changed (const Glib::RefPtr<Gtk::Style>& style) {
|
||||
setDirty(true);
|
||||
queue_draw ();
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "curvelistener.h"
|
||||
#include "cursormanager.h"
|
||||
#include "coloredbar.h"
|
||||
#include "coordinateadjuster.h"
|
||||
#include "../rtengine/LUT.h"
|
||||
#include "guiutils.h"
|
||||
#include "options.h"
|
||||
@ -59,8 +60,9 @@ enum ResizeState {
|
||||
};
|
||||
|
||||
class MyCurveIdleHelper;
|
||||
class CurveEditor;
|
||||
|
||||
class MyCurve : public Gtk::DrawingArea, public BackBuffer, public ColorCaller {
|
||||
class MyCurve : public Gtk::DrawingArea, public BackBuffer, public ColorCaller, public CoordinateProvider {
|
||||
|
||||
friend class MyCurveIdleHelper;
|
||||
|
||||
@ -72,14 +74,14 @@ class MyCurve : public Gtk::DrawingArea, public BackBuffer, public ColorCaller {
|
||||
ColoredBar *leftBar;
|
||||
ColoredBar *bottomBar;
|
||||
CursorShape cursor_type;
|
||||
int graphX, graphY, graphW, graphH; /// dimensions of the graphic area, excluding surrounding space for the points of for the colored bar
|
||||
int graphX, graphY, graphW, graphH; /// position and dimensions of the graphic area, excluding surrounding space for the points of for the colored bar
|
||||
int prevGraphW, prevGraphH; /// previous inner width and height of the editor
|
||||
Gdk::ModifierType mod_type;
|
||||
int cursorX; /// X coordinate in the graph of the cursor
|
||||
int cursorY; /// Y coordinate in the graph of the cursor
|
||||
std::vector< Point<float> > point;
|
||||
std::vector< Point<float> > upoint;
|
||||
std::vector< Point<float> > lpoint;
|
||||
LUTf point;
|
||||
LUTf upoint;
|
||||
LUTf lpoint;
|
||||
bool buttonPressed;
|
||||
/**
|
||||
* snapToElmt, which will be used for the Y axis only, must be interpreted like this:
|
||||
@ -98,10 +100,14 @@ class MyCurve : public Gtk::DrawingArea, public BackBuffer, public ColorCaller {
|
||||
enum ResizeState sized;
|
||||
bool curveIsDirty;
|
||||
|
||||
int edited_point; // > -1 when a point is being numerically edited
|
||||
std::vector<double> editedPos;
|
||||
|
||||
virtual std::vector<double> get_vector (int veclen) = 0;
|
||||
int getGraphMinSize() { return GRAPH_SIZE + RADIUS + 1; }
|
||||
bool snapCoordinateX(double testedVal, double realVal);
|
||||
bool snapCoordinateY(double testedVal, double realVal);
|
||||
float getVal(LUTf &curve, int x);
|
||||
|
||||
// return value = new requested height
|
||||
int calcDimensions ();
|
||||
@ -123,7 +129,7 @@ class MyCurve : public Gtk::DrawingArea, public BackBuffer, public ColorCaller {
|
||||
virtual bool handleEvents (GdkEvent* event) = 0;
|
||||
virtual void reset (const std::vector<double> &resetCurve, double identityValue=0.5) = 0;
|
||||
|
||||
virtual void pipetteMouseOver (EditDataProvider *provider, int modifierKey) =0;
|
||||
virtual void pipetteMouseOver (CurveEditor *ce, EditDataProvider *provider, int modifierKey) =0;
|
||||
virtual void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) =0;
|
||||
virtual void pipetteButton1Released(EditDataProvider *provider) =0;
|
||||
virtual void pipetteDrag(EditDataProvider *provider, int modifierKey) =0;
|
||||
|
@ -33,6 +33,9 @@ MyDiagonalCurve::MyDiagonalCurve () : activeParam(-1), bghistvalid(false) {
|
||||
|
||||
bghist = new unsigned int[256];
|
||||
|
||||
editedPos.resize(2);
|
||||
editedPos.at(0) = editedPos.at(1) = 0.0;
|
||||
|
||||
signal_event().connect( sigc::mem_fun(*this, &MyDiagonalCurve::handleEvents) );
|
||||
|
||||
curve.type = DCT_Spline;
|
||||
@ -82,47 +85,77 @@ std::vector<double> MyDiagonalCurve::get_vector (int veclen) {
|
||||
|
||||
// calculate remaining points
|
||||
std::vector<double> curveDescr = getPoints ();
|
||||
rtengine::DiagonalCurve* rtcurve = new rtengine::DiagonalCurve (curveDescr, veclen*1.2);
|
||||
rtengine::DiagonalCurve rtcurve(curveDescr, veclen*1.2);
|
||||
std::vector<double> t;
|
||||
t.resize (veclen);
|
||||
for (int i = 0; i < veclen; i++)
|
||||
t[i] = (double) i / (veclen - 1.0);
|
||||
rtcurve->getVal (t, vector);
|
||||
delete rtcurve;
|
||||
rtcurve.getVal (t, vector);
|
||||
return vector;
|
||||
}
|
||||
|
||||
void MyDiagonalCurve::get_LUT (LUTf &lut) {
|
||||
|
||||
int size = lut.getSize();
|
||||
|
||||
if (curve.type != DCT_Parametric) {
|
||||
// count active points:
|
||||
double prev =- 1.0;
|
||||
int active = 0;
|
||||
int firstact = -1;
|
||||
for (int i = 0; i < (int)curve.x.size(); ++i)
|
||||
if (curve.x.at(i) > prev) {
|
||||
if (firstact < 0)
|
||||
firstact = i;
|
||||
prev = curve.x.at(i);
|
||||
++active;
|
||||
}
|
||||
// handle degenerate case:
|
||||
if (active < 2) {
|
||||
double ry;
|
||||
if (active > 0)
|
||||
ry = curve.y.at(firstact);
|
||||
else
|
||||
ry = 0.0;
|
||||
if (ry < 0.0) ry = 0.0;
|
||||
if (ry > 1.0) ry = 1.0;
|
||||
for (int x = 0; x < size; ++x)
|
||||
lut[x] = ry;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate remaining points
|
||||
std::vector<double> curveDescr = getPoints ();
|
||||
rtengine::DiagonalCurve rtcurve(curveDescr, lut.getUpperBound()*1.2);
|
||||
double t;
|
||||
double maxVal = double(lut.getUpperBound());
|
||||
for (int i = 0; i < size; i++) {
|
||||
t = double(i) / maxVal;
|
||||
lut[i] = rtcurve.getVal (t);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void MyDiagonalCurve::interpolate () {
|
||||
|
||||
prevGraphW = graphW;
|
||||
prevGraphH = graphH;
|
||||
int nbPoints = graphW-2;
|
||||
point.resize (nbPoints);
|
||||
std::vector<double> vector = get_vector (nbPoints);
|
||||
for (int i = 0; i < nbPoints; ++i) {
|
||||
float currX = float(i)/float(nbPoints-1);
|
||||
point.at(i).setCoords(float(graphX)+1.5f+float(graphW-3)*currX, float(graphY)-1.5f-float(graphH-3)*float(vector.at(i)));
|
||||
}
|
||||
upoint.clear ();
|
||||
lpoint.clear ();
|
||||
int nbPoints = rtengine::max(graphW-2,201);
|
||||
point(nbPoints);
|
||||
get_LUT (point);
|
||||
upoint.reset();
|
||||
lpoint.reset ();
|
||||
|
||||
if (curve.type==DCT_Parametric && activeParam>0) {
|
||||
double tmp = curve.x.at(activeParam-1);
|
||||
if (activeParam>=4) {
|
||||
upoint.resize(nbPoints);
|
||||
lpoint.resize(nbPoints);
|
||||
upoint(nbPoints);
|
||||
lpoint(nbPoints);
|
||||
curve.x.at(activeParam-1) = 100;
|
||||
vector = get_vector (nbPoints);
|
||||
for (int i = 0; i < nbPoints; ++i) {
|
||||
float currX = float(i)/float(nbPoints-1);
|
||||
upoint.at(i).setCoords(float(graphX)+1.5f+float(graphW-3)*currX, float(graphY)-1.5f-float(graphH-3)*float(vector.at(i)));
|
||||
}
|
||||
get_LUT(upoint);
|
||||
curve.x.at(activeParam-1) = -100;
|
||||
vector = get_vector (nbPoints);
|
||||
for (int i = 0; i < nbPoints; ++i) {
|
||||
float currX = float(i)/float(nbPoints-1);
|
||||
lpoint.at(i).setCoords(float(graphX)+1.5f+float(graphW-3)*currX, float(graphY)-1.5f-float(graphH-3)*float(vector.at(i)));
|
||||
}
|
||||
get_LUT (lpoint);
|
||||
curve.x.at(activeParam-1) = tmp;
|
||||
}
|
||||
}
|
||||
@ -140,8 +173,10 @@ void MyDiagonalCurve::draw (int handle) {
|
||||
return;
|
||||
|
||||
// re-calculate curve if dimensions changed
|
||||
if (curveIsDirty || prevGraphW != graphW || prevGraphH != graphH || int(point.size()) != graphW-2)
|
||||
int currPointSize = point.getUpperBound();
|
||||
if (curveIsDirty || /*prevGraphW != graphW || prevGraphH != graphH ||*/ (currPointSize==200 && (graphW-3>200)) || (currPointSize>200 && (graphW-2<=200 || graphW-3!=currPointSize)))
|
||||
interpolate ();
|
||||
currPointSize = point.getUpperBound();
|
||||
|
||||
Gtk::StateType state = !is_sensitive() ? Gtk::STATE_INSENSITIVE : Gtk::STATE_NORMAL;
|
||||
|
||||
@ -214,15 +249,16 @@ void MyDiagonalCurve::draw (int handle) {
|
||||
cr->set_line_width (1.0);
|
||||
|
||||
// draw upper and lower bounds
|
||||
if (curve.type==DCT_Parametric && activeParam>0 && lpoint.size()>1 && upoint.size()>1) {
|
||||
float graphH_ = float(graphH-3);
|
||||
float graphX_ = float(graphX)+1.5;
|
||||
float graphY_ = float(graphY)-1.5;
|
||||
if (curve.type==DCT_Parametric && activeParam>0 && lpoint.getUpperBound()>1 && upoint.getUpperBound()>1) {
|
||||
cr->set_source_rgba (0.0, 0.0, 0.0, 0.15);
|
||||
cr->move_to (upoint[0].x, upoint[0].y);
|
||||
for (int i=1; i<(int)upoint.size(); i++)
|
||||
cr->line_to (upoint[i].x, upoint[i].y);
|
||||
cr->line_to (lpoint[lpoint.size()-1].x, lpoint[lpoint.size()-1].y);
|
||||
for (int i=(int)lpoint.size()-2; i>=0; i--)
|
||||
cr->line_to (lpoint[i].x, lpoint[i].y);
|
||||
cr->line_to (upoint[0].x, upoint[0].y);
|
||||
cr->move_to (graphX_, getVal(upoint, 0)*-graphH_+graphY_);
|
||||
for (int i=1; i<graphW-2; ++i)
|
||||
cr->line_to (float(i)+graphX_, getVal(upoint, i)*-graphH_+graphY_);
|
||||
for (int i=graphW-3; i>=0; --i)
|
||||
cr->line_to (float(i)+graphX_, getVal(lpoint, i)*-graphH_+graphY_);
|
||||
cr->fill ();
|
||||
}
|
||||
|
||||
@ -299,10 +335,9 @@ void MyDiagonalCurve::draw (int handle) {
|
||||
|
||||
// draw curve
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
cr->move_to (double(point.at(0).x), double(point.at(0).y));
|
||||
for (int i=1; i<(int)point.size(); i++) {
|
||||
cr->line_to (double(point.at(i).x), double(point.at(i).y));
|
||||
}
|
||||
cr->move_to (graphX_, getVal(point, 0)*-graphH_+graphY_);
|
||||
for (int i=1; i<graphW-2; ++i)
|
||||
cr->line_to (float(i)+graphX_, getVal(point, i)*-graphH_+graphY_);
|
||||
cr->stroke ();
|
||||
|
||||
// draw the left colored bar
|
||||
@ -348,7 +383,7 @@ void MyDiagonalCurve::draw (int handle) {
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
}
|
||||
else {
|
||||
if (i == handle || i == snapToElmt)
|
||||
if (i == handle || i == snapToElmt || i == edited_point)
|
||||
cr->set_source_rgb (1.0, 0.0, 0.0);
|
||||
else
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
@ -359,6 +394,14 @@ void MyDiagonalCurve::draw (int handle) {
|
||||
|
||||
cr->arc (x, y, RADIUS+0.5, 0, 2*M_PI);
|
||||
cr->fill ();
|
||||
|
||||
if (i == edited_point) {
|
||||
cr->set_line_width(2.);
|
||||
cr->arc (x, y, RADIUS+3.5, 0, 2*M_PI);
|
||||
cr->stroke();
|
||||
cr->set_line_width(1.);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
setDirty(false);
|
||||
@ -408,7 +451,8 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
|
||||
// setDrawRectangle will allocate the backbuffer Surface
|
||||
if (setDrawRectangle(win, 0, 0, get_allocation().get_width(), get_allocation().get_height())) {
|
||||
setDirty(true);
|
||||
curveIsDirty = true;
|
||||
if (prevGraphW > 200 || graphW > 200)
|
||||
curveIsDirty = true;
|
||||
}
|
||||
draw (lit_point);
|
||||
GdkRectangle *rectangle = &(event->expose.area);
|
||||
@ -421,50 +465,118 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
|
||||
case Gdk::BUTTON_PRESS:
|
||||
snapToElmt = -100;
|
||||
if (curve.type!=DCT_Parametric) {
|
||||
if (event->button.button == 1) {
|
||||
std::vector<double>::iterator itx, ity;
|
||||
buttonPressed = true;
|
||||
add_modal_grab ();
|
||||
if (edited_point == -1) {
|
||||
if (event->button.button == 1) {
|
||||
std::vector<double>::iterator itx, ity;
|
||||
buttonPressed = true;
|
||||
add_modal_grab ();
|
||||
|
||||
// get the pointer position
|
||||
getCursorPosition(Gdk::EventType(event->type), event->motion.is_hint!=0, int(event->button.x), int(event->button.y), Gdk::ModifierType(event->button.state));
|
||||
findClosestPoint();
|
||||
// get the pointer position
|
||||
getCursorPosition(Gdk::EventType(event->type), event->motion.is_hint!=0, int(event->button.x), int(event->button.y), Gdk::ModifierType(event->button.state));
|
||||
findClosestPoint();
|
||||
|
||||
new_type = CSMove;
|
||||
if (distanceX > minDistanceX) {
|
||||
/* insert a new control point */
|
||||
if (num > 0) {
|
||||
if (clampedX > curve.x.at(closest_point))
|
||||
++closest_point;
|
||||
new_type = CSMove;
|
||||
if (distanceX > minDistanceX) {
|
||||
if (mod_type & GDK_CONTROL_MASK) {
|
||||
clampedY = point.getVal01(clampedX);
|
||||
}
|
||||
/* insert a new control point */
|
||||
if (num > 0) {
|
||||
if (clampedX > curve.x.at(closest_point))
|
||||
++closest_point;
|
||||
}
|
||||
itx = curve.x.begin();
|
||||
ity = curve.y.begin();
|
||||
for (int i=0; i<closest_point; i++) { itx++; ity++; }
|
||||
curve.x.insert (itx, 0);
|
||||
curve.y.insert (ity, 0);
|
||||
num++;
|
||||
|
||||
// the graph is refreshed only if a new point is created
|
||||
curve.x.at(closest_point) = clampedX;
|
||||
curve.y.at(closest_point) = clampedY;
|
||||
|
||||
curveIsDirty = true;
|
||||
setDirty(true);
|
||||
draw (closest_point);
|
||||
notifyListener ();
|
||||
}
|
||||
itx = curve.x.begin();
|
||||
ity = curve.y.begin();
|
||||
for (int i=0; i<closest_point; i++) { itx++; ity++; }
|
||||
curve.x.insert (itx, 0);
|
||||
curve.y.insert (ity, 0);
|
||||
num++;
|
||||
|
||||
// the graph is refreshed only if a new point is created (snaped to a pixel)
|
||||
curve.x.at(closest_point) = clampedX;
|
||||
curve.y.at(closest_point) = clampedY;
|
||||
|
||||
curveIsDirty = true;
|
||||
setDirty(true);
|
||||
draw (closest_point);
|
||||
notifyListener ();
|
||||
grab_point = closest_point;
|
||||
lit_point = closest_point;
|
||||
ugpX = curve.x.at(closest_point);
|
||||
ugpY = curve.y.at(closest_point);
|
||||
}
|
||||
grab_point = closest_point;
|
||||
lit_point = closest_point;
|
||||
ugpX = curve.x.at(closest_point);
|
||||
ugpY = curve.y.at(closest_point);
|
||||
else if (event->button.button == 3) {
|
||||
if (lit_point>-1 && grab_point==-1) {
|
||||
if (!coordinateAdjuster->is_visible())
|
||||
coordinateAdjuster->showMe(this);
|
||||
|
||||
edited_point = lit_point;
|
||||
std::vector<CoordinateAdjuster::Boundaries> newBoundaries(2);
|
||||
unsigned int size = curve.x.size();
|
||||
if (edited_point == 0) { newBoundaries.at(0).minVal = 0.; newBoundaries.at(0).maxVal = curve.x.at(1); }
|
||||
else if (edited_point == size-1) { newBoundaries.at(0).minVal = curve.x.at(edited_point-1); newBoundaries.at(0).maxVal = 1.; }
|
||||
else if (curve.x.size() > 2) { newBoundaries.at(0).minVal = curve.x.at(edited_point-1); newBoundaries.at(0).maxVal = curve.x.at(edited_point+1); }
|
||||
newBoundaries.at(1).minVal = 0.; newBoundaries.at(1).maxVal = 1.;
|
||||
editedPos.at(0) = curve.x.at(edited_point);
|
||||
editedPos.at(1) = curve.y.at(edited_point);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
coordinateAdjuster->startNumericalAdjustment(newBoundaries);
|
||||
setDirty(true);
|
||||
draw (lit_point);
|
||||
new_type = CSArrow;
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
if (buttonPressed) retval = true;
|
||||
}
|
||||
if (buttonPressed) retval = true;
|
||||
else { // if (edited_point > -1)
|
||||
if (event->button.button == 3) {
|
||||
// do we edit another point?
|
||||
if (edited_point>-1 && grab_point==-1) {
|
||||
/* get the pointer position */
|
||||
getCursorPosition(Gdk::EventType(event->type), event->motion.is_hint!=0, int(event->button.x), int(event->button.y), Gdk::ModifierType(event->button.state));
|
||||
findClosestPoint();
|
||||
if (cursorX>=0 && cursorX<=graphW && cursorY>=0 && cursorY<=graphH) {
|
||||
if (distanceX <= minDistanceX) {
|
||||
// the cursor is close to an existing point
|
||||
lit_point = closest_point;
|
||||
if (lit_point != edited_point) {
|
||||
edited_point = lit_point;
|
||||
curveIsDirty = true;
|
||||
setDirty(true);
|
||||
draw (lit_point);
|
||||
std::vector<CoordinateAdjuster::Boundaries> newBoundaries;
|
||||
newBoundaries.resize(2);
|
||||
unsigned int size = curve.x.size();
|
||||
if (edited_point == 0) { newBoundaries.at(0).minVal = 0.; newBoundaries.at(0).maxVal = curve.x.at(1); }
|
||||
else if (edited_point == size-1) { newBoundaries.at(0).minVal = curve.x.at(edited_point-1); newBoundaries.at(0).maxVal = 1.; }
|
||||
else if (curve.x.size() > 2) { newBoundaries.at(0).minVal = curve.x.at(edited_point-1); newBoundaries.at(0).maxVal = curve.x.at(edited_point+1); }
|
||||
newBoundaries.at(1).minVal = 0.; newBoundaries.at(1).maxVal = 1.;
|
||||
retval = true;
|
||||
editedPos.at(0) = curve.x.at(edited_point);
|
||||
editedPos.at(1) = curve.y.at(edited_point);
|
||||
coordinateAdjuster->switchAdjustedPoint(editedPos, newBoundaries);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the cursor is inside the graph but away from existing points
|
||||
new_type = CSPlus;
|
||||
curveIsDirty = true;
|
||||
stopNumericalAdjustment();
|
||||
}
|
||||
}
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Gdk::BUTTON_RELEASE:
|
||||
snapToElmt = -100;
|
||||
if (curve.type!=DCT_Parametric) {
|
||||
if (curve.type!=DCT_Parametric && edited_point==-1) {
|
||||
if (buttonPressed && event->button.button == 1) {
|
||||
std::vector<double>::iterator itx, ity;
|
||||
int src, dst;
|
||||
@ -542,25 +654,56 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
|
||||
getCursorPosition(Gdk::EventType(event->type), event->motion.is_hint!=0, int(event->button.x), int(event->button.y), Gdk::ModifierType(event->button.state));
|
||||
|
||||
if (grab_point == -1) {
|
||||
// there's no point currently being moved
|
||||
int previous_lit_point = lit_point;
|
||||
findClosestPoint();
|
||||
if (cursorX<0 || cursorX>graphW || cursorY<0 || cursorY>graphH) {
|
||||
// the cursor has left the graph area
|
||||
new_type = CSArrow;
|
||||
lit_point = -1;
|
||||
if (edited_point==-1) {
|
||||
// there's no point currently being moved
|
||||
int previous_lit_point = lit_point;
|
||||
findClosestPoint();
|
||||
if (cursorX<0 || cursorX>graphW || cursorY<0 || cursorY>graphH) {
|
||||
// the cursor has left the graph area
|
||||
new_type = CSArrow;
|
||||
lit_point = -1;
|
||||
}
|
||||
else if (distanceX <= minDistanceX) {
|
||||
// the cursor is close to an existing point
|
||||
new_type = CSMove;
|
||||
lit_point = closest_point;
|
||||
}
|
||||
else {
|
||||
// the cursor is inside the graph but away from existing points
|
||||
new_type = CSPlus;
|
||||
lit_point = -1;
|
||||
}
|
||||
if (lit_point != previous_lit_point) {
|
||||
setDirty(true);
|
||||
draw (lit_point);
|
||||
if (lit_point > -1) {
|
||||
editedPos.at(0) = curve.x.at(lit_point);
|
||||
editedPos.at(1) = curve.y.at(lit_point);
|
||||
}
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
if (lit_point == -1 && new_type == CSPlus) {
|
||||
editedPos.at(0) = clampedX;
|
||||
editedPos.at(1) = clampedY;
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
}
|
||||
else if (distanceX <= minDistanceX) {
|
||||
new_type = CSMove;
|
||||
lit_point = closest_point;
|
||||
}
|
||||
else {
|
||||
new_type = CSPlus;
|
||||
lit_point = -1;
|
||||
}
|
||||
if (lit_point != previous_lit_point) {
|
||||
setDirty(true);
|
||||
draw (lit_point);
|
||||
else { // if (edited_point > -1)
|
||||
// there's no point currently being moved
|
||||
int previous_lit_point = lit_point;
|
||||
findClosestPoint();
|
||||
if (distanceX <= minDistanceX) {
|
||||
// the cursor is close to an existing point
|
||||
lit_point = closest_point;
|
||||
}
|
||||
else {
|
||||
// the cursor is outside the graph or inside the graph but away from existing points
|
||||
lit_point = -1;
|
||||
}
|
||||
if (lit_point != previous_lit_point) {
|
||||
setDirty(true);
|
||||
draw (lit_point);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -646,6 +789,12 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
|
||||
setDirty(true);
|
||||
draw (lit_point);
|
||||
notifyListener ();
|
||||
|
||||
if (coordinateAdjuster->is_visible()) {
|
||||
editedPos.at(0) = curve.x.at(grab_point);
|
||||
editedPos.at(1) = curve.y.at(grab_point);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -669,7 +818,7 @@ CursorShape MyDiagonalCurve::motionNotify(CursorShape type, double minDistanceX,
|
||||
return new_type;
|
||||
}
|
||||
|
||||
void MyDiagonalCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey) {
|
||||
void MyDiagonalCurve::pipetteMouseOver (CurveEditor *ce, EditDataProvider *provider, int modifierKey) {
|
||||
if (!provider) {
|
||||
// occurs when leaving the preview area -> cleanup the curve editor
|
||||
pipetteR = pipetteG = pipetteB = -1.f;
|
||||
@ -681,8 +830,9 @@ void MyDiagonalCurve::pipetteMouseOver (EditDataProvider *provider, int modifier
|
||||
pipetteG = provider->pipetteVal[1];
|
||||
pipetteB = provider->pipetteVal[2];
|
||||
pipetteVal = 0.f;
|
||||
if (listener)
|
||||
pipetteVal = listener->blendPipetteValues(pipetteR, pipetteG, pipetteB);
|
||||
if (listener) {
|
||||
pipetteVal = listener->blendPipetteValues(ce, pipetteR, pipetteG, pipetteB);
|
||||
}
|
||||
else {
|
||||
int n = 0;
|
||||
if (pipetteR != -1.f) {
|
||||
@ -713,33 +863,45 @@ void MyDiagonalCurve::pipetteMouseOver (EditDataProvider *provider, int modifier
|
||||
|
||||
if (curve.type == DCT_Linear || curve.type == DCT_Spline || curve.type == DCT_NURBS) {
|
||||
// get the pointer position
|
||||
int px = graphX + int(float(graphW)*pipetteVal); // WARNING: converting pipetteVal from float to int, precision loss here!
|
||||
getCursorPosition(Gdk::MOTION_NOTIFY, false, px, graphY, Gdk::ModifierType(modifierKey));
|
||||
getCursorPositionFromCurve(pipetteVal);
|
||||
|
||||
if (grab_point == -1) {
|
||||
// there's no point currently being moved
|
||||
int previous_lit_point = lit_point;
|
||||
findClosestPoint();
|
||||
if (cursorX<0 || cursorX>graphW || cursorY<0 || cursorY>graphH) {
|
||||
// the cursor has left the graph area
|
||||
lit_point = -1;
|
||||
}
|
||||
else if (distanceX <= minDistanceX) {
|
||||
lit_point = closest_point;
|
||||
}
|
||||
else {
|
||||
lit_point = -1;
|
||||
}
|
||||
if (lit_point != previous_lit_point) {
|
||||
setDirty(true);
|
||||
draw (lit_point);
|
||||
if (edited_point==-1) {
|
||||
if (grab_point == -1) {
|
||||
// there's no point currently being moved
|
||||
int previous_lit_point = lit_point;
|
||||
findClosestPoint();
|
||||
if (cursorX<0 || cursorX>graphW || cursorY<0 || cursorY>graphH) {
|
||||
// the cursor has left the graph area
|
||||
lit_point = -1;
|
||||
}
|
||||
else if (distanceX <= minDistanceX) {
|
||||
lit_point = closest_point;
|
||||
}
|
||||
else {
|
||||
lit_point = -1;
|
||||
}
|
||||
if (lit_point != previous_lit_point) {
|
||||
setDirty(true);
|
||||
draw (lit_point);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
draw(lit_point);
|
||||
|
||||
if (edited_point==-1) {
|
||||
editedPos.at(0) = pipetteVal;
|
||||
editedPos.at(1) = point.getVal01(pipetteVal);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MyDiagonalCurve::pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) {
|
||||
if (edited_point>1)
|
||||
return;
|
||||
|
||||
int num = (int)curve.x.size();
|
||||
|
||||
/* graphW and graphH are the size of the graph */
|
||||
@ -756,13 +918,10 @@ void MyDiagonalCurve::pipetteButton1Pressed(EditDataProvider *provider, int modi
|
||||
buttonPressed = true;
|
||||
|
||||
// get the pointer position
|
||||
int px = graphX + int(float(graphW)*pipetteVal); // WARNING: converting pipetteVal from float to int, precision loss here!
|
||||
getCursorPosition(Gdk::BUTTON_PRESS, false, px, graphY, Gdk::ModifierType(modifierKey));
|
||||
getCursorPositionFromCurve(pipetteVal);
|
||||
findClosestPoint();
|
||||
|
||||
if (distanceX > minDistanceX) {
|
||||
rtengine::DiagonalCurve rtCurve(getPoints(), 200);
|
||||
|
||||
/* insert a new control point */
|
||||
if (num > 0) {
|
||||
if (clampedX > curve.x.at(closest_point))
|
||||
@ -771,17 +930,25 @@ void MyDiagonalCurve::pipetteButton1Pressed(EditDataProvider *provider, int modi
|
||||
itx = curve.x.begin();
|
||||
ity = curve.y.begin();
|
||||
for (int i=0; i<closest_point; i++) { itx++; ity++; }
|
||||
lit_point = closest_point;
|
||||
curve.x.insert (itx, 0);
|
||||
curve.y.insert (ity, 0);
|
||||
num++;
|
||||
|
||||
// the graph is refreshed only if a new point is created (snaped to a pixel)
|
||||
curve.x.at(closest_point) = clampedX;
|
||||
curve.y.at(closest_point) = clampedY = rtCurve.getVal(pipetteVal);
|
||||
// the graph is refreshed only if a new point is created (snapped to a pixel)
|
||||
curve.x.at(lit_point) = clampedX;
|
||||
curve.y.at(lit_point) = clampedY;
|
||||
|
||||
if (lit_point>-1 && grab_point==-1 && coordinateAdjuster->is_visible()) {
|
||||
std::vector<double> position;
|
||||
position.resize(2);
|
||||
position.at(0) = clampedX;
|
||||
position.at(1) = clampedY;
|
||||
coordinateAdjuster->setPos(position);
|
||||
}
|
||||
|
||||
curveIsDirty = true;
|
||||
setDirty(true);
|
||||
draw (closest_point);
|
||||
draw (lit_point);
|
||||
notifyListener ();
|
||||
}
|
||||
grab_point = closest_point;
|
||||
@ -792,6 +959,9 @@ void MyDiagonalCurve::pipetteButton1Pressed(EditDataProvider *provider, int modi
|
||||
}
|
||||
|
||||
void MyDiagonalCurve::pipetteButton1Released(EditDataProvider *provider) {
|
||||
if (edited_point>1)
|
||||
return;
|
||||
|
||||
/* graphW and graphH are the size of the graph */
|
||||
calcDimensions();
|
||||
|
||||
@ -827,7 +997,7 @@ void MyDiagonalCurve::pipetteButton1Released(EditDataProvider *provider) {
|
||||
}
|
||||
|
||||
void MyDiagonalCurve::pipetteDrag(EditDataProvider *provider, int modifierKey) {
|
||||
if (curve.type==DCT_Parametric || graphW<0 || graphH<0)
|
||||
if (edited_point>-1 || curve.type==DCT_Parametric || graphW<0 || graphH<0)
|
||||
return;
|
||||
|
||||
snapToMinDistY = snapToMinDistX = 10.;
|
||||
@ -837,7 +1007,7 @@ void MyDiagonalCurve::pipetteDrag(EditDataProvider *provider, int modifierKey) {
|
||||
/* graphW and graphH are the size of the graph */
|
||||
calcDimensions();
|
||||
|
||||
getCursorPosition(Gdk::MOTION_NOTIFY, false, cursorX+graphX, graphY+provider->deltaScreen.y, Gdk::ModifierType(modifierKey));
|
||||
getCursorPosition(Gdk::MOTION_NOTIFY, false, cursorX+graphX, graphY-cursorY+provider->deltaPrevScreen.y, Gdk::ModifierType(modifierKey));
|
||||
|
||||
// we memorize the previous position of the point, for optimization purpose
|
||||
double prevPosX = curve.x.at(grab_point);
|
||||
@ -888,9 +1058,38 @@ void MyDiagonalCurve::pipetteDrag(EditDataProvider *provider, int modifierKey) {
|
||||
setDirty(true);
|
||||
draw (lit_point);
|
||||
notifyListener ();
|
||||
|
||||
if (lit_point>-1 && coordinateAdjuster->is_visible()) {
|
||||
std::vector<double> position;
|
||||
position.resize(2);
|
||||
position.at(0) = curve.x.at(grab_point);
|
||||
position.at(1) = curve.y.at(grab_point);
|
||||
coordinateAdjuster->setPos(position);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void MyDiagonalCurve::getCursorPositionFromCurve(float x) {
|
||||
|
||||
// the graph is refreshed only if a new point is created (snaped to a pixel)
|
||||
clampedX = x;
|
||||
clampedY = point.getVal01(x);
|
||||
|
||||
cursorX = int(clampedX*float(graphW-3)) + graphX+1.5;
|
||||
cursorY = graphY - int(clampedY*float(graphH-3));
|
||||
}
|
||||
|
||||
// x = cursor position found in the event
|
||||
void MyDiagonalCurve::getCursorPositionFromCurve(int x) {
|
||||
|
||||
// the graph is refreshed only if a new point is created (snaped to a pixel)
|
||||
cursorX = x-graphX;
|
||||
clampedX = (float(cursorX)-1.5) / float(graphW-3);
|
||||
clampedY = point.getVal01(clampedX);
|
||||
cursorY = graphY - int(float(1.-clampedY)*float(graphH-3));
|
||||
}
|
||||
|
||||
void MyDiagonalCurve::getCursorPosition(Gdk::EventType evType, bool isHint, int evX, int evY, Gdk::ModifierType modifierKey) {
|
||||
int tx, ty;
|
||||
int prevCursorX, prevCursorY;
|
||||
@ -1006,6 +1205,7 @@ std::vector<double> MyDiagonalCurve::getPoints () {
|
||||
|
||||
void MyDiagonalCurve::setPoints (const std::vector<double>& p) {
|
||||
int ix = 0;
|
||||
stopNumericalAdjustment();
|
||||
DiagonalCurveType t = (DiagonalCurveType)p[ix++];
|
||||
curve.type = t;
|
||||
if (t==DCT_Parametric) {
|
||||
@ -1028,6 +1228,29 @@ void MyDiagonalCurve::setPoints (const std::vector<double>& p) {
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
void MyDiagonalCurve::setPos(double pos, int chanIdx) {
|
||||
assert (edited_point > -1);
|
||||
if (chanIdx == 0) {
|
||||
curve.x.at(edited_point) = pos;
|
||||
}
|
||||
else if (chanIdx == 1) {
|
||||
curve.y.at(edited_point) = pos;
|
||||
}
|
||||
curveIsDirty = true;
|
||||
setDirty(true);
|
||||
draw(lit_point);
|
||||
notifyListener ();
|
||||
}
|
||||
|
||||
void MyDiagonalCurve::stopNumericalAdjustment() {
|
||||
if (edited_point>-1) {
|
||||
edited_point = grab_point = lit_point = -1;
|
||||
coordinateAdjuster->stopNumericalAdjustment();
|
||||
setDirty(true);
|
||||
draw(lit_point);
|
||||
}
|
||||
}
|
||||
|
||||
void MyDiagonalCurve::setType (DiagonalCurveType t) {
|
||||
|
||||
curve.type = t;
|
||||
@ -1081,6 +1304,8 @@ void MyDiagonalCurve::updateBackgroundHistogram (LUTu & hist) {
|
||||
|
||||
void MyDiagonalCurve::reset(const std::vector<double> &resetCurve, double identityValue) {
|
||||
|
||||
stopNumericalAdjustment();
|
||||
|
||||
if (!resetCurve.empty()) {
|
||||
setPoints(resetCurve);
|
||||
return;
|
||||
|
@ -49,7 +49,7 @@ class MyDiagonalCurve : public MyCurve {
|
||||
|
||||
protected:
|
||||
DiagonalCurveDescr curve;
|
||||
int grab_point; // the point that the user is moving
|
||||
int grab_point; // the point that the user is moving by mouse
|
||||
int closest_point; // the point that is the closest from the cursor
|
||||
int lit_point; // the point that is lit when the cursor is near it
|
||||
double clampedX; // clamped grabbed point X coordinates in the [0;1] range
|
||||
@ -63,12 +63,18 @@ class MyDiagonalCurve : public MyCurve {
|
||||
int activeParam;
|
||||
unsigned int* bghist; // histogram values
|
||||
bool bghistvalid;
|
||||
|
||||
void draw (int handle);
|
||||
void interpolate ();
|
||||
void getCursorPosition(Gdk::EventType evType, bool isHint, int evX, int evY, Gdk::ModifierType modifierKey);
|
||||
void findClosestPoint();
|
||||
CursorShape motionNotify(CursorShape type, double minDistanceX, double minDistanceY, int num);
|
||||
std::vector<double> get_vector (int veclen);
|
||||
void get_LUT (LUTf &lut);
|
||||
// Get the cursor position and unclamped position from the curve given an X value ; BEWARE: can be time consuming, use with care
|
||||
void getCursorPositionFromCurve(float x);
|
||||
void getCursorPositionFromCurve(int x);
|
||||
// Get the cursor position and unclamped value depending on cursor's position in the graph
|
||||
void getCursorPosition(Gdk::EventType evType, bool isHint, int evX, int evY, Gdk::ModifierType modifierKey);
|
||||
|
||||
public:
|
||||
MyDiagonalCurve ();
|
||||
@ -81,10 +87,13 @@ class MyDiagonalCurve : public MyCurve {
|
||||
void reset (const std::vector<double> &resetCurve, double identityValue=0.5);
|
||||
void updateBackgroundHistogram (LUTu & hist);
|
||||
|
||||
void pipetteMouseOver (EditDataProvider *provider, int modifierKey);
|
||||
void pipetteMouseOver (CurveEditor *ce, EditDataProvider *provider, int modifierKey);
|
||||
void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey);
|
||||
void pipetteButton1Released(EditDataProvider *provider);
|
||||
void pipetteDrag(EditDataProvider *provider, int modifierKey);
|
||||
|
||||
virtual void setPos(double pos, int chanIdx);
|
||||
virtual void stopNumericalAdjustment();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -37,6 +37,9 @@ MyFlatCurve::MyFlatCurve () {
|
||||
|
||||
//bghist = new unsigned int[256];
|
||||
|
||||
editedPos.resize(4);
|
||||
editedPos.at(0) = editedPos.at(1) = editedPos.at(2) = editedPos.at(3) = 0.0;
|
||||
|
||||
signal_event().connect( sigc::mem_fun(*this, &MyFlatCurve::handleEvents) );
|
||||
|
||||
// By default, we create a curve with 8 control points
|
||||
@ -55,7 +58,7 @@ std::vector<double> MyFlatCurve::get_vector (int veclen) {
|
||||
|
||||
// Get the curve control points
|
||||
std::vector<double> curveDescr = getPoints ();
|
||||
rtengine::FlatCurve* rtcurve = new rtengine::FlatCurve (curveDescr, periodic, veclen*1.2 > 5000 ? 5000 : veclen*1.2);
|
||||
rtengine::FlatCurve rtcurve(curveDescr, periodic, veclen*1.2 > 5000 ? 5000 : veclen*1.2);
|
||||
|
||||
// Create the sample values that will be converted
|
||||
std::vector<double> samples;
|
||||
@ -64,26 +67,38 @@ std::vector<double> MyFlatCurve::get_vector (int veclen) {
|
||||
samples.at(i) = (double) i / (veclen - 1.0);
|
||||
|
||||
// Converting the values
|
||||
rtcurve->getVal (samples, convertedValues);
|
||||
rtcurve.getVal (samples, convertedValues);
|
||||
|
||||
// Cleanup and return
|
||||
delete rtcurve;
|
||||
return convertedValues;
|
||||
}
|
||||
|
||||
void MyFlatCurve::get_LUT (LUTf &lut) {
|
||||
|
||||
int size = lut.getSize();
|
||||
|
||||
// Get the curve control points
|
||||
std::vector<double> curveDescr = getPoints ();
|
||||
rtengine::FlatCurve rtcurve(curveDescr, periodic, lut.getUpperBound()*1.2 > 5000 ? 5000 : lut.getUpperBound()*1.2);
|
||||
|
||||
double t;
|
||||
double maxVal = double(lut.getUpperBound());
|
||||
for (int i = 0; i < size; i++) {
|
||||
t = double(i) / maxVal;
|
||||
lut[i] = rtcurve.getVal (t);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void MyFlatCurve::interpolate () {
|
||||
|
||||
prevGraphW = graphW;
|
||||
prevGraphH = graphH;
|
||||
int nbPoints = graphW-2;
|
||||
point.resize (nbPoints);
|
||||
std::vector<double> vector = get_vector (nbPoints);
|
||||
for (int i = 0; i < nbPoints; ++i) {
|
||||
float currX = float(i)/float(nbPoints-1);
|
||||
point.at(i).setCoords(float(graphX)+1.5f+float(graphW-3)*currX, float(graphY)-1.5f-float(graphH-3)*float(vector.at(i)));
|
||||
}
|
||||
upoint.clear ();
|
||||
lpoint.clear ();
|
||||
point(nbPoints);
|
||||
get_LUT (point);
|
||||
upoint.reset ();
|
||||
lpoint.reset ();
|
||||
|
||||
curveIsDirty = false;
|
||||
}
|
||||
@ -98,7 +113,8 @@ void MyFlatCurve::draw () {
|
||||
return;
|
||||
|
||||
// re-calculate curve if dimensions changed
|
||||
if (curveIsDirty || prevGraphW != graphW || prevGraphH != graphH || (int)point.size() != graphW-2)
|
||||
int currPointSize = point.getUpperBound();
|
||||
if (curveIsDirty || /*prevGraphW != graphW || prevGraphH != graphH ||*/ (currPointSize==200 && (graphW-3>200)) || (currPointSize>200 && (graphW-2<=200 || graphW-3!=currPointSize)))
|
||||
interpolate ();
|
||||
|
||||
double innerW = double(graphW-2);
|
||||
@ -228,22 +244,30 @@ void MyFlatCurve::draw () {
|
||||
cr->set_line_width (coloredLineWidth);
|
||||
|
||||
// draw the lit_point's horizontal line
|
||||
if (i == lit_point) {
|
||||
|
||||
bool drawHLine = false;
|
||||
if (edited_point>-1) {
|
||||
if (i == edited_point) {
|
||||
cr->set_line_width (2*coloredLineWidth);
|
||||
drawHLine = true;
|
||||
}
|
||||
}
|
||||
else if (i == lit_point) {
|
||||
if ( (area&(FCT_Area_H|FCT_Area_V|FCT_Area_Point)) || editedHandle==FCT_EditedHandle_CPointUD) {
|
||||
|
||||
if (editedHandle&(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointY)) {
|
||||
cr->set_line_width (2*coloredLineWidth);
|
||||
drawHLine = true;
|
||||
}
|
||||
|
||||
colorProvider->colorForValue(curve.x.at(i), curve.y.at(i), CCET_HORIZONTAL_BAR, colorCallerId, this);
|
||||
cr->set_source_rgb (ccRed, ccGreen, ccBlue);
|
||||
|
||||
cr->move_to (double(graphX+1) , double(graphY-1) - innerH*curve.y.at(lit_point));
|
||||
cr->rel_line_to (innerW, 0.);
|
||||
cr->stroke ();
|
||||
}
|
||||
}
|
||||
if (drawHLine) {
|
||||
int point = edited_point>-1 ? edited_point : lit_point;
|
||||
colorProvider->colorForValue(curve.x.at(i), curve.y.at(i), CCET_HORIZONTAL_BAR, colorCallerId, this);
|
||||
cr->set_source_rgb (ccRed, ccGreen, ccBlue);
|
||||
|
||||
cr->move_to (double(graphX+1) , double(graphY-1) - innerH*curve.y.at(point));
|
||||
cr->rel_line_to (innerW, 0.);
|
||||
cr->stroke ();
|
||||
}
|
||||
}
|
||||
}
|
||||
// endif
|
||||
@ -252,12 +276,13 @@ void MyFlatCurve::draw () {
|
||||
else {
|
||||
cr->set_source_rgb (0.5, 0.0, 0.0);
|
||||
|
||||
if ((lit_point>-1) && ((area&(FCT_Area_H|FCT_Area_V|FCT_Area_Point)) || editedHandle==FCT_EditedHandle_CPointUD) ) {
|
||||
if (edited_point>-1 || ((lit_point>-1) && ((area&(FCT_Area_H|FCT_Area_V|FCT_Area_Point)) || editedHandle==FCT_EditedHandle_CPointUD)) ) {
|
||||
// draw the lit_point's vertical line
|
||||
if (editedHandle&(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointY)) {
|
||||
if (edited_point>-1 || (editedHandle&(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointY))) {
|
||||
cr->set_line_width (2.0);
|
||||
}
|
||||
cr->move_to (double(graphX)+1 + innerW*curve.x.at(lit_point), double(graphY-1));
|
||||
int point = edited_point>-1 ? edited_point : lit_point;
|
||||
cr->move_to (double(graphX)+1 + innerW*curve.x.at(point), double(graphY-1));
|
||||
cr->rel_line_to (0., -innerH);
|
||||
cr->stroke ();
|
||||
cr->set_line_width (1.0);
|
||||
@ -266,7 +291,7 @@ void MyFlatCurve::draw () {
|
||||
if (editedHandle&(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointY)) {
|
||||
cr->set_line_width (2.0);
|
||||
}
|
||||
cr->move_to (double(graphX+1) , double(graphY-1) - innerH*curve.y.at(lit_point));
|
||||
cr->move_to (double(graphX+1) , double(graphY-1) - innerH*curve.y.at(point));
|
||||
cr->rel_line_to (innerW, 0.);
|
||||
cr->stroke ();
|
||||
cr->set_line_width (1.0);
|
||||
@ -282,7 +307,7 @@ void MyFlatCurve::draw () {
|
||||
cr->stroke ();
|
||||
|
||||
double lineMinLength = 1. / graphW * SQUARE * 0.9;
|
||||
if (lit_point!=-1 && getHandles(lit_point) && curve.x.at(lit_point)!=-1.) {
|
||||
if (tanHandlesDisplayed && lit_point!=-1 && getHandles(lit_point) && curve.x.at(lit_point)!=-1.) {
|
||||
double x = double(graphX+1) + innerW*curve.x.at(lit_point);
|
||||
double y = double(graphY) - innerH*curve.y.at(lit_point);
|
||||
double x2;
|
||||
@ -353,26 +378,30 @@ void MyFlatCurve::draw () {
|
||||
// draw curve
|
||||
c = style->get_fg (state);
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
cr->move_to (point.at(0).x, point.at(0).y);
|
||||
for (int i=1; i<(int)point.size(); i++)
|
||||
cr->line_to (double(point.at(i).x), double(point.at(i).y));
|
||||
float graphH_ = float(graphH-3);
|
||||
float graphX_ = float(graphX)+1.5;
|
||||
float graphY_ = float(graphY)-1.5;
|
||||
cr->move_to (graphX_, getVal(point, 0)*-graphH_+graphY_);
|
||||
for (int i=1; i<graphW-2; ++i)
|
||||
cr->line_to (float(i)+graphX_, getVal(point, i)*-graphH_+graphY_);
|
||||
cr->stroke ();
|
||||
|
||||
// draw bullets
|
||||
//if (curve.type!=FCT_Parametric)
|
||||
for (int i = 0; i < (int)curve.x.size(); ++i) {
|
||||
if (curve.x.at(i) != -1.) {
|
||||
if (i == lit_point) {
|
||||
if (colorProvider) {
|
||||
if (i == edited_point)
|
||||
cr->set_source_rgb (1.0, 0.0, 0.0);
|
||||
else if (i == lit_point) {
|
||||
if (colorProvider && edited_point==-1) {
|
||||
colorProvider->colorForValue(curve.x.at(i), curve.y.at(i), CCET_POINT, colorCallerId, this);
|
||||
cr->set_source_rgb (ccRed, ccGreen, ccBlue);
|
||||
}
|
||||
else
|
||||
cr->set_source_rgb (1.0, 0.0, 0.0);
|
||||
}
|
||||
else if (i == snapToElmt) {
|
||||
else if (i == snapToElmt || i == edited_point)
|
||||
cr->set_source_rgb (1.0, 0.0, 0.0);
|
||||
}
|
||||
else if (curve.y.at(i) == 0.5)
|
||||
cr->set_source_rgb (0.0, 0.5, 0.0);
|
||||
else
|
||||
@ -383,6 +412,15 @@ void MyFlatCurve::draw () {
|
||||
|
||||
cr->arc (x, y, (double)RADIUS, 0, 2*M_PI);
|
||||
cr->fill ();
|
||||
|
||||
if (i == edited_point) {
|
||||
cr->set_source_rgb (1.0, 0.0, 0.0);
|
||||
cr->set_line_width(2.);
|
||||
cr->arc (x, y, RADIUS+3.5, 0, 2*M_PI);
|
||||
cr->stroke();
|
||||
cr->set_line_width(1.);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// endif
|
||||
@ -499,7 +537,8 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
// setDrawRectangle will allocate the backbuffer Surface
|
||||
if (setDrawRectangle(win, 0, 0, get_allocation().get_width(), get_allocation().get_height())) {
|
||||
setDirty(true);
|
||||
curveIsDirty = true;
|
||||
if (prevGraphW > 200 || graphW > 200)
|
||||
curveIsDirty = true;
|
||||
}
|
||||
draw ();
|
||||
GdkRectangle *rectangle = &(event->expose.area);
|
||||
@ -510,7 +549,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
}
|
||||
|
||||
case Gdk::BUTTON_PRESS:
|
||||
//if (curve.type!=FCT_Parametric) {
|
||||
if (edited_point==-1) { //curve.type!=FCT_Parametric) {
|
||||
if (event->button.button == 1) {
|
||||
buttonPressed = true;
|
||||
add_modal_grab ();
|
||||
@ -544,6 +583,10 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
curve.rightTangent.insert (itrt, 0);
|
||||
num++;
|
||||
|
||||
if (mod_type & GDK_CONTROL_MASK) {
|
||||
clampedY = point.getVal01(clampedX);
|
||||
}
|
||||
|
||||
// the graph is refreshed only if a new point is created
|
||||
curve.x.at(closest_point) = clampedX;
|
||||
curve.y.at(closest_point) = clampedY;
|
||||
@ -593,14 +636,85 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event->button.button == 3) {
|
||||
/* get the pointer position */
|
||||
getCursorPosition(Gdk::EventType(event->type), event->motion.is_hint!=0, int(event->button.x), int(event->button.y), Gdk::ModifierType(event->button.state));
|
||||
getMouseOverArea();
|
||||
if (lit_point>-1 && lit_point!=edited_point) {
|
||||
if (editedHandle == FCT_EditedHandle_None) {
|
||||
if (area == FCT_Area_Point || area == FCT_Area_V) {
|
||||
// the cursor is close to an existing point
|
||||
if (!coordinateAdjuster->is_visible())
|
||||
coordinateAdjuster->showMe(this);
|
||||
|
||||
new_type = CSArrow;
|
||||
tanHandlesDisplayed = false;
|
||||
edited_point = lit_point;
|
||||
setDirty(true);
|
||||
draw ();
|
||||
std::vector<CoordinateAdjuster::Boundaries> newBoundaries(4);
|
||||
unsigned int size = curve.x.size();
|
||||
if (edited_point == 0) { newBoundaries.at(0).minVal = 0.; newBoundaries.at(0).maxVal = curve.x.at(1); }
|
||||
else if (edited_point == size-1) { newBoundaries.at(0).minVal = curve.x.at(edited_point-1); newBoundaries.at(0).maxVal = 1.; }
|
||||
else if (curve.x.size() > 2) { newBoundaries.at(0).minVal = curve.x.at(edited_point-1); newBoundaries.at(0).maxVal = curve.x.at(edited_point+1); }
|
||||
newBoundaries.at(1).minVal = 0.; newBoundaries.at(1).maxVal = 1.;
|
||||
newBoundaries.at(2).minVal = 0.; newBoundaries.at(2).maxVal = 1.;
|
||||
newBoundaries.at(3).minVal = 0.; newBoundaries.at(3).maxVal = 1.;
|
||||
retval = true;
|
||||
editedPos.at(0) = curve.x.at(edited_point);
|
||||
editedPos.at(1) = curve.y.at(edited_point);
|
||||
editedPos.at(2) = curve.leftTangent.at(edited_point);
|
||||
editedPos.at(3) = curve.rightTangent.at(edited_point);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
coordinateAdjuster->startNumericalAdjustment(newBoundaries);
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = true;
|
||||
}
|
||||
if (buttonPressed) retval = true;
|
||||
//}
|
||||
}
|
||||
else { // if (edited_point > -1)
|
||||
if (event->button.button == 3) {
|
||||
// do we edit another point?
|
||||
/* get the pointer position */
|
||||
getCursorPosition(Gdk::EventType(event->type), event->motion.is_hint!=0, int(event->button.x), int(event->button.y), Gdk::ModifierType(event->button.state));
|
||||
getMouseOverArea();
|
||||
if (area == FCT_Area_Point || area == FCT_Area_V) {
|
||||
// the cursor is close to an existing point
|
||||
if (lit_point != edited_point) {
|
||||
edited_point = lit_point;
|
||||
setDirty(true);
|
||||
draw ();
|
||||
std::vector<CoordinateAdjuster::Boundaries> newBoundaries(4);
|
||||
unsigned int size = curve.x.size();
|
||||
if (edited_point == 0) { newBoundaries.at(0).minVal = 0.; newBoundaries.at(0).maxVal = curve.x.at(1); }
|
||||
else if (edited_point == size-1) { newBoundaries.at(0).minVal = curve.x.at(edited_point-1); newBoundaries.at(0).maxVal = 1.; }
|
||||
else if (curve.x.size() > 2) { newBoundaries.at(0).minVal = curve.x.at(edited_point-1); newBoundaries.at(0).maxVal = curve.x.at(edited_point+1); }
|
||||
newBoundaries.at(1).minVal = 0.; newBoundaries.at(1).maxVal = 1.;
|
||||
newBoundaries.at(2).minVal = 0.; newBoundaries.at(2).maxVal = 1.;
|
||||
newBoundaries.at(3).minVal = 0.; newBoundaries.at(3).maxVal = 1.;
|
||||
editedPos.at(0) = curve.x.at(edited_point);
|
||||
editedPos.at(1) = curve.y.at(edited_point);
|
||||
editedPos.at(2) = curve.leftTangent.at(edited_point);
|
||||
editedPos.at(3) = curve.rightTangent.at(edited_point);
|
||||
coordinateAdjuster->switchAdjustedPoint(editedPos, newBoundaries);
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
else if (area == FCT_Area_Insertion) {
|
||||
// the cursor is inside the graph but away from existing points
|
||||
new_type = CSPlus;
|
||||
curveIsDirty = true;
|
||||
stopNumericalAdjustment();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Gdk::BUTTON_RELEASE:
|
||||
//if (curve.type!=FCT_Parametric) {
|
||||
if (edited_point==-1) { //curve.type!=FCT_Parametric) {
|
||||
if (buttonPressed && event->button.button == 1) {
|
||||
int src, dst;
|
||||
buttonPressed = false;
|
||||
@ -684,7 +798,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
retval = true;
|
||||
//notifyListener ();
|
||||
}
|
||||
//}
|
||||
}
|
||||
break;
|
||||
|
||||
case Gdk::MOTION_NOTIFY:
|
||||
@ -722,7 +836,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
|
||||
case (FCT_EditedHandle_None): {
|
||||
|
||||
if ((lit_point != -1 && previous_lit_point != lit_point) && (area&(FCT_Area_V|FCT_Area_Point))) {
|
||||
if ((lit_point != -1 && previous_lit_point != lit_point) && (area&(FCT_Area_V|FCT_Area_Point)) && edited_point==-1) {
|
||||
|
||||
bool sameSide = false;
|
||||
|
||||
@ -771,54 +885,92 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (lit_point == -1) {
|
||||
else if (lit_point == -1 || edited_point>-1) {
|
||||
tanHandlesDisplayed = false;
|
||||
}
|
||||
|
||||
|
||||
switch (area) {
|
||||
if (edited_point==-1) {
|
||||
switch (area) {
|
||||
|
||||
case (FCT_Area_Insertion):
|
||||
new_type = CSPlus;
|
||||
break;
|
||||
case (FCT_Area_Point):
|
||||
//new_type = CSMove;
|
||||
//break;
|
||||
case (FCT_Area_V):
|
||||
new_type = CSMove;
|
||||
break;
|
||||
case (FCT_Area_H):
|
||||
new_type = CSResizeHeight;
|
||||
break;
|
||||
case (FCT_Area_LeftTan):
|
||||
new_type = CSMoveLeft;
|
||||
break;
|
||||
case (FCT_Area_RightTan):
|
||||
new_type = CSMoveRight;
|
||||
break;
|
||||
case (FCT_Area_None):
|
||||
default:
|
||||
new_type = CSArrow;
|
||||
break;
|
||||
case (FCT_Area_Insertion):
|
||||
new_type = CSPlus;
|
||||
break;
|
||||
case (FCT_Area_Point):
|
||||
//new_type = CSMove;
|
||||
//break;
|
||||
case (FCT_Area_V):
|
||||
new_type = CSMove;
|
||||
break;
|
||||
case (FCT_Area_H):
|
||||
new_type = CSResizeHeight;
|
||||
break;
|
||||
case (FCT_Area_LeftTan):
|
||||
new_type = CSMoveLeft;
|
||||
break;
|
||||
case (FCT_Area_RightTan):
|
||||
new_type = CSMoveRight;
|
||||
break;
|
||||
case (FCT_Area_None):
|
||||
default:
|
||||
new_type = CSArrow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((lit_point != previous_lit_point) || (prevArea != area)) {
|
||||
setDirty(true);
|
||||
draw ();
|
||||
}
|
||||
|
||||
if (coordinateAdjuster->is_visible() && edited_point==-1) {
|
||||
if (lit_point > -1) {
|
||||
if (lit_point != previous_lit_point) {
|
||||
editedPos.at(0) = curve.x.at(lit_point);
|
||||
editedPos.at(1) = curve.y.at(lit_point);
|
||||
editedPos.at(2) = curve.leftTangent.at(lit_point);
|
||||
editedPos.at(3) = curve.rightTangent.at(lit_point);
|
||||
}
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
else if (area == FCT_Area_Insertion) {
|
||||
editedPos.at(0) = clampedX;
|
||||
editedPos.at(1) = clampedY;
|
||||
editedPos.at(2) = 0.;
|
||||
editedPos.at(3) = 0.;
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
else {
|
||||
editedPos.at(0) = editedPos.at(1) = editedPos.at(2) = editedPos.at(3) = 0;
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case (FCT_EditedHandle_CPoint):
|
||||
movePoint(true, true);
|
||||
if (coordinateAdjuster->is_visible()) {
|
||||
editedPos.at(0) = curve.x.at(lit_point);
|
||||
editedPos.at(1) = curve.y.at(lit_point);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case (FCT_EditedHandle_CPointX):
|
||||
movePoint(true, false);
|
||||
if (coordinateAdjuster->is_visible()) {
|
||||
editedPos.at(0) = curve.x.at(lit_point);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case (FCT_EditedHandle_CPointY):
|
||||
movePoint(false, true);
|
||||
if (coordinateAdjuster->is_visible()) {
|
||||
editedPos.at(1) = curve.y.at(lit_point);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case (FCT_EditedHandle_LeftTan): {
|
||||
@ -843,6 +995,10 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
setDirty(true);
|
||||
draw ();
|
||||
notifyListener ();
|
||||
if (coordinateAdjuster->is_visible()) {
|
||||
editedPos.at(2) = curve.leftTangent.at(lit_point);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -869,6 +1025,8 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
setDirty(true);
|
||||
draw ();
|
||||
notifyListener ();
|
||||
editedPos.at(3) = curve.rightTangent.at(lit_point);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -879,6 +1037,23 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (edited_point==-1) {
|
||||
if (lit_point == -1) {
|
||||
editedPos.at(0) = editedPos.at(1) = editedPos.at(2) = editedPos.at(3) = 0;
|
||||
}
|
||||
else if (editedPos.at(0) != curve.x.at(lit_point)
|
||||
|| editedPos.at(1) != curve.y.at(lit_point)
|
||||
|| editedPos.at(2) != curve.leftTangent.at(lit_point)
|
||||
|| editedPos.at(3) != curve.rightTangent.at(lit_point))
|
||||
{
|
||||
editedPos.at(0) = curve.x.at(lit_point);
|
||||
editedPos.at(1) = curve.y.at(lit_point);
|
||||
editedPos.at(2) = curve.leftTangent.at(lit_point);
|
||||
editedPos.at(3) = curve.rightTangent.at(lit_point);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retval = true;
|
||||
@ -908,7 +1083,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
void MyFlatCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey) {
|
||||
void MyFlatCurve::pipetteMouseOver (CurveEditor *ce, EditDataProvider *provider, int modifierKey) {
|
||||
if (!provider) {
|
||||
// occurs when leaving the preview area -> cleanup the curve editor
|
||||
pipetteR = pipetteG = pipetteB = -1.f;
|
||||
@ -921,7 +1096,7 @@ void MyFlatCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey)
|
||||
pipetteB = provider->pipetteVal[2];
|
||||
pipetteVal = 0.f;
|
||||
if (listener)
|
||||
pipetteVal = listener->blendPipetteValues(pipetteR, pipetteG, pipetteB);
|
||||
pipetteVal = listener->blendPipetteValues(ce, pipetteR, pipetteG, pipetteB);
|
||||
else {
|
||||
int n = 0;
|
||||
if (pipetteR != -1.f) {
|
||||
@ -958,7 +1133,8 @@ void MyFlatCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey)
|
||||
// get the pointer position
|
||||
int px = graphX + int(float(graphW)*pipetteVal); // WARNING: converting pipetteVal from float to int, precision loss here!
|
||||
getCursorPosition(Gdk::EventType(Gdk::BUTTON_PRESS), false, px, graphY, Gdk::ModifierType(modifierKey));
|
||||
getMouseOverArea();
|
||||
if (edited_point==-1)
|
||||
getMouseOverArea();
|
||||
|
||||
if (area==FCT_Area_Point)
|
||||
area = FCT_Area_V;
|
||||
@ -966,13 +1142,26 @@ void MyFlatCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey)
|
||||
snapToMinDistY = snapToMinDistX = 10.;
|
||||
snapToValY = snapToValX = 0.;
|
||||
|
||||
if (editedHandle==FCT_EditedHandle_None && lit_point != previous_lit_point) {
|
||||
setDirty(true);
|
||||
draw ();
|
||||
if (edited_point==-1) {
|
||||
if (editedHandle==FCT_EditedHandle_None && lit_point != previous_lit_point) {
|
||||
setDirty(true);
|
||||
draw ();
|
||||
}
|
||||
}
|
||||
else
|
||||
draw();
|
||||
|
||||
if (edited_point==-1) {
|
||||
editedPos.at(0) = pipetteVal;
|
||||
editedPos.at(1) = point.getVal01(pipetteVal);
|
||||
coordinateAdjuster->setPos(editedPos);
|
||||
}
|
||||
}
|
||||
|
||||
void MyFlatCurve::pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) {
|
||||
if (edited_point>-1)
|
||||
return;
|
||||
|
||||
buttonPressed = true;
|
||||
|
||||
// get the pointer position
|
||||
@ -1040,6 +1229,9 @@ void MyFlatCurve::pipetteButton1Pressed(EditDataProvider *provider, int modifier
|
||||
}
|
||||
|
||||
void MyFlatCurve::pipetteButton1Released(EditDataProvider *provider) {
|
||||
if (edited_point>-1)
|
||||
return;
|
||||
|
||||
buttonPressed = false;
|
||||
remove_modal_grab ();
|
||||
|
||||
@ -1057,6 +1249,8 @@ void MyFlatCurve::pipetteButton1Released(EditDataProvider *provider) {
|
||||
}
|
||||
|
||||
void MyFlatCurve::pipetteDrag(EditDataProvider *provider, int modifierKey) {
|
||||
if (edited_point>-1)
|
||||
return;
|
||||
|
||||
snapToMinDistY = snapToMinDistX = 10.;
|
||||
snapToValY = snapToValX = 0.;
|
||||
@ -1423,6 +1617,7 @@ std::vector<double> MyFlatCurve::getPoints () {
|
||||
|
||||
void MyFlatCurve::setPoints (const std::vector<double>& p) {
|
||||
int ix = 0;
|
||||
stopNumericalAdjustment();
|
||||
FlatCurveType t = (FlatCurveType)p[ix++];
|
||||
curve.type = t;
|
||||
if (t==FCT_MinMaxCPoints) {
|
||||
@ -1442,6 +1637,38 @@ void MyFlatCurve::setPoints (const std::vector<double>& p) {
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
void MyFlatCurve::setPos(double pos, int chanIdx) {
|
||||
assert (edited_point > -1);
|
||||
switch (chanIdx) {
|
||||
case (0):
|
||||
curve.x.at(edited_point) = pos;
|
||||
break;
|
||||
case (1):
|
||||
curve.y.at(edited_point) = pos;
|
||||
break;
|
||||
case (2):
|
||||
curve.leftTangent.at(edited_point) = pos;
|
||||
break;
|
||||
case (3):
|
||||
curve.rightTangent.at(edited_point) = pos;
|
||||
break;
|
||||
}
|
||||
curveIsDirty = true;
|
||||
setDirty(true);
|
||||
draw();
|
||||
notifyListener ();
|
||||
}
|
||||
|
||||
void MyFlatCurve::stopNumericalAdjustment() {
|
||||
if (edited_point>-1) {
|
||||
edited_point = lit_point = -1;
|
||||
area = FCT_Area_None;
|
||||
coordinateAdjuster->stopNumericalAdjustment();
|
||||
setDirty(true);
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
void MyFlatCurve::setType (FlatCurveType t) {
|
||||
|
||||
curve.type = t;
|
||||
@ -1451,6 +1678,8 @@ void MyFlatCurve::setType (FlatCurveType t) {
|
||||
void MyFlatCurve::reset(const std::vector<double> &resetCurve, double identityValue) {
|
||||
calcDimensions();
|
||||
|
||||
stopNumericalAdjustment();
|
||||
|
||||
// If a resetCurve exist (non empty)
|
||||
if (!resetCurve.empty()) {
|
||||
setPoints(resetCurve);
|
||||
|
@ -110,6 +110,7 @@ class MyFlatCurve : public MyCurve {
|
||||
bool getHandles(int n);
|
||||
CursorShape motionNotify(CursorShape type, double minDistanceX, double minDistanceY, int num);
|
||||
std::vector<double> get_vector (int veclen);
|
||||
void get_LUT (LUTf &lut);
|
||||
|
||||
public:
|
||||
MyFlatCurve ();
|
||||
@ -122,10 +123,13 @@ class MyFlatCurve : public MyCurve {
|
||||
void reset (const std::vector<double> &resetCurve, double identityValue=0.5);
|
||||
//void updateBackgroundHistogram (unsigned int* hist);
|
||||
|
||||
void pipetteMouseOver (EditDataProvider *provider, int modifierKey);
|
||||
void pipetteMouseOver (CurveEditor *ce, EditDataProvider *provider, int modifierKey);
|
||||
void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey);
|
||||
void pipetteButton1Released(EditDataProvider *provider);
|
||||
void pipetteDrag(EditDataProvider *provider, int modifierKey);
|
||||
|
||||
void setPos(double pos, int chanIdx);
|
||||
virtual void stopNumericalAdjustment();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -2,13 +2,15 @@
|
||||
#define _PPVERSION_
|
||||
|
||||
// This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes
|
||||
#define PPVERSION 322
|
||||
#define PPVERSION 323
|
||||
#define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified
|
||||
|
||||
/*
|
||||
Log of version changes
|
||||
322 2015-01-31
|
||||
[Wavelet] new tool using wavelet levels
|
||||
323 2015-10-05
|
||||
[Exposure] Added 'Luminance' tone curve mode
|
||||
322 2015-01-31
|
||||
[Wavelet] new tool using wavelet levels
|
||||
321 2014-08-17
|
||||
[Film Simulation] new tool using HALDCLUT files
|
||||
320 2014-07-02 (yes, same version number... this is an error due to a wrong version number set in comment of previous change)
|
||||
|
@ -123,6 +123,7 @@ ToneCurve::ToneCurve () : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LA
|
||||
toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_WEIGHTEDSTD"));
|
||||
toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE"));
|
||||
toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING"));
|
||||
toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_LUMINANCE"));
|
||||
toneCurveMode->set_active (0);
|
||||
toneCurveMode->set_tooltip_text(M("TP_EXPOSURE_TCMODE_LABEL1"));
|
||||
|
||||
@ -148,6 +149,7 @@ ToneCurve::ToneCurve () : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LA
|
||||
toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_WEIGHTEDSTD"));
|
||||
toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE"));
|
||||
toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING"));
|
||||
toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_LUMINANCE"));
|
||||
toneCurveMode2->set_active (0);
|
||||
toneCurveMode2->set_tooltip_text(M("TP_EXPOSURE_TCMODE_LABEL2"));
|
||||
|
||||
@ -224,10 +226,10 @@ void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) {
|
||||
shape->setUnChanged (!pedited->toneCurve.curve);
|
||||
shape2->setUnChanged (!pedited->toneCurve.curve2);
|
||||
if (!pedited->toneCurve.curveMode) {
|
||||
toneCurveMode->set_active(4);
|
||||
toneCurveMode->set_active(5);
|
||||
}
|
||||
if (!pedited->toneCurve.curveMode2) {
|
||||
toneCurveMode2->set_active(4);
|
||||
toneCurveMode2->set_active(5);
|
||||
}
|
||||
}
|
||||
if (pedited)
|
||||
@ -292,12 +294,14 @@ void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) {
|
||||
else if (tcMode == 1) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_WEIGHTEDSTD;
|
||||
else if (tcMode == 2) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_FILMLIKE;
|
||||
else if (tcMode == 3) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_SATANDVALBLENDING;
|
||||
else if (tcMode == 4) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_LUMINANCE;
|
||||
|
||||
tcMode = toneCurveMode2->get_active_row_number();
|
||||
if (tcMode == 0) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD;
|
||||
else if (tcMode == 1) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_WEIGHTEDSTD;
|
||||
else if (tcMode == 2) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_FILMLIKE;
|
||||
else if (tcMode == 3) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_SATANDVALBLENDING;
|
||||
else if (tcMode == 4) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_LUMINANCE;
|
||||
|
||||
if (pedited) {
|
||||
pedited->toneCurve.expcomp = expcomp->getEditedState ();
|
||||
@ -312,8 +316,8 @@ void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) {
|
||||
pedited->toneCurve.clip = clipDirty;
|
||||
pedited->toneCurve.curve = !shape->isUnChanged ();
|
||||
pedited->toneCurve.curve2 = !shape2->isUnChanged ();
|
||||
pedited->toneCurve.curveMode = toneCurveMode->get_active_row_number() != 4;
|
||||
pedited->toneCurve.curveMode2 = toneCurveMode2->get_active_row_number() != 4;
|
||||
pedited->toneCurve.curveMode = toneCurveMode->get_active_row_number() != 5;
|
||||
pedited->toneCurve.curveMode2 = toneCurveMode2->get_active_row_number() != 5;
|
||||
}
|
||||
if (pedited) {
|
||||
pedited->toneCurve.method = method->get_active_row_number()!=4;
|
||||
@ -446,6 +450,19 @@ bool ToneCurve::curveMode2Changed_ () {
|
||||
return false;
|
||||
}
|
||||
|
||||
float ToneCurve::blendPipetteValues(CurveEditor *ce, float chan1, float chan2, float chan3) {
|
||||
// assuming that all the channels are used...
|
||||
if (ce == shape) {
|
||||
if (toneCurveMode->get_active_row_number() == 4)
|
||||
return chan1*0.2126729f + chan2*0.7151521f + chan3*0.0721750f;
|
||||
}
|
||||
else if (ce == shape2) {
|
||||
if (toneCurveMode2->get_active_row_number() == 4)
|
||||
return chan1*0.2126729f + chan2*0.7151521f + chan3*0.0721750f;
|
||||
}
|
||||
return CurveListener::blendPipetteValues(ce, chan1, chan2, chan3);
|
||||
}
|
||||
|
||||
void ToneCurve::adjusterChanged (Adjuster* a, double newval) {
|
||||
|
||||
// Switch off auto exposure if user changes sliders manually
|
||||
|
@ -84,6 +84,7 @@ class ToneCurve : public ToolParamBlock, public AdjusterListener, public Foldabl
|
||||
void autoOpenCurve ();
|
||||
void setEditProvider (EditDataProvider *provider);
|
||||
|
||||
virtual float blendPipetteValues (CurveEditor *ce, float chan1, float chan2, float chan3);
|
||||
|
||||
void adjusterChanged (Adjuster* a, double newval);
|
||||
void neutral_pressed ();
|
||||
|
Loading…
x
Reference in New Issue
Block a user