Solving issue 2610: "Display curve node input/output values" + add a new tone curve mode (Luminance)

This commit is contained in:
Hombrenatureh.510 2015-05-21 00:07:22 +02:00
parent 06deac5da4
commit 7c0b8e6fe1
41 changed files with 1434 additions and 239 deletions

View File

@ -9,10 +9,15 @@ ADJUSTER_RESET_TO_DEFAULT;Réglages par défaut
BATCHQUEUE_AUTOSTART;Démarrage auto BATCHQUEUE_AUTOSTART;Démarrage auto
BATCHQUEUE_DESTFILENAME;Chemin et nom de fichier BATCHQUEUE_DESTFILENAME;Chemin et nom de fichier
BATCH_PROCESSING;Traitement par lot 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_CURVES;Courbes
CURVEEDITOR_CURVE;Courbe CURVEEDITOR_CURVE;Courbe
CURVEEDITOR_CUSTOM;Personnalisé CURVEEDITOR_CUSTOM;Personnalisé
CURVEEDITOR_DARKS;Zones sombres 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_HIGHLIGHTS;Hautes lumières
CURVEEDITOR_LIGHTS;Zones claires CURVEEDITOR_LIGHTS;Zones claires
CURVEEDITOR_LINEAR;Linéaire CURVEEDITOR_LINEAR;Linéaire
@ -1171,6 +1176,7 @@ TP_EXPOSURE_SATURATION;Saturation
TP_EXPOSURE_TCMODE_FILMLIKE;Similaire Film TP_EXPOSURE_TCMODE_FILMLIKE;Similaire Film
TP_EXPOSURE_TCMODE_LABEL1;Mode courbe 1 TP_EXPOSURE_TCMODE_LABEL1;Mode courbe 1
TP_EXPOSURE_TCMODE_LABEL2;Mode courbe 2 TP_EXPOSURE_TCMODE_LABEL2;Mode courbe 2
TP_EXPOSURE_TCMODE_LUMINANCE;Luminance
TP_EXPOSURE_TCMODE_SATANDVALBLENDING;Mixage Saturation et Valeur TP_EXPOSURE_TCMODE_SATANDVALBLENDING;Mixage Saturation et Valeur
TP_EXPOSURE_TCMODE_STANDARD;Standard TP_EXPOSURE_TCMODE_STANDARD;Standard
TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Standard Pondéré TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Standard Pondéré

View File

@ -11,10 +11,15 @@ ADJUSTER_RESET_TO_DEFAULT;Reset to default
BATCHQUEUE_AUTOSTART;Auto-start BATCHQUEUE_AUTOSTART;Auto-start
BATCHQUEUE_DESTFILENAME;Path and file name BATCHQUEUE_DESTFILENAME;Path and file name
BATCH_PROCESSING;Batch Processing 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_CURVES;Curves
CURVEEDITOR_CURVE;Curve CURVEEDITOR_CURVE;Curve
CURVEEDITOR_CUSTOM;Custom CURVEEDITOR_CUSTOM;Custom
CURVEEDITOR_DARKS;Darks 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_HIGHLIGHTS;Highlights
CURVEEDITOR_LIGHTS;Lights CURVEEDITOR_LIGHTS;Lights
CURVEEDITOR_LINEAR;Linear CURVEEDITOR_LINEAR;Linear
@ -1358,6 +1363,7 @@ TP_EXPOSURE_SATURATION;Saturation
TP_EXPOSURE_TCMODE_FILMLIKE;Film-like TP_EXPOSURE_TCMODE_FILMLIKE;Film-like
TP_EXPOSURE_TCMODE_LABEL1;Curve mode 1 TP_EXPOSURE_TCMODE_LABEL1;Curve mode 1
TP_EXPOSURE_TCMODE_LABEL2;Curve mode 2 TP_EXPOSURE_TCMODE_LABEL2;Curve mode 2
TP_EXPOSURE_TCMODE_LUMINANCE;Luminance
TP_EXPOSURE_TCMODE_SATANDVALBLENDING;Saturation and Value Blending TP_EXPOSURE_TCMODE_SATANDVALBLENDING;Saturation and Value Blending
TP_EXPOSURE_TCMODE_STANDARD;Standard TP_EXPOSURE_TCMODE_STANDARD;Standard
TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Weighted Standard TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Weighted Standard

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -535,6 +542,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -880,6 +887,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -537,6 +544,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -520,6 +527,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -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" { style "clearlooks-framelessspinbutton" {
# IMPORTANT! # IMPORTANT!
@ -515,6 +522,7 @@ widget "*.MyExpanderTitle" style "clearlooks-expander"
widget "*.ExpanderBox" style "clearlooks-toolFrame" widget "*.ExpanderBox" style "clearlooks-toolFrame"
widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander" widget "*.ExpanderBox.*.MyExpanderTitle" style "clearlooks-subexpander"
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" # The window of the tooltip is called "gtk-tooltip"
################################################################## ##################################################################

View File

@ -84,7 +84,9 @@ protected:
unsigned int maxs; unsigned int maxs;
float maxsf; float maxsf;
T * data; 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: private:
unsigned int owner; unsigned int owner;
#if defined( __SSE2__ ) && defined( __x86_64__ ) #if defined( __SSE2__ ) && defined( __x86_64__ )
@ -109,6 +111,7 @@ public:
data = new T[s]; data = new T[s];
owner = 1; owner = 1;
size = s; size = s;
upperBound = size-1;
maxs=size-2; maxs=size-2;
maxsf = (float)maxs; maxsf = (float)maxs;
#if defined( __SSE2__ ) && defined( __x86_64__ ) #if defined( __SSE2__ ) && defined( __x86_64__ )
@ -131,6 +134,7 @@ public:
data = new T[s]; data = new T[s];
owner = 1; owner = 1;
size = s; size = s;
upperBound = size-1;
maxs=size-2; maxs=size-2;
maxsf = (float)maxs; maxsf = (float)maxs;
#if defined( __SSE2__ ) && defined( __x86_64__ ) #if defined( __SSE2__ ) && defined( __x86_64__ )
@ -155,6 +159,7 @@ public:
data = new T[s]; data = new T[s];
owner = 1; owner = 1;
size = s; size = s;
upperBound = size-1;
maxs=size-2; maxs=size-2;
maxsf = (float)maxs; maxsf = (float)maxs;
#if defined( __SSE2__ ) && defined( __x86_64__ ) #if defined( __SSE2__ ) && defined( __x86_64__ )
@ -199,7 +204,7 @@ public:
* @return number of element in the array * @return number of element in the array
*/ */
int getUpperBound() { int getUpperBound() {
return size>0 ? size-1 : 0; return size>0 ? upperBound : 0;
} }
LUT<T> & operator=(LUT<T> &rhs) { LUT<T> & operator=(LUT<T> &rhs) {
@ -214,6 +219,7 @@ public:
this->owner=1; this->owner=1;
memcpy(this->data,rhs.data,rhs.size*sizeof(T)); memcpy(this->data,rhs.data,rhs.size*sizeof(T));
this->size=rhs.size; this->size=rhs.size;
this->upperBound=rhs.upperBound;
this->maxs=this->size-2; this->maxs=this->size-2;
this->maxsf = (float)this->maxs; this->maxsf = (float)this->maxs;
#if defined( __SSE2__ ) && defined( __x86_64__ ) #if defined( __SSE2__ ) && defined( __x86_64__ )
@ -228,7 +234,7 @@ public:
} }
// use with integer indices // use with integer indices
T& operator[](int index) const { 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__ ) #if defined( __SSE2__ ) && defined( __x86_64__ )
@ -350,7 +356,7 @@ public:
else if (index > maxsf) else if (index > maxsf)
{ {
if (clip & LUT_CLIP_ABOVE) if (clip & LUT_CLIP_ABOVE)
return data[size - 1]; return data[upperBound];
idx =maxs; idx =maxs;
} }
float diff = index - (float) idx; float diff = index - (float) idx;
@ -359,6 +365,27 @@ public:
return (p1 + p2*diff); 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 #ifndef NDEBUG
// Debug facility ; dump the content of the LUT in a file. No control of the filename is done // 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; data = NULL;
owner = 1; owner = 1;
size = 0; size = 0;
upperBound=0;
maxs=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. /** @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) */ 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 { class HueLUT : public LUTf {
@ -413,7 +446,7 @@ class HueLUT : public LUTf {
// use with integer indices // use with integer indices
float& operator[](int index) const { 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 // use with float indices in the [0.;1.] range
@ -422,7 +455,7 @@ class HueLUT : public LUTf {
if (index<0.f) if (index<0.f)
return data[0]; return data[0];
else if (index > 1.f) else if (index > 1.f)
return data[size - 1]; return data[upperBound];
float balance = index - float(idx/500.f); float balance = index - float(idx/500.f);
float h1 = data[idx]; float h1 = data[idx];

View File

@ -154,8 +154,14 @@ public:
* @return luminance value * @return luminance value
*/ */
// xyz_sRGBD65 : conversion matrix from XYZ to sRGB for D65 illuminant: we use diagonal values // 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 float rgbLuminance(float r, float g, float b) {
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]; } // 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;
}
/** /**

View File

@ -585,6 +585,11 @@ class WeightedStdToneCurve : public ToneCurve {
void Apply(float& r, float& g, float& b) const; 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 { class WeightedStdToneCurvebw : public ToneCurve {
private: private:
float Triangle(float refX, float refY, float X2) const; 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)); 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 { inline float WeightedStdToneCurve::Triangle(float a, float a1, float b) const {
if (a != b) { if (a != b) {
float b1; float b1;

View File

@ -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 // Color space conversion to/from XYZ; color spaces adapted to D65
const double xyz_sRGBd65[3][3] = {{0.4124564, 0.3575761, 0.1804375}, 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}}; {0.0193339, 0.1191920, 0.9503041}};
const double sRGBd65_xyz[3][3] = {{ 3.2404542, -1.5371385, -0.4985314}, const double sRGBd65_xyz[3][3] = {{ 3.2404542, -1.5371385, -0.4985314},

View File

@ -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 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) { if (iGammaLUTf) {

View File

@ -1065,6 +1065,9 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol
case (ToneCurveParams::TC_MODE_WEIGHTEDSTD): case (ToneCurveParams::TC_MODE_WEIGHTEDSTD):
method = "WeightedStd"; method = "WeightedStd";
break; break;
case (ToneCurveParams::TC_MODE_LUMINANCE):
method = "Luminance";
break;
} }
keyFile.set_string ("Exposure", "CurveMode", method); 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): case (ToneCurveParams::TC_MODE_WEIGHTEDSTD):
method = "WeightedStd"; method = "WeightedStd";
break; break;
case (ToneCurveParams::TC_MODE_LUMINANCE):
method = "Luminance";
break;
} }
keyFile.set_string ("Exposure", "CurveMode2", method); 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 == "FilmLike") toneCurve.curveMode = ToneCurveParams::TC_MODE_FILMLIKE;
else if (sMode == "SatAndValueBlending") toneCurve.curveMode = ToneCurveParams::TC_MODE_SATANDVALBLENDING; else if (sMode == "SatAndValueBlending") toneCurve.curveMode = ToneCurveParams::TC_MODE_SATANDVALBLENDING;
else if (sMode == "WeightedStd") toneCurve.curveMode = ToneCurveParams::TC_MODE_WEIGHTEDSTD; 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 (pedited) pedited->toneCurve.curveMode = true;
} }
if (keyFile.has_key ("Exposure", "CurveMode2")) { if (keyFile.has_key ("Exposure", "CurveMode2")) {
@ -1916,7 +1923,7 @@ if (keyFile.has_group ("Exposure")) {
if (sMode == "Standard") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD; if (sMode == "Standard") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD;
else if (sMode == "FilmLike") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_FILMLIKE; else if (sMode == "FilmLike") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_FILMLIKE;
else if (sMode == "SatAndValueBlending") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_SATANDVALBLENDING; 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 (pedited) pedited->toneCurve.curveMode2 = true;
} }
if (ppVersion>200) { if (ppVersion>200) {

View File

@ -193,7 +193,8 @@ class ToneCurveParams {
TC_MODE_STD, // Standard modes, the curve is applied on all component individually TC_MODE_STD, // Standard modes, the curve is applied on all component individually
TC_MODE_WEIGHTEDSTD, // Weighted standard mode TC_MODE_WEIGHTEDSTD, // Weighted standard mode
TC_MODE_FILMLIKE, // Film-like mode, as defined in Adobe's reference code 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; bool autoexp;

View File

@ -4,7 +4,7 @@ set (BASESOURCEFILES
exportpanel.cc cursormanager.cc rtwindow.cc renamedlg.cc recentbrowser.cc placesbrowser.cc filepanel.cc editorpanel.cc batchqueuepanel.cc exportpanel.cc cursormanager.cc rtwindow.cc renamedlg.cc recentbrowser.cc placesbrowser.cc filepanel.cc editorpanel.cc batchqueuepanel.cc
ilabel.cc thumbbrowserbase.cc adjuster.cc filebrowserentry.cc filebrowser.cc filethumbnailbuttonset.cc ilabel.cc thumbbrowserbase.cc adjuster.cc filebrowserentry.cc filebrowser.cc filethumbnailbuttonset.cc
cachemanager.cc cacheimagedata.cc shcselector.cc perspective.cc thresholdselector.cc thresholdadjuster.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 coarsepanel.cc cacorrection.cc chmixer.cc blackwhite.cc
resize.cc icmpanel.cc crop.cc shadowshighlights.cc resize.cc icmpanel.cc crop.cc shadowshighlights.cc
impulsedenoise.cc dirpyrdenoise.cc epd.cc impulsedenoise.cc dirpyrdenoise.cc epd.cc

198
rtgui/coordinateadjuster.cc Normal file
View 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
View 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

View File

@ -46,6 +46,10 @@ CurveEditorGroup::~CurveEditorGroup() {
void CurveEditorGroup::hideCurrentCurve() { void CurveEditorGroup::hideCurrentCurve() {
// Setting the curve type to 'Unchanged' hide the CurveEditor // Setting the curve type to 'Unchanged' hide the CurveEditor
if (diagonalSubGroup)
diagonalSubGroup->stopNumericalAdjustment();
if (flatSubGroup)
flatSubGroup->stopNumericalAdjustment();
if (displayedCurve) if (displayedCurve)
displayedCurve->curveType->set_active(false); displayedCurve->curveType->set_active(false);
} }
@ -280,10 +284,10 @@ void CurveEditorGroup::curveChanged () {
/* /*
* Listener called when the user has modified the curve * 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) if (cl)
return cl->blendPipetteValues(chan1, chan2, chan3); return cl->blendPipetteValues(ce, chan1, chan2, chan3);
return -1.f; return -1.f;
} }

View File

@ -89,10 +89,12 @@ protected:
void updateGUI (CurveEditor* ce); void updateGUI (CurveEditor* ce);
void curveResetPressed (); void curveResetPressed ();
void curveChanged (); 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); void setUnChanged (bool uc, CurveEditor* ce);
}; };
class CoordinateProvider;
class CurveEditorSubGroup { class CurveEditorSubGroup {
friend class CurveEditorGroup; friend class CurveEditorGroup;
@ -105,6 +107,7 @@ protected:
int valLinear; int valLinear;
int valUnchanged; int valUnchanged;
CurveEditorGroup *parent; CurveEditorGroup *parent;
int curveBBoxPos; // 0=above, 1=right, 2=below, 3=left
ColoredBar* leftBar; ColoredBar* leftBar;
ColoredBar* bottomBar; ColoredBar* bottomBar;
@ -120,6 +123,9 @@ public:
virtual void refresh(CurveEditor *curveToRefresh) = 0; virtual void refresh(CurveEditor *curveToRefresh) = 0;
virtual void editModeSwitchedOff() = 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 pipetteMouseOver(EditDataProvider *provider, int modifierKey) =0;
virtual void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) =0; virtual void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) =0;
virtual void pipetteButton1Released(EditDataProvider *provider) =0; virtual void pipetteButton1Released(EditDataProvider *provider) =0;

View File

@ -19,6 +19,8 @@
#ifndef _CURVELISTENER_ #ifndef _CURVELISTENER_
#define _CURVELISTENER_ #define _CURVELISTENER_
#include <vector>
class CurveEditor; class CurveEditor;
class CurveListener { class CurveListener {
@ -37,7 +39,7 @@ class CurveListener {
* @param ce CurveEditor that we want to reset * @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) * @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! */ * 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 /** @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. 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 chan2 second channel's value
@param chan3 third channel's value @param chan3 third channel's value
@return the blended 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; float retVal = 0.f;
int n = 0; int n = 0;
if (chan1 != -1.f) { if (chan1 != -1.f) {

View File

@ -27,6 +27,7 @@
#include "shcselector.h" #include "shcselector.h"
#include "adjuster.h" #include "adjuster.h"
#include "mycurve.h" #include "mycurve.h"
#include "mydiagonalcurve.h"
#include "curveeditor.h" #include "curveeditor.h"
#include "diagonalcurveeditorsubgroup.h" #include "diagonalcurveeditorsubgroup.h"
@ -35,6 +36,8 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
editedAdjuster = NULL; editedAdjuster = NULL;
editedAdjusterValue = 0; editedAdjusterValue = 0;
curveBBoxPos = options.curvebboxpos;
valLinear = (int)DCT_Linear; valLinear = (int)DCT_Linear;
valUnchanged = (int)DCT_Unchanged; valUnchanged = (int)DCT_Unchanged;
parent = prt; parent = prt;
@ -66,6 +69,9 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
saveCustom->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); saveCustom->add (*Gtk::manage (new RTImage ("gtk-save-large.png")));
loadCustom = Gtk::manage (new Gtk::Button ()); loadCustom = Gtk::manage (new Gtk::Button ());
loadCustom->add (*Gtk::manage (new RTImage ("gtk-open.png"))); 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 = Gtk::manage (new Gtk::ToggleButton());
editCustom->add (*Gtk::manage (new RTImage ("editmodehand.png"))); editCustom->add (*Gtk::manage (new RTImage ("editmodehand.png")));
editCustom->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); 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 (*copyCustom, Gtk::PACK_SHRINK, 0);
custombbox->pack_end (*saveCustom, Gtk::PACK_SHRINK, 0); custombbox->pack_end (*saveCustom, Gtk::PACK_SHRINK, 0);
custombbox->pack_end (*loadCustom, 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); custombbox->pack_start(*editCustom, Gtk::PACK_SHRINK, 0);
customCurveAndButtons->pack_start (*customCurve, Gtk::PACK_EXPAND_WIDGET, 0); customCurveAndButtons->pack_start (*customCurve, Gtk::PACK_EXPAND_WIDGET, 0);
@ -90,12 +97,21 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
} else if (options.curvebboxpos==3) { } else if (options.curvebboxpos==3) {
customCurveAndButtons->reorder_child(*custombbox, 0); 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 (); customCurveBox->show_all ();
customCoordAdjuster->hide();
saveCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); saveCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) );
loadCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); loadCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) );
copyCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); copyCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) );
pasteCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); 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) ); editCustomConn = editCustom->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editToggled), editCustom) );
saveCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); 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"))); saveNURBS->add (*Gtk::manage (new RTImage ("gtk-save-large.png")));
loadNURBS = Gtk::manage (new Gtk::Button ()); loadNURBS = Gtk::manage (new Gtk::Button ());
loadNURBS->add (*Gtk::manage (new RTImage ("gtk-open.png"))); 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 = Gtk::manage (new Gtk::ToggleButton());
editNURBS->add (*Gtk::manage (new RTImage ("editmodehand.png"))); editNURBS->add (*Gtk::manage (new RTImage ("editmodehand.png")));
editNURBS->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); 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 (*copyNURBS, Gtk::PACK_SHRINK, 0);
NURBSbbox->pack_end (*saveNURBS, Gtk::PACK_SHRINK, 0); NURBSbbox->pack_end (*saveNURBS, Gtk::PACK_SHRINK, 0);
NURBSbbox->pack_end (*loadNURBS, 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); NURBSbbox->pack_start(*editNURBS, Gtk::PACK_SHRINK, 0);
NURBSCurveAndButtons->pack_start (*NURBSCurve, Gtk::PACK_EXPAND_WIDGET, 0); NURBSCurveAndButtons->pack_start (*NURBSCurve, Gtk::PACK_EXPAND_WIDGET, 0);
@ -153,12 +173,21 @@ DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt,
} else if (options.curvebboxpos==3) { } else if (options.curvebboxpos==3) {
NURBSCurveAndButtons->reorder_child(*NURBSbbox, 0); 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 (); NURBSCurveBox->show_all ();
NURBSCoordAdjuster->hide();
saveNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); saveNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) );
loadNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); loadNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) );
pasteNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); pasteNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) );
copyNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); 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) ); editNURBSConn = editNURBS->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editToggled), editNURBS) );
saveNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); saveNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE"));
@ -320,17 +349,17 @@ void DiagonalCurveEditorSubGroup::editModeSwitchedOff () {
bool prevState; bool prevState;
prevState = editCustomConn.block(true); prevState = editCustomConn.block(true);
editCustom->set_active(false); editCustom->set_active(false);
customCurve->pipetteMouseOver(NULL, 0); customCurve->pipetteMouseOver(NULL, NULL, 0);
customCurve->setDirty(true); customCurve->setDirty(true);
if (!prevState) editCustomConn.block(false); if (!prevState) editCustomConn.block(false);
prevState = editNURBSConn.block(true); prevState = editNURBSConn.block(true);
editNURBS->set_active(false); editNURBS->set_active(false);
NURBSCurve->pipetteMouseOver(NULL, 0); NURBSCurve->pipetteMouseOver(NULL, NULL, 0);
NURBSCurve->setDirty(true); NURBSCurve->setDirty(true);
if (!prevState) editNURBSConn.block(false); if (!prevState) editNURBSConn.block(false);
prevState = editParamConn.block(true); prevState = editParamConn.block(true);
editParam->set_active(false); editParam->set_active(false);
paramCurve->pipetteMouseOver(NULL, 0); paramCurve->pipetteMouseOver(NULL, NULL, 0);
paramCurve->setDirty(true); paramCurve->setDirty(true);
if (!prevState) editParamConn.block(false); if (!prevState) editParamConn.block(false);
} }
@ -339,12 +368,12 @@ void DiagonalCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, i
CurveEditor *curveEditor = static_cast<DiagonalCurveEditor*>(parent->displayedCurve); CurveEditor *curveEditor = static_cast<DiagonalCurveEditor*>(parent->displayedCurve);
switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) { switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) {
case (DCT_Spline): case (DCT_Spline):
customCurve->pipetteMouseOver(provider, modifierKey); customCurve->pipetteMouseOver(curveEditor, provider, modifierKey);
customCurve->setDirty(true); customCurve->setDirty(true);
break; break;
case (DCT_Parametric): case (DCT_Parametric):
{ {
paramCurve->pipetteMouseOver(provider, modifierKey); paramCurve->pipetteMouseOver(curveEditor, provider, modifierKey);
paramCurve->setDirty(true); paramCurve->setDirty(true);
float pipetteVal = 0.f; float pipetteVal = 0.f;
editedAdjuster = NULL; editedAdjuster = NULL;
@ -392,7 +421,7 @@ void DiagonalCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, i
} }
break; break;
case (DCT_NURBS): case (DCT_NURBS):
NURBSCurve->pipetteMouseOver(provider, modifierKey); NURBSCurve->pipetteMouseOver(curveEditor, provider, modifierKey);
NURBSCurve->setDirty(true); NURBSCurve->setDirty(true);
break; break;
default: // (DCT_Linear, DCT_Unchanged) 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 * Force the resize of the curve editor, if the displayed one is the requested one
*/ */
@ -773,6 +816,31 @@ void DiagonalCurveEditorSubGroup::pastePressed () {
return; 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) { void DiagonalCurveEditorSubGroup::editToggled (Gtk::ToggleButton *button) {
DiagonalCurveEditor* dCurve = static_cast<DiagonalCurveEditor*>(parent->displayedCurve); DiagonalCurveEditor* dCurve = static_cast<DiagonalCurveEditor*>(parent->displayedCurve);
if (!dCurve) if (!dCurve)

View File

@ -46,18 +46,23 @@ protected:
Adjuster *editedAdjuster; Adjuster *editedAdjuster;
int editedAdjusterValue; int editedAdjusterValue;
CoordinateAdjuster *customCoordAdjuster;
CoordinateAdjuster *NURBSCoordAdjuster;
Gtk::Button* saveCustom; Gtk::Button* saveCustom;
Gtk::Button* loadCustom; Gtk::Button* loadCustom;
Gtk::Button* copyCustom; Gtk::Button* copyCustom;
Gtk::Button* pasteCustom; Gtk::Button* pasteCustom;
Gtk::ToggleButton* editPointCustom;
Gtk::ToggleButton* editCustom; Gtk::ToggleButton* editCustom;
sigc::connection editCustomConn; sigc::connection editCustomConn, editPointCustomConn;
Gtk::Button* saveNURBS; Gtk::Button* saveNURBS;
Gtk::Button* loadNURBS; Gtk::Button* loadNURBS;
Gtk::Button* copyNURBS; Gtk::Button* copyNURBS;
Gtk::Button* pasteNURBS; Gtk::Button* pasteNURBS;
Gtk::ToggleButton* editPointNURBS;
Gtk::ToggleButton* editNURBS; Gtk::ToggleButton* editNURBS;
sigc::connection editNURBSConn; sigc::connection editNURBSConn, editPointNURBSConn;
Gtk::Button* saveParam; Gtk::Button* saveParam;
Gtk::Button* loadParam; Gtk::Button* loadParam;
Gtk::Button* copyParam; Gtk::Button* copyParam;
@ -80,6 +85,8 @@ public:
void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey); void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey);
void pipetteButton1Released(EditDataProvider *provider); void pipetteButton1Released(EditDataProvider *provider);
void pipetteDrag(EditDataProvider *provider, int modifierKey); void pipetteDrag(EditDataProvider *provider, int modifierKey);
void showCoordinateAdjuster(CoordinateProvider *provider);
void stopNumericalAdjustment();
bool curveReset (CurveEditor *ce); bool curveReset (CurveEditor *ce);
@ -91,6 +98,7 @@ protected:
void loadPressed (); void loadPressed ();
void copyPressed (); void copyPressed ();
void pastePressed (); void pastePressed ();
void editPointToggled(Gtk::ToggleButton *button);
void editToggled (Gtk::ToggleButton *button); void editToggled (Gtk::ToggleButton *button);
void removeEditor (); void removeEditor ();
const std::vector<double> getCurveFromGUI (int type); const std::vector<double> getCurveFromGUI (int type);

View File

@ -28,6 +28,7 @@
#include "shcselector.h" #include "shcselector.h"
#include "adjuster.h" #include "adjuster.h"
#include "mycurve.h" #include "mycurve.h"
#include "myflatcurve.h"
#include "curveeditor.h" #include "curveeditor.h"
#include "flatcurveeditorsubgroup.h" #include "flatcurveeditorsubgroup.h"
@ -37,6 +38,8 @@ FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::u
valUnchanged = (int)FCT_Unchanged; valUnchanged = (int)FCT_Unchanged;
parent = prt; parent = prt;
curveBBoxPos = options.curvebboxpos;
// ControlPoints curve // ControlPoints curve
CPointsCurveBox = new Gtk::VBox (); CPointsCurveBox = new Gtk::VBox ();
CPointsCurveBox->set_spacing(4); CPointsCurveBox->set_spacing(4);
@ -63,6 +66,9 @@ FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::u
loadCPoints = Gtk::manage (new Gtk::Button ()); loadCPoints = Gtk::manage (new Gtk::Button ());
loadCPoints->add (*Gtk::manage (new RTImage ("gtk-open.png"))); loadCPoints->add (*Gtk::manage (new RTImage ("gtk-open.png")));
editCPoints = Gtk::manage (new Gtk::ToggleButton()); 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->add (*Gtk::manage (new RTImage ("editmodehand.png")));
editCPoints->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); editCPoints->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP"));
editCPoints->hide(); editCPoints->hide();
@ -71,6 +77,7 @@ FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::u
CPointsbbox->pack_end (*copyCPoints, Gtk::PACK_SHRINK, 0); CPointsbbox->pack_end (*copyCPoints, Gtk::PACK_SHRINK, 0);
CPointsbbox->pack_end (*saveCPoints, Gtk::PACK_SHRINK, 0); CPointsbbox->pack_end (*saveCPoints, Gtk::PACK_SHRINK, 0);
CPointsbbox->pack_end (*loadCPoints, 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); CPointsbbox->pack_start(*editCPoints, Gtk::PACK_SHRINK, 0);
CPointsCurveAndButtons->pack_start (*CPointsCurve, Gtk::PACK_EXPAND_WIDGET, 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) { } else if (options.curvebboxpos==3) {
CPointsCurveAndButtons->reorder_child(*CPointsbbox, 0); 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 (); CPointsCurveBox->show_all ();
CPointsCoordAdjuster->hide();
saveCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::savePressed) ); saveCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::savePressed) );
loadCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::loadPressed) ); loadCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::loadPressed) );
copyCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::copyPressed) ); copyCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::copyPressed) );
pasteCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::pastePressed) ); 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) ); editCPointsConn = editCPoints->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &FlatCurveEditorSubGroup::editToggled), editCPoints) );
saveCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); saveCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE"));
@ -117,6 +141,17 @@ FlatCurveEditor* FlatCurveEditorSubGroup::addCurve(Glib::ustring curveLabel, boo
return newCE; 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 * 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 // toggling off all edit buttons, even if only one is toggle on
bool prevState = editCPointsConn.block(true); bool prevState = editCPointsConn.block(true);
editCPoints->set_active(false); editCPoints->set_active(false);
CPointsCurve->pipetteMouseOver(NULL, 0); CPointsCurve->pipetteMouseOver(NULL, NULL, 0);
CPointsCurve->setDirty(true); CPointsCurve->setDirty(true);
if (!prevState) editCPointsConn.block(false); if (!prevState) editCPointsConn.block(false);
} }
@ -149,7 +184,7 @@ void FlatCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, int m
CurveEditor *curveEditor = static_cast<FlatCurveEditor*>(parent->displayedCurve); CurveEditor *curveEditor = static_cast<FlatCurveEditor*>(parent->displayedCurve);
switch((FlatCurveType)(curveEditor->curveType->getSelected())) { switch((FlatCurveType)(curveEditor->curveType->getSelected())) {
case (FCT_MinMaxCPoints): case (FCT_MinMaxCPoints):
CPointsCurve->pipetteMouseOver(provider, modifierKey); CPointsCurve->pipetteMouseOver(curveEditor, provider, modifierKey);
CPointsCurve->setDirty(true); CPointsCurve->setDirty(true);
break; break;
default: // (DCT_Linear, DCT_Unchanged) default: // (DCT_Linear, DCT_Unchanged)
@ -380,6 +415,15 @@ void FlatCurveEditorSubGroup::pastePressed () {
return; return;
} }
void FlatCurveEditorSubGroup::editPointToggled(Gtk::ToggleButton *button) {
if (button->get_active())
CPointsCoordAdjuster->show();
else {
CPointsCurve->stopNumericalAdjustment();
CPointsCoordAdjuster->hide();
}
}
void FlatCurveEditorSubGroup::editToggled (Gtk::ToggleButton *button) { void FlatCurveEditorSubGroup::editToggled (Gtk::ToggleButton *button) {
FlatCurveEditor* dCurve = static_cast<FlatCurveEditor*>(parent->displayedCurve); FlatCurveEditor* dCurve = static_cast<FlatCurveEditor*>(parent->displayedCurve);
if (!dCurve) if (!dCurve)

View File

@ -33,12 +33,15 @@ protected:
MyFlatCurve* CPointsCurve; MyFlatCurve* CPointsCurve;
CoordinateAdjuster *CPointsCoordAdjuster;
Gtk::Button* saveCPoints; Gtk::Button* saveCPoints;
Gtk::Button* loadCPoints; Gtk::Button* loadCPoints;
Gtk::Button* copyCPoints; Gtk::Button* copyCPoints;
Gtk::Button* pasteCPoints; Gtk::Button* pasteCPoints;
Gtk::ToggleButton* editPointCPoints;
Gtk::ToggleButton* editCPoints; Gtk::ToggleButton* editCPoints;
sigc::connection editCPointsConn; sigc::connection editCPointsConn, editPointCPointsConn;
public: public:
FlatCurveEditorSubGroup(CurveEditorGroup* prt, Glib::ustring& curveDir); FlatCurveEditorSubGroup(CurveEditorGroup* prt, Glib::ustring& curveDir);
@ -53,6 +56,8 @@ public:
void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey); void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey);
void pipetteButton1Released(EditDataProvider *provider); void pipetteButton1Released(EditDataProvider *provider);
void pipetteDrag(EditDataProvider *provider, int modifierKey); void pipetteDrag(EditDataProvider *provider, int modifierKey);
void showCoordinateAdjuster(CoordinateProvider *provider);
void stopNumericalAdjustment();
bool curveReset (CurveEditor *ce); bool curveReset (CurveEditor *ce);
@ -66,6 +71,7 @@ protected:
void pastePressed (); void pastePressed ();
void removeEditor (); void removeEditor ();
const std::vector<double> getCurveFromGUI (int type); const std::vector<double> getCurveFromGUI (int type);
void editPointToggled(Gtk::ToggleButton *button);
void editToggled (Gtk::ToggleButton *button); void editToggled (Gtk::ToggleButton *button);
}; };

View File

@ -36,6 +36,7 @@ MyCurve::MyCurve () : pipetteR(-1.f), pipetteG(-1.f), pipetteB(-1.f), pipetteVal
sized = RS_Pending; sized = RS_Pending;
snapToElmt = -100; snapToElmt = -100;
curveIsDirty = true; curveIsDirty = true;
edited_point = -1;
set_extension_events(Gdk::EXTENSION_EVENTS_ALL); set_extension_events(Gdk::EXTENSION_EVENTS_ALL);
#if defined (__APPLE__) #if defined (__APPLE__)
@ -114,6 +115,15 @@ bool MyCurve::snapCoordinateY(double testedVal, double realVal) {
return false; 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) { void MyCurve::on_style_changed (const Glib::RefPtr<Gtk::Style>& style) {
setDirty(true); setDirty(true);
queue_draw (); queue_draw ();

View File

@ -24,6 +24,7 @@
#include "curvelistener.h" #include "curvelistener.h"
#include "cursormanager.h" #include "cursormanager.h"
#include "coloredbar.h" #include "coloredbar.h"
#include "coordinateadjuster.h"
#include "../rtengine/LUT.h" #include "../rtengine/LUT.h"
#include "guiutils.h" #include "guiutils.h"
#include "options.h" #include "options.h"
@ -59,8 +60,9 @@ enum ResizeState {
}; };
class MyCurveIdleHelper; 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; friend class MyCurveIdleHelper;
@ -72,14 +74,14 @@ class MyCurve : public Gtk::DrawingArea, public BackBuffer, public ColorCaller {
ColoredBar *leftBar; ColoredBar *leftBar;
ColoredBar *bottomBar; ColoredBar *bottomBar;
CursorShape cursor_type; 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 int prevGraphW, prevGraphH; /// previous inner width and height of the editor
Gdk::ModifierType mod_type; Gdk::ModifierType mod_type;
int cursorX; /// X coordinate in the graph of the cursor int cursorX; /// X coordinate in the graph of the cursor
int cursorY; /// Y coordinate in the graph of the cursor int cursorY; /// Y coordinate in the graph of the cursor
std::vector< Point<float> > point; LUTf point;
std::vector< Point<float> > upoint; LUTf upoint;
std::vector< Point<float> > lpoint; LUTf lpoint;
bool buttonPressed; bool buttonPressed;
/** /**
* snapToElmt, which will be used for the Y axis only, must be interpreted like this: * 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; enum ResizeState sized;
bool curveIsDirty; 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; virtual std::vector<double> get_vector (int veclen) = 0;
int getGraphMinSize() { return GRAPH_SIZE + RADIUS + 1; } int getGraphMinSize() { return GRAPH_SIZE + RADIUS + 1; }
bool snapCoordinateX(double testedVal, double realVal); bool snapCoordinateX(double testedVal, double realVal);
bool snapCoordinateY(double testedVal, double realVal); bool snapCoordinateY(double testedVal, double realVal);
float getVal(LUTf &curve, int x);
// return value = new requested height // return value = new requested height
int calcDimensions (); int calcDimensions ();
@ -123,7 +129,7 @@ class MyCurve : public Gtk::DrawingArea, public BackBuffer, public ColorCaller {
virtual bool handleEvents (GdkEvent* event) = 0; virtual bool handleEvents (GdkEvent* event) = 0;
virtual void reset (const std::vector<double> &resetCurve, double identityValue=0.5) = 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 pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) =0;
virtual void pipetteButton1Released(EditDataProvider *provider) =0; virtual void pipetteButton1Released(EditDataProvider *provider) =0;
virtual void pipetteDrag(EditDataProvider *provider, int modifierKey) =0; virtual void pipetteDrag(EditDataProvider *provider, int modifierKey) =0;

View File

@ -33,6 +33,9 @@ MyDiagonalCurve::MyDiagonalCurve () : activeParam(-1), bghistvalid(false) {
bghist = new unsigned int[256]; 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) ); signal_event().connect( sigc::mem_fun(*this, &MyDiagonalCurve::handleEvents) );
curve.type = DCT_Spline; curve.type = DCT_Spline;
@ -82,47 +85,77 @@ std::vector<double> MyDiagonalCurve::get_vector (int veclen) {
// calculate remaining points // calculate remaining points
std::vector<double> curveDescr = getPoints (); 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; std::vector<double> t;
t.resize (veclen); t.resize (veclen);
for (int i = 0; i < veclen; i++) for (int i = 0; i < veclen; i++)
t[i] = (double) i / (veclen - 1.0); t[i] = (double) i / (veclen - 1.0);
rtcurve->getVal (t, vector); rtcurve.getVal (t, vector);
delete rtcurve;
return 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 () { void MyDiagonalCurve::interpolate () {
prevGraphW = graphW; prevGraphW = graphW;
prevGraphH = graphH; prevGraphH = graphH;
int nbPoints = graphW-2; int nbPoints = rtengine::max(graphW-2,201);
point.resize (nbPoints); point(nbPoints);
std::vector<double> vector = get_vector (nbPoints); get_LUT (point);
for (int i = 0; i < nbPoints; ++i) { upoint.reset();
float currX = float(i)/float(nbPoints-1); lpoint.reset ();
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 ();
if (curve.type==DCT_Parametric && activeParam>0) { if (curve.type==DCT_Parametric && activeParam>0) {
double tmp = curve.x.at(activeParam-1); double tmp = curve.x.at(activeParam-1);
if (activeParam>=4) { if (activeParam>=4) {
upoint.resize(nbPoints); upoint(nbPoints);
lpoint.resize(nbPoints); lpoint(nbPoints);
curve.x.at(activeParam-1) = 100; curve.x.at(activeParam-1) = 100;
vector = get_vector (nbPoints); get_LUT(upoint);
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)));
}
curve.x.at(activeParam-1) = -100; curve.x.at(activeParam-1) = -100;
vector = get_vector (nbPoints); get_LUT (lpoint);
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)));
}
curve.x.at(activeParam-1) = tmp; curve.x.at(activeParam-1) = tmp;
} }
} }
@ -140,8 +173,10 @@ void MyDiagonalCurve::draw (int handle) {
return; return;
// re-calculate curve if dimensions changed // 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 (); interpolate ();
currPointSize = point.getUpperBound();
Gtk::StateType state = !is_sensitive() ? Gtk::STATE_INSENSITIVE : Gtk::STATE_NORMAL; 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); cr->set_line_width (1.0);
// draw upper and lower bounds // 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->set_source_rgba (0.0, 0.0, 0.0, 0.15);
cr->move_to (upoint[0].x, upoint[0].y); cr->move_to (graphX_, getVal(upoint, 0)*-graphH_+graphY_);
for (int i=1; i<(int)upoint.size(); i++) for (int i=1; i<graphW-2; ++i)
cr->line_to (upoint[i].x, upoint[i].y); cr->line_to (float(i)+graphX_, getVal(upoint, i)*-graphH_+graphY_);
cr->line_to (lpoint[lpoint.size()-1].x, lpoint[lpoint.size()-1].y); for (int i=graphW-3; i>=0; --i)
for (int i=(int)lpoint.size()-2; i>=0; i--) cr->line_to (float(i)+graphX_, getVal(lpoint, i)*-graphH_+graphY_);
cr->line_to (lpoint[i].x, lpoint[i].y);
cr->line_to (upoint[0].x, upoint[0].y);
cr->fill (); cr->fill ();
} }
@ -299,10 +335,9 @@ void MyDiagonalCurve::draw (int handle) {
// draw curve // draw curve
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); 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)); cr->move_to (graphX_, getVal(point, 0)*-graphH_+graphY_);
for (int i=1; i<(int)point.size(); i++) { for (int i=1; i<graphW-2; ++i)
cr->line_to (double(point.at(i).x), double(point.at(i).y)); cr->line_to (float(i)+graphX_, getVal(point, i)*-graphH_+graphY_);
}
cr->stroke (); cr->stroke ();
// draw the left colored bar // 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()); cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
} }
else { else {
if (i == handle || i == snapToElmt) if (i == handle || i == snapToElmt || i == edited_point)
cr->set_source_rgb (1.0, 0.0, 0.0); cr->set_source_rgb (1.0, 0.0, 0.0);
else else
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); 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->arc (x, y, RADIUS+0.5, 0, 2*M_PI);
cr->fill (); 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); setDirty(false);
@ -408,7 +451,8 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
// setDrawRectangle will allocate the backbuffer Surface // setDrawRectangle will allocate the backbuffer Surface
if (setDrawRectangle(win, 0, 0, get_allocation().get_width(), get_allocation().get_height())) { if (setDrawRectangle(win, 0, 0, get_allocation().get_width(), get_allocation().get_height())) {
setDirty(true); setDirty(true);
curveIsDirty = true; if (prevGraphW > 200 || graphW > 200)
curveIsDirty = true;
} }
draw (lit_point); draw (lit_point);
GdkRectangle *rectangle = &(event->expose.area); GdkRectangle *rectangle = &(event->expose.area);
@ -421,50 +465,118 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
case Gdk::BUTTON_PRESS: case Gdk::BUTTON_PRESS:
snapToElmt = -100; snapToElmt = -100;
if (curve.type!=DCT_Parametric) { if (curve.type!=DCT_Parametric) {
if (event->button.button == 1) { if (edited_point == -1) {
std::vector<double>::iterator itx, ity; if (event->button.button == 1) {
buttonPressed = true; std::vector<double>::iterator itx, ity;
add_modal_grab (); buttonPressed = true;
add_modal_grab ();
// get the pointer position // 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)); getCursorPosition(Gdk::EventType(event->type), event->motion.is_hint!=0, int(event->button.x), int(event->button.y), Gdk::ModifierType(event->button.state));
findClosestPoint(); findClosestPoint();
new_type = CSMove; new_type = CSMove;
if (distanceX > minDistanceX) { if (distanceX > minDistanceX) {
/* insert a new control point */ if (mod_type & GDK_CONTROL_MASK) {
if (num > 0) { clampedY = point.getVal01(clampedX);
if (clampedX > curve.x.at(closest_point)) }
++closest_point; /* 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(); grab_point = closest_point;
ity = curve.y.begin(); lit_point = closest_point;
for (int i=0; i<closest_point; i++) { itx++; ity++; } ugpX = curve.x.at(closest_point);
curve.x.insert (itx, 0); ugpY = curve.y.at(closest_point);
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; else if (event->button.button == 3) {
lit_point = closest_point; if (lit_point>-1 && grab_point==-1) {
ugpX = curve.x.at(closest_point); if (!coordinateAdjuster->is_visible())
ugpY = curve.y.at(closest_point); 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; break;
case Gdk::BUTTON_RELEASE: case Gdk::BUTTON_RELEASE:
snapToElmt = -100; snapToElmt = -100;
if (curve.type!=DCT_Parametric) { if (curve.type!=DCT_Parametric && edited_point==-1) {
if (buttonPressed && event->button.button == 1) { if (buttonPressed && event->button.button == 1) {
std::vector<double>::iterator itx, ity; std::vector<double>::iterator itx, ity;
int src, dst; 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)); 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) { if (grab_point == -1) {
// there's no point currently being moved if (edited_point==-1) {
int previous_lit_point = lit_point; // there's no point currently being moved
findClosestPoint(); int previous_lit_point = lit_point;
if (cursorX<0 || cursorX>graphW || cursorY<0 || cursorY>graphH) { findClosestPoint();
// the cursor has left the graph area if (cursorX<0 || cursorX>graphW || cursorY<0 || cursorY>graphH) {
new_type = CSArrow; // the cursor has left the graph area
lit_point = -1; 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) { else { // if (edited_point > -1)
new_type = CSMove; // there's no point currently being moved
lit_point = closest_point; int previous_lit_point = lit_point;
} findClosestPoint();
else { if (distanceX <= minDistanceX) {
new_type = CSPlus; // the cursor is close to an existing point
lit_point = -1; lit_point = closest_point;
} }
if (lit_point != previous_lit_point) { else {
setDirty(true); // the cursor is outside the graph or inside the graph but away from existing points
draw (lit_point); lit_point = -1;
}
if (lit_point != previous_lit_point) {
setDirty(true);
draw (lit_point);
}
} }
} }
else { else {
@ -646,6 +789,12 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
setDirty(true); setDirty(true);
draw (lit_point); draw (lit_point);
notifyListener (); 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; return new_type;
} }
void MyDiagonalCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey) { void MyDiagonalCurve::pipetteMouseOver (CurveEditor *ce, EditDataProvider *provider, int modifierKey) {
if (!provider) { if (!provider) {
// occurs when leaving the preview area -> cleanup the curve editor // occurs when leaving the preview area -> cleanup the curve editor
pipetteR = pipetteG = pipetteB = -1.f; pipetteR = pipetteG = pipetteB = -1.f;
@ -681,8 +830,9 @@ void MyDiagonalCurve::pipetteMouseOver (EditDataProvider *provider, int modifier
pipetteG = provider->pipetteVal[1]; pipetteG = provider->pipetteVal[1];
pipetteB = provider->pipetteVal[2]; pipetteB = provider->pipetteVal[2];
pipetteVal = 0.f; pipetteVal = 0.f;
if (listener) if (listener) {
pipetteVal = listener->blendPipetteValues(pipetteR, pipetteG, pipetteB); pipetteVal = listener->blendPipetteValues(ce, pipetteR, pipetteG, pipetteB);
}
else { else {
int n = 0; int n = 0;
if (pipetteR != -1.f) { 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) { if (curve.type == DCT_Linear || curve.type == DCT_Spline || curve.type == DCT_NURBS) {
// get the pointer position // get the pointer position
int px = graphX + int(float(graphW)*pipetteVal); // WARNING: converting pipetteVal from float to int, precision loss here! getCursorPositionFromCurve(pipetteVal);
getCursorPosition(Gdk::MOTION_NOTIFY, false, px, graphY, Gdk::ModifierType(modifierKey));
if (grab_point == -1) { if (edited_point==-1) {
// there's no point currently being moved if (grab_point == -1) {
int previous_lit_point = lit_point; // there's no point currently being moved
findClosestPoint(); int previous_lit_point = lit_point;
if (cursorX<0 || cursorX>graphW || cursorY<0 || cursorY>graphH) { findClosestPoint();
// the cursor has left the graph area if (cursorX<0 || cursorX>graphW || cursorY<0 || cursorY>graphH) {
lit_point = -1; // the cursor has left the graph area
} lit_point = -1;
else if (distanceX <= minDistanceX) { }
lit_point = closest_point; else if (distanceX <= minDistanceX) {
} lit_point = closest_point;
else { }
lit_point = -1; else {
} lit_point = -1;
if (lit_point != previous_lit_point) { }
setDirty(true); if (lit_point != previous_lit_point) {
draw (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) { void MyDiagonalCurve::pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) {
if (edited_point>1)
return;
int num = (int)curve.x.size(); int num = (int)curve.x.size();
/* graphW and graphH are the size of the graph */ /* graphW and graphH are the size of the graph */
@ -756,13 +918,10 @@ void MyDiagonalCurve::pipetteButton1Pressed(EditDataProvider *provider, int modi
buttonPressed = true; buttonPressed = true;
// get the pointer position // get the pointer position
int px = graphX + int(float(graphW)*pipetteVal); // WARNING: converting pipetteVal from float to int, precision loss here! getCursorPositionFromCurve(pipetteVal);
getCursorPosition(Gdk::BUTTON_PRESS, false, px, graphY, Gdk::ModifierType(modifierKey));
findClosestPoint(); findClosestPoint();
if (distanceX > minDistanceX) { if (distanceX > minDistanceX) {
rtengine::DiagonalCurve rtCurve(getPoints(), 200);
/* insert a new control point */ /* insert a new control point */
if (num > 0) { if (num > 0) {
if (clampedX > curve.x.at(closest_point)) if (clampedX > curve.x.at(closest_point))
@ -771,17 +930,25 @@ void MyDiagonalCurve::pipetteButton1Pressed(EditDataProvider *provider, int modi
itx = curve.x.begin(); itx = curve.x.begin();
ity = curve.y.begin(); ity = curve.y.begin();
for (int i=0; i<closest_point; i++) { itx++; ity++; } for (int i=0; i<closest_point; i++) { itx++; ity++; }
lit_point = closest_point;
curve.x.insert (itx, 0); curve.x.insert (itx, 0);
curve.y.insert (ity, 0); curve.y.insert (ity, 0);
num++;
// the graph is refreshed only if a new point is created (snaped to a pixel) // the graph is refreshed only if a new point is created (snapped to a pixel)
curve.x.at(closest_point) = clampedX; curve.x.at(lit_point) = clampedX;
curve.y.at(closest_point) = clampedY = rtCurve.getVal(pipetteVal); 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; curveIsDirty = true;
setDirty(true); setDirty(true);
draw (closest_point); draw (lit_point);
notifyListener (); notifyListener ();
} }
grab_point = closest_point; grab_point = closest_point;
@ -792,6 +959,9 @@ void MyDiagonalCurve::pipetteButton1Pressed(EditDataProvider *provider, int modi
} }
void MyDiagonalCurve::pipetteButton1Released(EditDataProvider *provider) { void MyDiagonalCurve::pipetteButton1Released(EditDataProvider *provider) {
if (edited_point>1)
return;
/* graphW and graphH are the size of the graph */ /* graphW and graphH are the size of the graph */
calcDimensions(); calcDimensions();
@ -827,7 +997,7 @@ void MyDiagonalCurve::pipetteButton1Released(EditDataProvider *provider) {
} }
void MyDiagonalCurve::pipetteDrag(EditDataProvider *provider, int modifierKey) { 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; return;
snapToMinDistY = snapToMinDistX = 10.; snapToMinDistY = snapToMinDistX = 10.;
@ -837,7 +1007,7 @@ void MyDiagonalCurve::pipetteDrag(EditDataProvider *provider, int modifierKey) {
/* graphW and graphH are the size of the graph */ /* graphW and graphH are the size of the graph */
calcDimensions(); 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 // we memorize the previous position of the point, for optimization purpose
double prevPosX = curve.x.at(grab_point); double prevPosX = curve.x.at(grab_point);
@ -888,9 +1058,38 @@ void MyDiagonalCurve::pipetteDrag(EditDataProvider *provider, int modifierKey) {
setDirty(true); setDirty(true);
draw (lit_point); draw (lit_point);
notifyListener (); 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) { void MyDiagonalCurve::getCursorPosition(Gdk::EventType evType, bool isHint, int evX, int evY, Gdk::ModifierType modifierKey) {
int tx, ty; int tx, ty;
int prevCursorX, prevCursorY; int prevCursorX, prevCursorY;
@ -1006,6 +1205,7 @@ std::vector<double> MyDiagonalCurve::getPoints () {
void MyDiagonalCurve::setPoints (const std::vector<double>& p) { void MyDiagonalCurve::setPoints (const std::vector<double>& p) {
int ix = 0; int ix = 0;
stopNumericalAdjustment();
DiagonalCurveType t = (DiagonalCurveType)p[ix++]; DiagonalCurveType t = (DiagonalCurveType)p[ix++];
curve.type = t; curve.type = t;
if (t==DCT_Parametric) { if (t==DCT_Parametric) {
@ -1028,6 +1228,29 @@ void MyDiagonalCurve::setPoints (const std::vector<double>& p) {
queue_draw (); 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) { void MyDiagonalCurve::setType (DiagonalCurveType t) {
curve.type = t; curve.type = t;
@ -1081,6 +1304,8 @@ void MyDiagonalCurve::updateBackgroundHistogram (LUTu & hist) {
void MyDiagonalCurve::reset(const std::vector<double> &resetCurve, double identityValue) { void MyDiagonalCurve::reset(const std::vector<double> &resetCurve, double identityValue) {
stopNumericalAdjustment();
if (!resetCurve.empty()) { if (!resetCurve.empty()) {
setPoints(resetCurve); setPoints(resetCurve);
return; return;

View File

@ -49,7 +49,7 @@ class MyDiagonalCurve : public MyCurve {
protected: protected:
DiagonalCurveDescr curve; 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 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 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 double clampedX; // clamped grabbed point X coordinates in the [0;1] range
@ -63,12 +63,18 @@ class MyDiagonalCurve : public MyCurve {
int activeParam; int activeParam;
unsigned int* bghist; // histogram values unsigned int* bghist; // histogram values
bool bghistvalid; bool bghistvalid;
void draw (int handle); void draw (int handle);
void interpolate (); void interpolate ();
void getCursorPosition(Gdk::EventType evType, bool isHint, int evX, int evY, Gdk::ModifierType modifierKey);
void findClosestPoint(); void findClosestPoint();
CursorShape motionNotify(CursorShape type, double minDistanceX, double minDistanceY, int num); CursorShape motionNotify(CursorShape type, double minDistanceX, double minDistanceY, int num);
std::vector<double> get_vector (int veclen); 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: public:
MyDiagonalCurve (); MyDiagonalCurve ();
@ -81,10 +87,13 @@ class MyDiagonalCurve : public MyCurve {
void reset (const std::vector<double> &resetCurve, double identityValue=0.5); void reset (const std::vector<double> &resetCurve, double identityValue=0.5);
void updateBackgroundHistogram (LUTu & hist); 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 pipetteButton1Pressed(EditDataProvider *provider, int modifierKey);
void pipetteButton1Released(EditDataProvider *provider); void pipetteButton1Released(EditDataProvider *provider);
void pipetteDrag(EditDataProvider *provider, int modifierKey); void pipetteDrag(EditDataProvider *provider, int modifierKey);
virtual void setPos(double pos, int chanIdx);
virtual void stopNumericalAdjustment();
}; };
#endif #endif

View File

@ -37,6 +37,9 @@ MyFlatCurve::MyFlatCurve () {
//bghist = new unsigned int[256]; //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) ); signal_event().connect( sigc::mem_fun(*this, &MyFlatCurve::handleEvents) );
// By default, we create a curve with 8 control points // 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 // Get the curve control points
std::vector<double> curveDescr = getPoints (); 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 // Create the sample values that will be converted
std::vector<double> samples; std::vector<double> samples;
@ -64,26 +67,38 @@ std::vector<double> MyFlatCurve::get_vector (int veclen) {
samples.at(i) = (double) i / (veclen - 1.0); samples.at(i) = (double) i / (veclen - 1.0);
// Converting the values // Converting the values
rtcurve->getVal (samples, convertedValues); rtcurve.getVal (samples, convertedValues);
// Cleanup and return // Cleanup and return
delete rtcurve;
return convertedValues; 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 () { void MyFlatCurve::interpolate () {
prevGraphW = graphW; prevGraphW = graphW;
prevGraphH = graphH; prevGraphH = graphH;
int nbPoints = graphW-2; int nbPoints = graphW-2;
point.resize (nbPoints); point(nbPoints);
std::vector<double> vector = get_vector (nbPoints); get_LUT (point);
for (int i = 0; i < nbPoints; ++i) { upoint.reset ();
float currX = float(i)/float(nbPoints-1); lpoint.reset ();
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 ();
curveIsDirty = false; curveIsDirty = false;
} }
@ -98,7 +113,8 @@ void MyFlatCurve::draw () {
return; return;
// re-calculate curve if dimensions changed // 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 (); interpolate ();
double innerW = double(graphW-2); double innerW = double(graphW-2);
@ -228,22 +244,30 @@ void MyFlatCurve::draw () {
cr->set_line_width (coloredLineWidth); cr->set_line_width (coloredLineWidth);
// draw the lit_point's horizontal line // 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 ( (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)) { if (editedHandle&(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointY)) {
cr->set_line_width (2*coloredLineWidth); 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 // endif
@ -252,12 +276,13 @@ void MyFlatCurve::draw () {
else { else {
cr->set_source_rgb (0.5, 0.0, 0.0); 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 // 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->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->rel_line_to (0., -innerH);
cr->stroke (); cr->stroke ();
cr->set_line_width (1.0); cr->set_line_width (1.0);
@ -266,7 +291,7 @@ void MyFlatCurve::draw () {
if (editedHandle&(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointY)) { if (editedHandle&(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointY)) {
cr->set_line_width (2.0); 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->rel_line_to (innerW, 0.);
cr->stroke (); cr->stroke ();
cr->set_line_width (1.0); cr->set_line_width (1.0);
@ -282,7 +307,7 @@ void MyFlatCurve::draw () {
cr->stroke (); cr->stroke ();
double lineMinLength = 1. / graphW * SQUARE * 0.9; 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 x = double(graphX+1) + innerW*curve.x.at(lit_point);
double y = double(graphY) - innerH*curve.y.at(lit_point); double y = double(graphY) - innerH*curve.y.at(lit_point);
double x2; double x2;
@ -353,26 +378,30 @@ void MyFlatCurve::draw () {
// draw curve // draw curve
c = style->get_fg (state); c = style->get_fg (state);
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); 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); float graphH_ = float(graphH-3);
for (int i=1; i<(int)point.size(); i++) float graphX_ = float(graphX)+1.5;
cr->line_to (double(point.at(i).x), double(point.at(i).y)); 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 (); cr->stroke ();
// draw bullets // draw bullets
//if (curve.type!=FCT_Parametric) //if (curve.type!=FCT_Parametric)
for (int i = 0; i < (int)curve.x.size(); ++i) { for (int i = 0; i < (int)curve.x.size(); ++i) {
if (curve.x.at(i) != -1.) { if (curve.x.at(i) != -1.) {
if (i == lit_point) { if (i == edited_point)
if (colorProvider) { 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); colorProvider->colorForValue(curve.x.at(i), curve.y.at(i), CCET_POINT, colorCallerId, this);
cr->set_source_rgb (ccRed, ccGreen, ccBlue); cr->set_source_rgb (ccRed, ccGreen, ccBlue);
} }
else else
cr->set_source_rgb (1.0, 0.0, 0.0); 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); cr->set_source_rgb (1.0, 0.0, 0.0);
}
else if (curve.y.at(i) == 0.5) else if (curve.y.at(i) == 0.5)
cr->set_source_rgb (0.0, 0.5, 0.0); cr->set_source_rgb (0.0, 0.5, 0.0);
else else
@ -383,6 +412,15 @@ void MyFlatCurve::draw () {
cr->arc (x, y, (double)RADIUS, 0, 2*M_PI); cr->arc (x, y, (double)RADIUS, 0, 2*M_PI);
cr->fill (); 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 // endif
@ -499,7 +537,8 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
// setDrawRectangle will allocate the backbuffer Surface // setDrawRectangle will allocate the backbuffer Surface
if (setDrawRectangle(win, 0, 0, get_allocation().get_width(), get_allocation().get_height())) { if (setDrawRectangle(win, 0, 0, get_allocation().get_width(), get_allocation().get_height())) {
setDirty(true); setDirty(true);
curveIsDirty = true; if (prevGraphW > 200 || graphW > 200)
curveIsDirty = true;
} }
draw (); draw ();
GdkRectangle *rectangle = &(event->expose.area); GdkRectangle *rectangle = &(event->expose.area);
@ -510,7 +549,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
} }
case Gdk::BUTTON_PRESS: case Gdk::BUTTON_PRESS:
//if (curve.type!=FCT_Parametric) { if (edited_point==-1) { //curve.type!=FCT_Parametric) {
if (event->button.button == 1) { if (event->button.button == 1) {
buttonPressed = true; buttonPressed = true;
add_modal_grab (); add_modal_grab ();
@ -544,6 +583,10 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
curve.rightTangent.insert (itrt, 0); curve.rightTangent.insert (itrt, 0);
num++; num++;
if (mod_type & GDK_CONTROL_MASK) {
clampedY = point.getVal01(clampedX);
}
// the graph is refreshed only if a new point is created // the graph is refreshed only if a new point is created
curve.x.at(closest_point) = clampedX; curve.x.at(closest_point) = clampedX;
curve.y.at(closest_point) = clampedY; curve.y.at(closest_point) = clampedY;
@ -593,14 +636,85 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
default: default:
break; 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; 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; break;
case Gdk::BUTTON_RELEASE: case Gdk::BUTTON_RELEASE:
//if (curve.type!=FCT_Parametric) { if (edited_point==-1) { //curve.type!=FCT_Parametric) {
if (buttonPressed && event->button.button == 1) { if (buttonPressed && event->button.button == 1) {
int src, dst; int src, dst;
buttonPressed = false; buttonPressed = false;
@ -684,7 +798,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
retval = true; retval = true;
//notifyListener (); //notifyListener ();
} }
//} }
break; break;
case Gdk::MOTION_NOTIFY: case Gdk::MOTION_NOTIFY:
@ -722,7 +836,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
case (FCT_EditedHandle_None): { 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; 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; tanHandlesDisplayed = false;
} }
switch (area) { if (edited_point==-1) {
switch (area) {
case (FCT_Area_Insertion): case (FCT_Area_Insertion):
new_type = CSPlus; new_type = CSPlus;
break; break;
case (FCT_Area_Point): case (FCT_Area_Point):
//new_type = CSMove; //new_type = CSMove;
//break; //break;
case (FCT_Area_V): case (FCT_Area_V):
new_type = CSMove; new_type = CSMove;
break; break;
case (FCT_Area_H): case (FCT_Area_H):
new_type = CSResizeHeight; new_type = CSResizeHeight;
break; break;
case (FCT_Area_LeftTan): case (FCT_Area_LeftTan):
new_type = CSMoveLeft; new_type = CSMoveLeft;
break; break;
case (FCT_Area_RightTan): case (FCT_Area_RightTan):
new_type = CSMoveRight; new_type = CSMoveRight;
break; break;
case (FCT_Area_None): case (FCT_Area_None):
default: default:
new_type = CSArrow; new_type = CSArrow;
break; break;
}
} }
if ((lit_point != previous_lit_point) || (prevArea != area)) { if ((lit_point != previous_lit_point) || (prevArea != area)) {
setDirty(true); setDirty(true);
draw (); 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; break;
} }
case (FCT_EditedHandle_CPoint): case (FCT_EditedHandle_CPoint):
movePoint(true, true); 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; break;
case (FCT_EditedHandle_CPointX): case (FCT_EditedHandle_CPointX):
movePoint(true, false); movePoint(true, false);
if (coordinateAdjuster->is_visible()) {
editedPos.at(0) = curve.x.at(lit_point);
coordinateAdjuster->setPos(editedPos);
}
break; break;
case (FCT_EditedHandle_CPointY): case (FCT_EditedHandle_CPointY):
movePoint(false, true); movePoint(false, true);
if (coordinateAdjuster->is_visible()) {
editedPos.at(1) = curve.y.at(lit_point);
coordinateAdjuster->setPos(editedPos);
}
break; break;
case (FCT_EditedHandle_LeftTan): { case (FCT_EditedHandle_LeftTan): {
@ -843,6 +995,10 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
setDirty(true); setDirty(true);
draw (); draw ();
notifyListener (); notifyListener ();
if (coordinateAdjuster->is_visible()) {
editedPos.at(2) = curve.leftTangent.at(lit_point);
coordinateAdjuster->setPos(editedPos);
}
} }
break; break;
} }
@ -869,6 +1025,8 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
setDirty(true); setDirty(true);
draw (); draw ();
notifyListener (); notifyListener ();
editedPos.at(3) = curve.rightTangent.at(lit_point);
coordinateAdjuster->setPos(editedPos);
} }
break; break;
} }
@ -879,6 +1037,23 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
default: default:
break; 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; retval = true;
@ -908,7 +1083,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) {
return retval; return retval;
} }
void MyFlatCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey) { void MyFlatCurve::pipetteMouseOver (CurveEditor *ce, EditDataProvider *provider, int modifierKey) {
if (!provider) { if (!provider) {
// occurs when leaving the preview area -> cleanup the curve editor // occurs when leaving the preview area -> cleanup the curve editor
pipetteR = pipetteG = pipetteB = -1.f; pipetteR = pipetteG = pipetteB = -1.f;
@ -921,7 +1096,7 @@ void MyFlatCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey)
pipetteB = provider->pipetteVal[2]; pipetteB = provider->pipetteVal[2];
pipetteVal = 0.f; pipetteVal = 0.f;
if (listener) if (listener)
pipetteVal = listener->blendPipetteValues(pipetteR, pipetteG, pipetteB); pipetteVal = listener->blendPipetteValues(ce, pipetteR, pipetteG, pipetteB);
else { else {
int n = 0; int n = 0;
if (pipetteR != -1.f) { if (pipetteR != -1.f) {
@ -958,7 +1133,8 @@ void MyFlatCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey)
// get the pointer position // get the pointer position
int px = graphX + int(float(graphW)*pipetteVal); // WARNING: converting pipetteVal from float to int, precision loss here! 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)); getCursorPosition(Gdk::EventType(Gdk::BUTTON_PRESS), false, px, graphY, Gdk::ModifierType(modifierKey));
getMouseOverArea(); if (edited_point==-1)
getMouseOverArea();
if (area==FCT_Area_Point) if (area==FCT_Area_Point)
area = FCT_Area_V; area = FCT_Area_V;
@ -966,13 +1142,26 @@ void MyFlatCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey)
snapToMinDistY = snapToMinDistX = 10.; snapToMinDistY = snapToMinDistX = 10.;
snapToValY = snapToValX = 0.; snapToValY = snapToValX = 0.;
if (editedHandle==FCT_EditedHandle_None && lit_point != previous_lit_point) { if (edited_point==-1) {
setDirty(true); if (editedHandle==FCT_EditedHandle_None && lit_point != previous_lit_point) {
draw (); 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) { void MyFlatCurve::pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) {
if (edited_point>-1)
return;
buttonPressed = true; buttonPressed = true;
// get the pointer position // get the pointer position
@ -1040,6 +1229,9 @@ void MyFlatCurve::pipetteButton1Pressed(EditDataProvider *provider, int modifier
} }
void MyFlatCurve::pipetteButton1Released(EditDataProvider *provider) { void MyFlatCurve::pipetteButton1Released(EditDataProvider *provider) {
if (edited_point>-1)
return;
buttonPressed = false; buttonPressed = false;
remove_modal_grab (); remove_modal_grab ();
@ -1057,6 +1249,8 @@ void MyFlatCurve::pipetteButton1Released(EditDataProvider *provider) {
} }
void MyFlatCurve::pipetteDrag(EditDataProvider *provider, int modifierKey) { void MyFlatCurve::pipetteDrag(EditDataProvider *provider, int modifierKey) {
if (edited_point>-1)
return;
snapToMinDistY = snapToMinDistX = 10.; snapToMinDistY = snapToMinDistX = 10.;
snapToValY = snapToValX = 0.; snapToValY = snapToValX = 0.;
@ -1423,6 +1617,7 @@ std::vector<double> MyFlatCurve::getPoints () {
void MyFlatCurve::setPoints (const std::vector<double>& p) { void MyFlatCurve::setPoints (const std::vector<double>& p) {
int ix = 0; int ix = 0;
stopNumericalAdjustment();
FlatCurveType t = (FlatCurveType)p[ix++]; FlatCurveType t = (FlatCurveType)p[ix++];
curve.type = t; curve.type = t;
if (t==FCT_MinMaxCPoints) { if (t==FCT_MinMaxCPoints) {
@ -1442,6 +1637,38 @@ void MyFlatCurve::setPoints (const std::vector<double>& p) {
queue_draw (); 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) { void MyFlatCurve::setType (FlatCurveType t) {
curve.type = t; curve.type = t;
@ -1451,6 +1678,8 @@ void MyFlatCurve::setType (FlatCurveType t) {
void MyFlatCurve::reset(const std::vector<double> &resetCurve, double identityValue) { void MyFlatCurve::reset(const std::vector<double> &resetCurve, double identityValue) {
calcDimensions(); calcDimensions();
stopNumericalAdjustment();
// If a resetCurve exist (non empty) // If a resetCurve exist (non empty)
if (!resetCurve.empty()) { if (!resetCurve.empty()) {
setPoints(resetCurve); setPoints(resetCurve);

View File

@ -110,6 +110,7 @@ class MyFlatCurve : public MyCurve {
bool getHandles(int n); bool getHandles(int n);
CursorShape motionNotify(CursorShape type, double minDistanceX, double minDistanceY, int num); CursorShape motionNotify(CursorShape type, double minDistanceX, double minDistanceY, int num);
std::vector<double> get_vector (int veclen); std::vector<double> get_vector (int veclen);
void get_LUT (LUTf &lut);
public: public:
MyFlatCurve (); MyFlatCurve ();
@ -122,10 +123,13 @@ class MyFlatCurve : public MyCurve {
void reset (const std::vector<double> &resetCurve, double identityValue=0.5); void reset (const std::vector<double> &resetCurve, double identityValue=0.5);
//void updateBackgroundHistogram (unsigned int* hist); //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 pipetteButton1Pressed(EditDataProvider *provider, int modifierKey);
void pipetteButton1Released(EditDataProvider *provider); void pipetteButton1Released(EditDataProvider *provider);
void pipetteDrag(EditDataProvider *provider, int modifierKey); void pipetteDrag(EditDataProvider *provider, int modifierKey);
void setPos(double pos, int chanIdx);
virtual void stopNumericalAdjustment();
}; };
#endif #endif

View File

@ -2,13 +2,15 @@
#define _PPVERSION_ #define _PPVERSION_
// This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes // 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 #define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified
/* /*
Log of version changes Log of version changes
322 2015-01-31 323 2015-10-05
[Wavelet] new tool using wavelet levels [Exposure] Added 'Luminance' tone curve mode
322 2015-01-31
[Wavelet] new tool using wavelet levels
321 2014-08-17 321 2014-08-17
[Film Simulation] new tool using HALDCLUT files [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) 320 2014-07-02 (yes, same version number... this is an error due to a wrong version number set in comment of previous change)

View File

@ -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_WEIGHTEDSTD"));
toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE")); toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE"));
toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING")); toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING"));
toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_LUMINANCE"));
toneCurveMode->set_active (0); toneCurveMode->set_active (0);
toneCurveMode->set_tooltip_text(M("TP_EXPOSURE_TCMODE_LABEL1")); 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_WEIGHTEDSTD"));
toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE")); toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE"));
toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING")); toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING"));
toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_LUMINANCE"));
toneCurveMode2->set_active (0); toneCurveMode2->set_active (0);
toneCurveMode2->set_tooltip_text(M("TP_EXPOSURE_TCMODE_LABEL2")); 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); shape->setUnChanged (!pedited->toneCurve.curve);
shape2->setUnChanged (!pedited->toneCurve.curve2); shape2->setUnChanged (!pedited->toneCurve.curve2);
if (!pedited->toneCurve.curveMode) { if (!pedited->toneCurve.curveMode) {
toneCurveMode->set_active(4); toneCurveMode->set_active(5);
} }
if (!pedited->toneCurve.curveMode2) { if (!pedited->toneCurve.curveMode2) {
toneCurveMode2->set_active(4); toneCurveMode2->set_active(5);
} }
} }
if (pedited) 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 == 1) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_WEIGHTEDSTD;
else if (tcMode == 2) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_FILMLIKE; 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 == 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(); tcMode = toneCurveMode2->get_active_row_number();
if (tcMode == 0) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD; if (tcMode == 0) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD;
else if (tcMode == 1) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_WEIGHTEDSTD; 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 == 2) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_FILMLIKE;
else if (tcMode == 3) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_SATANDVALBLENDING; else if (tcMode == 3) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_SATANDVALBLENDING;
else if (tcMode == 4) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_LUMINANCE;
if (pedited) { if (pedited) {
pedited->toneCurve.expcomp = expcomp->getEditedState (); pedited->toneCurve.expcomp = expcomp->getEditedState ();
@ -312,8 +316,8 @@ void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) {
pedited->toneCurve.clip = clipDirty; pedited->toneCurve.clip = clipDirty;
pedited->toneCurve.curve = !shape->isUnChanged (); pedited->toneCurve.curve = !shape->isUnChanged ();
pedited->toneCurve.curve2 = !shape2->isUnChanged (); pedited->toneCurve.curve2 = !shape2->isUnChanged ();
pedited->toneCurve.curveMode = toneCurveMode->get_active_row_number() != 4; pedited->toneCurve.curveMode = toneCurveMode->get_active_row_number() != 5;
pedited->toneCurve.curveMode2 = toneCurveMode2->get_active_row_number() != 4; pedited->toneCurve.curveMode2 = toneCurveMode2->get_active_row_number() != 5;
} }
if (pedited) { if (pedited) {
pedited->toneCurve.method = method->get_active_row_number()!=4; pedited->toneCurve.method = method->get_active_row_number()!=4;
@ -446,6 +450,19 @@ bool ToneCurve::curveMode2Changed_ () {
return false; 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) { void ToneCurve::adjusterChanged (Adjuster* a, double newval) {
// Switch off auto exposure if user changes sliders manually // Switch off auto exposure if user changes sliders manually

View File

@ -84,6 +84,7 @@ class ToneCurve : public ToolParamBlock, public AdjusterListener, public Foldabl
void autoOpenCurve (); void autoOpenCurve ();
void setEditProvider (EditDataProvider *provider); void setEditProvider (EditDataProvider *provider);
virtual float blendPipetteValues (CurveEditor *ce, float chan1, float chan2, float chan3);
void adjusterChanged (Adjuster* a, double newval); void adjusterChanged (Adjuster* a, double newval);
void neutral_pressed (); void neutral_pressed ();