1295 lines
39 KiB
C++
1295 lines
39 KiB
C++
/*
|
|
* This file is part of RawTherapee.
|
|
*
|
|
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
|
*
|
|
* RawTherapee is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* RawTherapee is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <myflatcurve.h>
|
|
#include <curves.h>
|
|
#include <string.h>
|
|
#include <gdkmm/types.h>
|
|
|
|
MyFlatCurve::MyFlatCurve () {
|
|
|
|
innerWidth = get_allocation().get_width() - RADIUS * 2;
|
|
innerHeight = get_allocation().get_height() - RADIUS * 2;
|
|
prevInnerHeight = innerHeight;
|
|
lit_point = -1;
|
|
closest_point = 0;
|
|
buttonPressed = false;
|
|
editedHandle = FCT_EditedHandle_None;
|
|
area = FCT_Area_None;
|
|
tanHandlesDisplayed = false;
|
|
periodic = true;
|
|
|
|
//bghist = new unsigned int[256];
|
|
|
|
signal_event().connect( sigc::mem_fun(*this, &MyFlatCurve::handleEvents) );
|
|
|
|
// By default, we create a curve with 8 control points
|
|
curve.type = FCT_MinMaxCPoints;
|
|
|
|
defaultCurve();
|
|
}
|
|
|
|
/*MyFlatCurve::~MyFlatCurve () {
|
|
}*/
|
|
|
|
std::vector<double> MyFlatCurve::get_vector (int veclen) {
|
|
|
|
// Create the output variable
|
|
std::vector<double> convertedValues;
|
|
|
|
// Get the curve control points
|
|
std::vector<double> curveDescr = getPoints ();
|
|
rtengine::FlatCurve* rtcurve = new rtengine::FlatCurve (curveDescr, veclen*1.5 > 5000 ? 5000 : veclen*1.5);
|
|
|
|
// Create the sample values that will be converted
|
|
std::vector<double> samples;
|
|
samples.resize (veclen);
|
|
for (int i = 0; i < veclen; i++)
|
|
samples[i] = (double) i / (veclen - 1.0);
|
|
|
|
// Converting the values
|
|
rtcurve->getVal (samples, convertedValues);
|
|
|
|
// Cleanup and return
|
|
delete rtcurve;
|
|
return convertedValues;
|
|
}
|
|
|
|
void MyFlatCurve::interpolate () {
|
|
|
|
prevInnerHeight = innerHeight;
|
|
point.resize (innerWidth+1);
|
|
std::vector<double> vector = get_vector (innerWidth+1);
|
|
for (int i = 0; i <= innerWidth; ++i)
|
|
point[i] = Gdk::Point ((double)RADIUS+0.5 + i, (double)RADIUS+0.5 + (double)innerHeight*(1.-vector[i]));
|
|
upoint.clear ();
|
|
lpoint.clear ();
|
|
|
|
/*if (curve.type==FCT_Parametric && activeParam>0) {
|
|
double tmp = curve.x[activeParam-1];
|
|
if (activeParam>=4) {
|
|
upoint.resize(innerWidth);
|
|
lpoint.resize(innerWidth);
|
|
curve.x[activeParam-1] = 100;
|
|
vector = get_vector (innerWidth);
|
|
for (int i = 0; i < innerWidth; ++i)
|
|
upoint[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
|
|
curve.x[activeParam-1] = -100;
|
|
vector = get_vector (innerWidth);
|
|
for (int i = 0; i < innerWidth; ++i)
|
|
lpoint[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
|
|
curve.x[activeParam-1] = tmp;
|
|
}
|
|
}*/
|
|
}
|
|
|
|
void MyFlatCurve::draw () {
|
|
if (!pixmap)
|
|
return;
|
|
|
|
// re-calculate curve if dimensions changed
|
|
if (prevInnerHeight != innerHeight || (int)point.size() != (innerWidth+1)) {
|
|
interpolate ();
|
|
|
|
}
|
|
|
|
Gtk::StateType state = Gtk::STATE_NORMAL;
|
|
if (!is_sensitive())
|
|
state = Gtk::STATE_INSENSITIVE;
|
|
|
|
Glib::RefPtr<Gtk::Style> style = get_style ();
|
|
Cairo::RefPtr<Cairo::Context> cr = pixmap->create_cairo_context();
|
|
|
|
// bounding rectangle
|
|
Gdk::Color c = style->get_bg (state);
|
|
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
|
cr->rectangle (0, 0, innerWidth+RADIUS*2+1.5, innerHeight+RADIUS*2+1.5);
|
|
cr->fill ();
|
|
|
|
// histogram in the background
|
|
/*if (bghistvalid) {
|
|
// find highest bin
|
|
unsigned int histheight = 0;
|
|
for (int i=0; i<256; i++)
|
|
if (bghist[i]>histheight)
|
|
histheight = bghist[i];
|
|
// draw histogram
|
|
cr->set_line_width (1.0);
|
|
double stepSize = (innerWidth-1) / 256.0;
|
|
cr->move_to (RADIUS, innerHeight-1+RADIUS);
|
|
cr->set_source_rgb (0.75, 0.75, 0.75);
|
|
for (int i=0; i<256; i++) {
|
|
double val = bghist[i] * (double)(innerHeight-2) / (double)histheight;
|
|
if (val>innerHeight-1)
|
|
val = innerHeight-1;
|
|
if (i>0)
|
|
cr->line_to (i*stepSize+RADIUS, innerHeight-1+RADIUS-val);
|
|
}
|
|
cr->line_to (innerWidth-1+RADIUS, innerHeight-1+RADIUS);
|
|
cr->fill ();
|
|
}*/
|
|
|
|
cr->set_line_cap(Cairo::LINE_CAP_SQUARE);
|
|
|
|
// draw the grid lines:
|
|
cr->set_line_width (1.0);
|
|
cr->set_antialias (Cairo::ANTIALIAS_NONE);
|
|
c = style->get_dark (state);
|
|
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
|
|
|
double x0 = (double)RADIUS-0.5;
|
|
double x1 = (double)RADIUS-0.5 + (double)innerWidth + 2.;
|
|
double y0 = (double)RADIUS-0.5;
|
|
double y1 = (double)RADIUS-0.5 + (double)innerHeight + 2.;
|
|
for (int i = 0; i < 5; i++) {
|
|
double currX = (double)RADIUS-0.5 + (double)i*((double)innerWidth + 2.)/4.;
|
|
double currY = (double)RADIUS-0.5 + (double)i*((double)innerHeight + 2.)/4.;
|
|
cr->move_to (x0, currY);
|
|
cr->line_to (x1, currY);
|
|
cr->move_to (currX, y0);
|
|
cr->line_to (currX, y1);
|
|
}
|
|
cr->stroke ();
|
|
|
|
// draw f(x)=0.5 line
|
|
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
|
std::valarray<double> ds (1);
|
|
ds[0] = 4;
|
|
cr->set_dash (ds, 0);
|
|
cr->move_to ((double)RADIUS+0.5 , (double)RADIUS+0.5 + (double)innerHeight/2.);
|
|
cr->line_to ((double)RADIUS+0.5 + (double)innerWidth/2., (double)RADIUS+0.5 + (double)innerHeight/2.);
|
|
cr->stroke ();
|
|
|
|
cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
|
|
|
|
cr->unset_dash ();
|
|
cr->set_line_width (1.0);
|
|
|
|
// draw the color feedback of the control points
|
|
if (colorProvider) {
|
|
|
|
//if (curve.type!=FCT_Parametric)
|
|
for (int i=0; i<(int)curve.x.size(); ++i) {
|
|
|
|
if (curve.x[i] != -1.) {
|
|
|
|
cr->set_line_width (1.0);
|
|
colorProvider->colorForValue(curve.x[i], 0.5);
|
|
cr->set_source_rgb (colorProvider->red, colorProvider->green, colorProvider->blue);
|
|
|
|
double x = (double)RADIUS+0.5 + innerWidth*curve.x[i];
|
|
|
|
if (i == lit_point && editedHandle&(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointX)) {
|
|
cr->set_line_width (2.0);
|
|
}
|
|
cr->move_to (x, (double)RADIUS+0.5);
|
|
cr->line_to (x, (double)RADIUS+0.5 + innerHeight);
|
|
cr->stroke ();
|
|
cr->set_line_width (1.0);
|
|
|
|
// draw the lit_point's horizontal line
|
|
if (i == lit_point) {
|
|
|
|
if (area&(FCT_Area_H|FCT_Area_V|FCT_Area_Point) || editedHandle==FCT_EditedHandle_CPointUD) {
|
|
|
|
if (editedHandle&(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointY)) {
|
|
cr->set_line_width (2.0);
|
|
}
|
|
|
|
colorProvider->colorForValue(curve.x[i], curve.y[i]);
|
|
cr->set_source_rgb (colorProvider->red, colorProvider->green, colorProvider->blue);
|
|
|
|
double y = (double)RADIUS+0.5 + (double)innerHeight*(1.-curve.y[lit_point]);
|
|
cr->move_to ( RADIUS, y);
|
|
cr->line_to ((double)RADIUS+0.5 + (double)innerWidth, y);
|
|
cr->stroke ();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// endif
|
|
cr->set_line_width (1.0);
|
|
}
|
|
else {
|
|
cr->set_source_rgb (0.5, 0.0, 0.0);
|
|
|
|
if (area==(FCT_Area_H|FCT_Area_V|FCT_Area_Point) || editedHandle==FCT_EditedHandle_CPointUD) {
|
|
double position;
|
|
|
|
// draw the lit_point's vertical line
|
|
if (editedHandle==(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointY)) {
|
|
cr->set_line_width (2.0);
|
|
}
|
|
position = (double)RADIUS+0.5 + (double)innerWidth*curve.x[lit_point];
|
|
cr->move_to (position, (double)RADIUS+0.5);
|
|
cr->line_to (position, (double)RADIUS+0.5 + (double)innerHeight);
|
|
cr->stroke ();
|
|
cr->set_line_width (1.0);
|
|
|
|
// draw the lit_point's horizontal line
|
|
if (editedHandle==(FCT_EditedHandle_CPointUD|FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointY)) {
|
|
cr->set_line_width (2.0);
|
|
}
|
|
position = (double)RADIUS+0.5 + (double)innerHeight*(1.-curve.y[lit_point]);
|
|
cr->move_to ((double)RADIUS+0.5 , position);
|
|
cr->line_to ((double)RADIUS+0.5 + (double)innerWidth, position);
|
|
cr->stroke ();
|
|
cr->set_line_width (1.0);
|
|
}
|
|
}
|
|
|
|
double lineMinLength = 1. / innerWidth * SQUARE * 0.9;
|
|
if (lit_point!=-1 && getHandles(lit_point) && curve.x[lit_point]!=-1.) {
|
|
double x = (double)RADIUS+0.5 + (double)innerWidth * curve.x[lit_point];
|
|
double y = (double)RADIUS+0.5 + (double)innerHeight * (1.-curve.y[lit_point]);
|
|
double x2;
|
|
double square;
|
|
bool crossingTheFrame;
|
|
|
|
// left handle is yellow
|
|
cr->set_source_rgb (1.0, 1.0, 0.0);
|
|
|
|
// draw tangential vectors
|
|
|
|
crossingTheFrame = false;
|
|
// We display the line only if it's longer than the handle knot half-size...
|
|
if (leftTanX < -0.00001) {
|
|
leftTanX += 1.0;
|
|
crossingTheFrame = true;
|
|
}
|
|
x2 = (double)RADIUS+0.5 + (double)innerWidth * leftTanX;
|
|
if (curve.x[lit_point] - leftTanX > lineMinLength || crossingTheFrame) {
|
|
// The left tangential vector reappear on the right side
|
|
// draw the line
|
|
cr->move_to (x, y);
|
|
if (crossingTheFrame) {
|
|
cr->line_to ((double)RADIUS+0.5, y);
|
|
cr->stroke ();
|
|
cr->move_to ((double)RADIUS+0.5 + (double)innerWidth, y);
|
|
}
|
|
cr->line_to (x2, y);
|
|
cr->stroke ();
|
|
}
|
|
// draw tangential knot
|
|
square = area == FCT_Area_LeftTan ? SQUARE*2. : SQUARE;
|
|
cr->move_to(x2-square, y+square);
|
|
cr->line_to(x2+square, y+square);
|
|
cr->line_to(x2+square, y-square);
|
|
cr->line_to(x2-square, y-square);
|
|
cr->line_to(x2-square, y+square);
|
|
cr->fill();
|
|
|
|
// right handle is blue
|
|
cr->set_source_rgb (0.0, 0.0, 1.0);
|
|
|
|
// draw tangential vectors
|
|
|
|
crossingTheFrame = false;
|
|
// We display the line only if it's longer than the handle knot half-size...
|
|
if (rightTanX > 1.00001) {
|
|
rightTanX -= 1.0;
|
|
crossingTheFrame = true;
|
|
}
|
|
x2 = (double)RADIUS+0.5 + (double)innerWidth * rightTanX;
|
|
if (rightTanX - curve.x[lit_point] > lineMinLength || crossingTheFrame) {
|
|
// The left tangential vector reappear on the right side
|
|
// draw the line
|
|
cr->move_to (x, y);
|
|
if (crossingTheFrame) {
|
|
cr->line_to ((double)RADIUS+0.5 + (double)innerWidth, y);
|
|
cr->stroke ();
|
|
cr->move_to ((double)RADIUS+0.5, y);
|
|
}
|
|
cr->line_to (x2, y);
|
|
cr->stroke ();
|
|
}
|
|
// draw tangential knot
|
|
square = area == FCT_Area_RightTan ? SQUARE*2. : SQUARE;
|
|
cr->move_to(x2-square, y+square);
|
|
cr->line_to(x2+square, y+square);
|
|
cr->line_to(x2+square, y-square);
|
|
cr->line_to(x2-square, y-square);
|
|
cr->line_to(x2-square, y+square);
|
|
cr->fill();
|
|
}
|
|
|
|
// draw curve
|
|
cr->set_source_rgb (0.0, 0.0, 0.0);
|
|
cr->move_to (point[0].get_x(), point[0].get_y());
|
|
for (int i=1; i<(int)point.size(); i++)
|
|
cr->line_to (point[i].get_x(), point[i].get_y());
|
|
cr->stroke ();
|
|
|
|
// draw bullets
|
|
//if (curve.type!=FCT_Parametric)
|
|
for (int i = 0; i < (int)curve.x.size(); ++i) {
|
|
if (curve.x[i] != -1.) {
|
|
if (i == lit_point) {
|
|
if (colorProvider) {
|
|
colorProvider->colorForValue(curve.x[i], curve.y[i]);
|
|
cr->set_source_rgb (colorProvider->red, colorProvider->green, colorProvider->blue);
|
|
}
|
|
else
|
|
cr->set_source_rgb (1.0, 0.0, 0.0);
|
|
}
|
|
else if (curve.y[i] == 0.5)
|
|
cr->set_source_rgb (0.0, 0.5, 0.0);
|
|
else
|
|
cr->set_source_rgb (0.0, 0.0, 0.0);
|
|
double x = (double)RADIUS+0.5 + (double)innerWidth * curve.x[i]; // project (curve.x[i], 0, 1, innerWidth);
|
|
double y = (double)RADIUS+0.5 + (double)innerHeight * (1.-curve.y[i]); // project (curve.y[i], 0, 1, innerHeight);
|
|
|
|
cr->arc (x, y, (double)RADIUS, 0, 2*M_PI);
|
|
cr->fill ();
|
|
}
|
|
}
|
|
// endif
|
|
|
|
// draw the left and right tangent handles
|
|
if (tanHandlesDisplayed) {
|
|
double top, bottom, left, right;
|
|
double halfSquareSizeX, halfSquareSizeY;
|
|
|
|
// LEFT handle
|
|
halfSquareSizeX = minDistanceX/2.;
|
|
halfSquareSizeY = minDistanceY/2.;
|
|
//halfSquareSizeX = area == FCT_Area_LeftTan ? minDistanceX : minDistanceX/2.;
|
|
//halfSquareSizeY = area == FCT_Area_LeftTan ? minDistanceY : minDistanceY/2.;
|
|
top = leftTanHandle.centerY + halfSquareSizeY;
|
|
bottom = leftTanHandle.centerY - halfSquareSizeY;
|
|
left = leftTanHandle.centerX - halfSquareSizeX;
|
|
right = leftTanHandle.centerX + halfSquareSizeX;
|
|
|
|
// yellow
|
|
cr->set_source_rgb (1.0, 1.0, 0.0);
|
|
cr->move_to((double)RADIUS+0.5 + (double)innerWidth * left, (double)RADIUS+0.5 + (double)innerHeight * (1.-top));
|
|
cr->line_to((double)RADIUS+0.5 + (double)innerWidth * right, (double)RADIUS+0.5 + (double)innerHeight * (1.-top));
|
|
cr->line_to((double)RADIUS+0.5 + (double)innerWidth * right, (double)RADIUS+0.5 + (double)innerHeight * (1.-bottom));
|
|
cr->line_to((double)RADIUS+0.5 + (double)innerWidth * left, (double)RADIUS+0.5 + (double)innerHeight * (1.-bottom));
|
|
cr->line_to((double)RADIUS+0.5 + (double)innerWidth * left, (double)RADIUS+0.5 + (double)innerHeight * (1.-top));
|
|
cr->fill();
|
|
|
|
// RIGHT handle
|
|
//halfSquareSizeX = area == FCT_Area_RightTan ? minDistanceX : minDistanceX/2.;
|
|
//halfSquareSizeY = area == FCT_Area_RightTan ? minDistanceY : minDistanceY/2.;
|
|
top = rightTanHandle.centerY + halfSquareSizeY;
|
|
bottom = rightTanHandle.centerY - halfSquareSizeY;
|
|
left = rightTanHandle.centerX - halfSquareSizeX;
|
|
right = rightTanHandle.centerX + halfSquareSizeX;
|
|
|
|
// blue
|
|
cr->set_source_rgb (0.0, 0.0, 1.0);
|
|
cr->move_to((double)RADIUS+0.5 + (double)innerWidth * left, (double)RADIUS+0.5 + (double)innerHeight * (1.-top));
|
|
cr->line_to((double)RADIUS+0.5 + (double)innerWidth * right, (double)RADIUS+0.5 + (double)innerHeight * (1.-top));
|
|
cr->line_to((double)RADIUS+0.5 + (double)innerWidth * right, (double)RADIUS+0.5 + (double)innerHeight * (1.-bottom));
|
|
cr->line_to((double)RADIUS+0.5 + (double)innerWidth * left, (double)RADIUS+0.5 + (double)innerHeight * (1.-bottom));
|
|
cr->line_to((double)RADIUS+0.5 + (double)innerWidth * left, (double)RADIUS+0.5 + (double)innerHeight * (1.-top));
|
|
cr->fill();
|
|
}
|
|
|
|
get_window()->draw_drawable (style->get_fg_gc (state), pixmap, 0, 0, 0, 0, innerWidth + RADIUS * 2 + 1, innerHeight + RADIUS * 2 + 1);
|
|
}
|
|
|
|
/*
|
|
* Return the X1, X2, Y position of the tangential handles.
|
|
*/
|
|
bool MyFlatCurve::getHandles(int n) {
|
|
int N = curve.x.size();
|
|
double prevX, nextX;
|
|
double prevY, nextY;
|
|
double prevTan, nextTan;
|
|
double x, y, leftTan, rightTan;
|
|
|
|
if (n == -1) return false;
|
|
|
|
x = curve.x[n];
|
|
y = curve.y[n];
|
|
leftTan = curve.leftTangent[n];
|
|
rightTan = curve.rightTangent[n];
|
|
|
|
if (!n) {
|
|
// first point, the left handle is then computed with the last point's right handle
|
|
prevX = curve.x[N-1]-1.0;
|
|
prevY = curve.y[N-1];
|
|
prevTan = curve.rightTangent[N-1];
|
|
|
|
nextX = curve.x[n+1];
|
|
nextY = curve.y[n+1];
|
|
nextTan = curve.leftTangent[n+1];
|
|
}
|
|
else if (n == N-1) {
|
|
// last point, the right handle is then computed with the first point's left handle
|
|
prevX = curve.x[n-1];
|
|
prevY = curve.y[n-1];
|
|
prevTan = curve.rightTangent[n-1];
|
|
|
|
nextX = curve.x[0]+1.0;
|
|
nextY = curve.y[0];
|
|
nextTan = curve.leftTangent[0];
|
|
}
|
|
else {
|
|
// last point, the right handle is then computed with the first point's left handle
|
|
prevX = curve.x[n-1];
|
|
prevY = curve.y[n-1];
|
|
prevTan = curve.rightTangent[n-1];
|
|
|
|
nextX = curve.x[n+1];
|
|
nextY = curve.y[n+1];
|
|
nextTan = curve.leftTangent[n+1];
|
|
}
|
|
|
|
if (leftTan == 0.0) leftTanX = x;
|
|
else if (leftTan == 1.0) leftTanX = prevX;
|
|
else {
|
|
leftTanX = (prevX - x) * leftTan + x;
|
|
}
|
|
|
|
if (rightTan == 0.0) rightTanX = x;
|
|
else if (rightTan == 1.0) rightTanX = nextX;
|
|
else {
|
|
rightTanX = (nextX - x) * rightTan + x;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MyFlatCurve::handleEvents (GdkEvent* event) {
|
|
|
|
CursorShape new_type = cursor_type;
|
|
int src, dst;
|
|
std::vector<double>::iterator itx, ity, itlt, itrt;
|
|
|
|
bool retval = false;
|
|
int num = (int)curve.x.size();
|
|
|
|
/* innerWidth and innerHeight are the size of the graph */
|
|
innerWidth = get_allocation().get_width() - 2*RADIUS - 1;
|
|
innerHeight = get_allocation().get_height() - 2*RADIUS - 1;
|
|
|
|
minDistanceX = (double)(MIN_DISTANCE) / (double)innerWidth;
|
|
minDistanceY = (double)(MIN_DISTANCE) / (double)innerHeight;
|
|
|
|
if ((innerWidth < 0) || (innerHeight < 0))
|
|
return false;
|
|
|
|
switch (event->type) {
|
|
case Gdk::CONFIGURE: {
|
|
GdkEventConfigure* cEvent = (GdkEventConfigure*)event;
|
|
if (!sized) {
|
|
int size = get_allocation().get_width();
|
|
set_size_request(size, size);
|
|
sized = true;
|
|
}
|
|
if (pixmap)
|
|
pixmap.clear ();
|
|
retval = true;
|
|
break;
|
|
}
|
|
case Gdk::EXPOSE:
|
|
if (!sized) {
|
|
set_size_request(GRAPH_SIZE + RADIUS + 1, GRAPH_SIZE + RADIUS + 1);
|
|
}
|
|
sized = false;
|
|
if (!pixmap) {
|
|
pixmap = Gdk::Pixmap::create (get_window(), get_allocation().get_width(), get_allocation().get_height());
|
|
interpolate ();
|
|
}
|
|
draw ();
|
|
retval = true;
|
|
break;
|
|
|
|
case Gdk::BUTTON_PRESS:
|
|
//if (curve.type!=FCT_Parametric) {
|
|
if (event->button.button == 1) {
|
|
buttonPressed = true;
|
|
add_modal_grab ();
|
|
|
|
// get the pointer position
|
|
getCursorPosition(event);
|
|
getMouseOverArea();
|
|
|
|
// hide the tangent handles
|
|
tanHandlesDisplayed = false;
|
|
|
|
// Action on BUTTON_PRESS and no edited point
|
|
switch (area) {
|
|
|
|
case (FCT_Area_Insertion):
|
|
new_type = CSMove;
|
|
|
|
/* insert a new control point */
|
|
if (num > 0) {
|
|
if (clampedX > curve.x[closest_point])
|
|
++closest_point;
|
|
}
|
|
itx = curve.x.begin();
|
|
ity = curve.y.begin();
|
|
itlt = curve.leftTangent.begin();
|
|
itrt = curve.rightTangent.begin();
|
|
for (int i=0; i<closest_point; i++) { itx++; ity++; itlt++; itrt++; }
|
|
curve.x.insert (itx, 0);
|
|
curve.y.insert (ity, 0);
|
|
curve.leftTangent.insert (itlt, 0);
|
|
curve.rightTangent.insert (itrt, 0);
|
|
num++;
|
|
|
|
// the graph is refreshed only if a new point is created (snaped to a pixel)
|
|
curve.x[closest_point] = clampedX;
|
|
curve.y[closest_point] = clampedY;
|
|
curve.leftTangent[closest_point] = 0.35;
|
|
curve.rightTangent[closest_point] = 0.35;
|
|
|
|
interpolate ();
|
|
draw ();
|
|
notifyListener ();
|
|
|
|
lit_point = closest_point;
|
|
|
|
// point automatically activated
|
|
editedHandle = FCT_EditedHandle_CPoint;
|
|
ugpX = curve.x[lit_point];
|
|
ugpY = curve.y[lit_point];
|
|
break;
|
|
|
|
case (FCT_Area_Point):
|
|
new_type = CSMove;
|
|
editedHandle = FCT_EditedHandle_CPoint;
|
|
ugpX = curve.x[lit_point];
|
|
ugpY = curve.y[lit_point];
|
|
break;
|
|
|
|
case (FCT_Area_H):
|
|
case (FCT_Area_V):
|
|
new_type = CSMove;
|
|
editedHandle = FCT_EditedHandle_CPointUD;
|
|
ugpX = curve.x[lit_point];
|
|
ugpY = curve.y[lit_point];
|
|
break;
|
|
|
|
case (FCT_Area_LeftTan):
|
|
new_type = CSEmpty;
|
|
editedHandle = FCT_EditedHandle_LeftTan;
|
|
ugpX = curve.leftTangent[lit_point];
|
|
break;
|
|
|
|
case (FCT_Area_RightTan):
|
|
new_type = CSEmpty;
|
|
editedHandle = FCT_EditedHandle_RightTan;
|
|
ugpX = curve.rightTangent[lit_point];
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
if (buttonPressed) retval = true;
|
|
//}
|
|
break;
|
|
|
|
case Gdk::BUTTON_RELEASE:
|
|
//if (curve.type!=FCT_Parametric) {
|
|
if (buttonPressed && event->button.button == 1) {
|
|
buttonPressed = false;
|
|
enum MouseOverAreas prevArea = area;
|
|
remove_modal_grab ();
|
|
|
|
int previous_lit_point = lit_point;
|
|
|
|
// Removing any deleted point if we were previously modifying the point position
|
|
if (editedHandle & (FCT_EditedHandle_CPoint|FCT_EditedHandle_CPointX|FCT_EditedHandle_CPointY)) {
|
|
/* delete inactive points: */
|
|
itx = curve.x.begin();
|
|
ity = curve.y.begin();
|
|
itlt = curve.leftTangent.begin();
|
|
itrt = curve.rightTangent.begin();
|
|
for (src = dst = 0; src < num; ++src)
|
|
if (curve.x[src] >= 0.0) {
|
|
curve.x[dst] = curve.x[src];
|
|
curve.y[dst] = curve.y[src];
|
|
curve.leftTangent[dst] = curve.leftTangent[src];
|
|
curve.rightTangent[dst] = curve.rightTangent[src];
|
|
++dst;
|
|
++itx;
|
|
++ity;
|
|
++itlt;
|
|
++itrt;
|
|
}
|
|
if (dst < src) {
|
|
|
|
// curve cleanup
|
|
curve.x.erase (itx, curve.x.end());
|
|
curve.y.erase (ity, curve.y.end());
|
|
curve.leftTangent.erase (itlt, curve.leftTangent.end());
|
|
curve.rightTangent.erase (itrt, curve.rightTangent.end());
|
|
if (!curve.x.size()) {
|
|
curve.x.push_back (0.5);
|
|
curve.y.push_back (0.5);
|
|
curve.leftTangent.push_back (0.3);
|
|
curve.rightTangent.push_back (0.3);
|
|
interpolate ();
|
|
}
|
|
}
|
|
}
|
|
|
|
editedHandle = FCT_EditedHandle_None;
|
|
lit_point = -1;
|
|
|
|
// get the pointer position
|
|
getCursorPosition(event);
|
|
getMouseOverArea();
|
|
|
|
switch (area) {
|
|
|
|
case (FCT_Area_Insertion):
|
|
new_type = CSArrow;
|
|
break;
|
|
|
|
case (FCT_Area_Point):
|
|
new_type = CSMove;
|
|
break;
|
|
|
|
case (FCT_Area_H):
|
|
new_type = CSResizeHeight;
|
|
break;
|
|
|
|
case (FCT_Area_V):
|
|
new_type = CSMove;
|
|
break;
|
|
|
|
case (FCT_Area_LeftTan):
|
|
new_type = CSEmpty;
|
|
break;
|
|
|
|
case (FCT_Area_RightTan):
|
|
new_type = CSEmpty;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ((lit_point != previous_lit_point) || (prevArea != area))
|
|
draw ();
|
|
retval = true;
|
|
//notifyListener ();
|
|
}
|
|
//}
|
|
break;
|
|
|
|
case Gdk::MOTION_NOTIFY:
|
|
if (curve.type == FCT_Linear || curve.type == FCT_MinMaxCPoints) {
|
|
int previous_lit_point = lit_point;
|
|
enum MouseOverAreas prevArea = area;
|
|
// get the pointer position
|
|
getCursorPosition(event);
|
|
getMouseOverArea();
|
|
|
|
if (editedHandle == FCT_EditedHandle_CPointUD) {
|
|
double dX = deltaX;
|
|
double dY = deltaY;
|
|
if (dX < 0.) dX = -dX;
|
|
if (dY < 0.) dY = -dY;
|
|
if (dX > dY) {
|
|
editedHandle = FCT_EditedHandle_CPointX;
|
|
area = FCT_Area_V;
|
|
new_type = CSResizeWidth;
|
|
}
|
|
else {
|
|
editedHandle = FCT_EditedHandle_CPointY;
|
|
area = FCT_Area_H;
|
|
new_type = CSResizeHeight;
|
|
}
|
|
}
|
|
|
|
switch (editedHandle) {
|
|
|
|
case (FCT_EditedHandle_None): {
|
|
|
|
if ((lit_point != -1 && previous_lit_point != lit_point) && area & (FCT_Area_V|FCT_Area_Point)) {
|
|
|
|
bool sameSide = false;
|
|
|
|
// display the handles
|
|
tanHandlesDisplayed = true;
|
|
|
|
if (curve.x[lit_point] < 3.*minDistanceX) {
|
|
// lit_point too near of the left border -> both handles are displayed on the right of the vertical line
|
|
rightTanHandle.centerX = leftTanHandle.centerX = curve.x[lit_point] + 2.*minDistanceX;
|
|
sameSide = true;
|
|
}
|
|
else if (curve.x[lit_point] > 1.-3.*minDistanceX) {
|
|
// lit_point too near of the left border -> both handles are displayed on the right of the vertical line
|
|
rightTanHandle.centerX = leftTanHandle.centerX = curve.x[lit_point] - 2.*minDistanceX;
|
|
sameSide = true;
|
|
}
|
|
else {
|
|
leftTanHandle.centerX = curve.x[lit_point] - 2.*minDistanceX;
|
|
rightTanHandle.centerX = curve.x[lit_point] + 2.*minDistanceX;
|
|
}
|
|
if (sameSide) {
|
|
if (clampedY > 1.-2.*minDistanceY) {
|
|
// lit_point too near of the top border
|
|
leftTanHandle.centerY = 1. - minDistanceY;
|
|
rightTanHandle.centerY = 1. - 3.*minDistanceY;
|
|
}
|
|
else if (clampedY < 2.*minDistanceY) {
|
|
// lit_point too near of the bottom border
|
|
leftTanHandle.centerY = 3.*minDistanceY;
|
|
rightTanHandle.centerY = minDistanceY;
|
|
}
|
|
else {
|
|
leftTanHandle.centerY = clampedY + minDistanceY;
|
|
rightTanHandle.centerY = clampedY - minDistanceY;
|
|
}
|
|
}
|
|
else {
|
|
if (clampedY > 1.-minDistanceY) {
|
|
rightTanHandle.centerY = leftTanHandle.centerY = 1. - minDistanceY;
|
|
}
|
|
else if (clampedY < minDistanceY) {
|
|
rightTanHandle.centerY = leftTanHandle.centerY = minDistanceY;
|
|
}
|
|
else {
|
|
rightTanHandle.centerY = leftTanHandle.centerY = clampedY;
|
|
}
|
|
}
|
|
}
|
|
else if (lit_point == -1) {
|
|
tanHandlesDisplayed = false;
|
|
}
|
|
|
|
|
|
switch (area) {
|
|
|
|
case (FCT_Area_Insertion):
|
|
new_type = CSPlus;
|
|
break;
|
|
case (FCT_Area_Point):
|
|
//new_type = CSMove;
|
|
//break;
|
|
case (FCT_Area_V):
|
|
new_type = CSMove;
|
|
break;
|
|
case (FCT_Area_H):
|
|
new_type = CSResizeHeight;
|
|
break;
|
|
case (FCT_Area_LeftTan):
|
|
new_type = CSMoveLeft;
|
|
break;
|
|
case (FCT_Area_RightTan):
|
|
new_type = CSMoveRight;
|
|
break;
|
|
case (FCT_Area_None):
|
|
default:
|
|
new_type = CSArrow;
|
|
break;
|
|
}
|
|
|
|
if ((lit_point != previous_lit_point) || (prevArea != area))
|
|
draw ();
|
|
break;
|
|
}
|
|
|
|
case (FCT_EditedHandle_CPoint):
|
|
movePoint(true, true);
|
|
break;
|
|
|
|
case (FCT_EditedHandle_CPointX):
|
|
movePoint(true, false);
|
|
break;
|
|
|
|
case (FCT_EditedHandle_CPointY):
|
|
movePoint(false, true);
|
|
break;
|
|
|
|
case (FCT_EditedHandle_LeftTan): {
|
|
double prevValue = ugpX;
|
|
|
|
ugpX -= deltaX*3;
|
|
ugpX = CLAMP(ugpX, 0., 1.);
|
|
curve.leftTangent[lit_point] = ugpX;
|
|
|
|
if (ugpX != prevValue) {
|
|
interpolate ();
|
|
draw ();
|
|
notifyListener ();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (FCT_EditedHandle_RightTan): {
|
|
double prevValue = ugpX;
|
|
|
|
ugpX += deltaX*3;
|
|
ugpX = CLAMP(ugpX, 0., 1.);
|
|
curve.rightTangent[lit_point] = ugpX;
|
|
|
|
if (ugpX != prevValue) {
|
|
interpolate ();
|
|
draw ();
|
|
notifyListener ();
|
|
}
|
|
break;
|
|
}
|
|
|
|
// already process before the "switch" instruction
|
|
//case (FCT_EditedHandle_CPointUD):
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
retval = true;
|
|
break;
|
|
|
|
case Gdk::LEAVE_NOTIFY:
|
|
// Pointer can LEAVE even when dragging the point, so we don't modify the cursor in this case
|
|
// The cursor will have to LEAVE another time after the drag...
|
|
if (editedHandle == FCT_EditedHandle_None) {
|
|
new_type = CSArrow;
|
|
lit_point = -1;
|
|
tanHandlesDisplayed = false;
|
|
draw ();
|
|
}
|
|
retval = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
if (new_type != cursor_type) {
|
|
cursor_type = new_type;
|
|
cursorManager.setCursor(cursor_type);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void MyFlatCurve::movePoint(bool moveX, bool moveY) {
|
|
|
|
// bounds of the grabbed point
|
|
double leftBound;
|
|
double rightBound;
|
|
double const bottomBound = 0.;
|
|
double const topBound = 1.;
|
|
|
|
// we memorize the previous position of the point, for optimization purpose
|
|
double prevPosX = curve.x[lit_point];
|
|
double prevPosY = curve.y[lit_point];
|
|
|
|
int nbPoints = (int)curve.x.size();
|
|
|
|
// left and right bound rely on curve periodicity
|
|
leftBound = (lit_point == 0 ) ? (periodic ? curve.x[nbPoints-1]-1. : 0.) : curve.x[lit_point-1];
|
|
rightBound = (lit_point == nbPoints-1) ? (periodic ? curve.x[0]+1. : 1.) : curve.x[lit_point+1];
|
|
|
|
double leftDeletionBound = leftBound - minDistanceX;
|
|
double rightDeletionBound = rightBound + minDistanceX;
|
|
double bottomDeletionBound = bottomBound - minDistanceY;
|
|
double topDeletionBound = topBound + minDistanceY;
|
|
|
|
if (moveX) {
|
|
// we memorize the previous position of the point, for optimization purpose
|
|
ugpX += deltaX;
|
|
|
|
// handling periodicity (the first and last point can reappear at the other side of the X range)
|
|
if (periodic) {
|
|
if (lit_point==0 && ugpX<0.) {
|
|
// the first point has to be placed at the tail of the point list
|
|
std::vector<double>::iterator itx, ity, itlt, itrt;
|
|
|
|
ugpX += 1.;
|
|
leftBound += 1.;
|
|
rightBound += 1.;
|
|
leftDeletionBound += 1.;
|
|
rightDeletionBound += 1.;
|
|
|
|
// adding a copy of the first point to the tail of the list
|
|
curve.x.push_back(curve.x[0]);
|
|
curve.y.push_back(curve.y[0]);
|
|
curve.leftTangent.push_back(curve.leftTangent[0]);
|
|
curve.rightTangent.push_back(curve.rightTangent[0]);
|
|
|
|
// deleting the first point
|
|
itx = curve.x.begin();
|
|
ity = curve.y.begin();
|
|
itlt = curve.leftTangent.begin();
|
|
itrt = curve.rightTangent.begin();
|
|
|
|
curve.x.erase(itx);
|
|
curve.y.erase(ity);
|
|
curve.leftTangent.erase(itlt);
|
|
curve.rightTangent.erase(itrt);
|
|
|
|
lit_point = nbPoints-1;
|
|
}
|
|
else if (lit_point==(nbPoints-1) && ugpX>1.) {
|
|
// the last point has to be placed at the head of the point list
|
|
std::vector<double>::iterator itx, ity, itlt, itrt;
|
|
|
|
ugpX -= 1.;
|
|
leftBound -= 1.;
|
|
rightBound -= 1.;
|
|
leftDeletionBound -= 1.;
|
|
rightDeletionBound -= 1.;
|
|
|
|
// adding a copy of the last point to the head of the list
|
|
itx = curve.x.begin();
|
|
ity = curve.y.begin();
|
|
itlt = curve.leftTangent.begin();
|
|
itrt = curve.rightTangent.begin();
|
|
|
|
curve.x.insert(itx,0);
|
|
curve.y.insert(ity,0);
|
|
curve.leftTangent.insert(itlt,0);
|
|
curve.rightTangent.insert(itrt,0);
|
|
|
|
curve.x[0] = curve.x[nbPoints];
|
|
curve.y[0] = curve.y[nbPoints];
|
|
curve.leftTangent[0] = curve.leftTangent[nbPoints];
|
|
curve.rightTangent[0] = curve.rightTangent[nbPoints];
|
|
|
|
// deleting the last point
|
|
curve.x.pop_back();
|
|
curve.y.pop_back();
|
|
curve.leftTangent.pop_back();
|
|
curve.rightTangent.pop_back();
|
|
|
|
lit_point = 0;
|
|
}
|
|
}
|
|
|
|
// handling limitations along X axis
|
|
if (ugpX >= rightDeletionBound && nbPoints>2) {
|
|
curve.x[lit_point] = -1.;
|
|
}
|
|
else if (ugpX <= leftDeletionBound && nbPoints>2) {
|
|
curve.x[lit_point] = -1.;
|
|
}
|
|
else
|
|
// nextPosX is in bounds
|
|
curve.x[lit_point] = CLAMP(ugpX, leftBound, rightBound);
|
|
}
|
|
|
|
if (moveY) {
|
|
// we memorize the previous position of the point, for optimization purpose
|
|
ugpY += deltaY;
|
|
|
|
// Handling limitations along Y axis
|
|
if (ugpY >= topDeletionBound && nbPoints>2) {
|
|
if (curve.x[lit_point] != -1.) {
|
|
deletedPointX = curve.x[lit_point];
|
|
curve.x[lit_point] = -1.;
|
|
curve.y[lit_point] = ugpY; // This is only to force the redraw of the curve
|
|
}
|
|
}
|
|
else if (ugpY <= bottomDeletionBound && nbPoints>2) {
|
|
if (curve.x[lit_point] != -1.) {
|
|
deletedPointX = curve.x[lit_point];
|
|
curve.x[lit_point] = -1.;
|
|
curve.y[lit_point] = ugpY; // This is only to force the redraw of the curve
|
|
}
|
|
}
|
|
else {
|
|
// nextPosY is in the bounds
|
|
curve.y[lit_point] = CLAMP(ugpY, 0.0, 1.0);
|
|
if (!moveX && curve.x[lit_point] == -1.) {
|
|
// bring back the X value of the point if it reappear
|
|
curve.x[lit_point] = deletedPointX;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (curve.x[lit_point] != prevPosX || curve.y[lit_point] != prevPosY) {
|
|
// we recalculate the curve only if we have to
|
|
interpolate ();
|
|
draw ();
|
|
notifyListener ();
|
|
}
|
|
}
|
|
|
|
// Set datas relative to cursor position
|
|
void MyFlatCurve::getCursorPosition(GdkEvent* event) {
|
|
int tx, ty;
|
|
int prevCursorX, prevCursorY;
|
|
double incrementX = 1. / (double)innerWidth;
|
|
double incrementY = 1. / (double)innerHeight;
|
|
|
|
switch (event->type) {
|
|
case (Gdk::MOTION_NOTIFY) :
|
|
if (event->motion.is_hint) {
|
|
get_window()->get_pointer (tx, ty, mod_type);
|
|
}
|
|
else {
|
|
tx = (int)event->button.x;
|
|
ty = (int)event->button.y;
|
|
mod_type = (Gdk::ModifierType)event->button.state;
|
|
}
|
|
break;
|
|
case (Gdk::BUTTON_PRESS) :
|
|
case (Gdk::BUTTON_RELEASE) :
|
|
tx = (int)event->button.x;
|
|
ty = (int)event->button.y;
|
|
mod_type = (Gdk::ModifierType)event->button.state;
|
|
break;
|
|
default :
|
|
// The cursor position is not available
|
|
return;
|
|
break;
|
|
}
|
|
|
|
if (editedHandle != FCT_EditedHandle_None) {
|
|
prevCursorX = cursorX;
|
|
prevCursorY = cursorY;
|
|
}
|
|
cursorX = tx - RADIUS;
|
|
cursorY = innerHeight - (ty - RADIUS);
|
|
|
|
preciseCursorX = cursorX * incrementX;
|
|
preciseCursorY = cursorY * incrementY;
|
|
|
|
snapTo = ST_None;
|
|
|
|
// update deltaX/Y if the user drags a point
|
|
if (editedHandle != FCT_EditedHandle_None) {
|
|
// set the dragging factor
|
|
int control_key = mod_type & GDK_CONTROL_MASK;
|
|
int shift_key = mod_type & GDK_SHIFT_MASK;
|
|
|
|
// the increment get smaller if modifier key are used, and "snap to" may be enabled
|
|
if (control_key && shift_key) { snapTo = ST_Neighbors; }
|
|
else if (control_key) { snapTo = ST_Identity; }
|
|
else if (shift_key) { incrementX *= 0.04; incrementY *= 0.04; }
|
|
|
|
deltaX = (double)(cursorX - prevCursorX) * incrementX;
|
|
deltaY = (double)(cursorY - prevCursorY) * incrementY;
|
|
}
|
|
// otherwise set the position of the new point (modifier keys has no effect here)
|
|
else {
|
|
clampedX = CLAMP (preciseCursorX, 0., 1.); // X position of the pointer from the origin of the graph
|
|
clampedY = CLAMP (preciseCursorY, 0., 1.); // Y position of the pointer from the origin of the graph
|
|
}
|
|
|
|
}
|
|
|
|
// Find out the active area under the cursor
|
|
void MyFlatCurve::getMouseOverArea () {
|
|
|
|
// When dragging an element, editedHandle keep its value
|
|
if (editedHandle == FCT_EditedHandle_None) {
|
|
|
|
double minDist = 1000; // used to find out the point pointed by the cursor (over it)
|
|
double minDistX = 1000; // used to find out the closest point
|
|
double dX, dY;
|
|
double absDX;
|
|
double dist;
|
|
bool aboveVLine = false;
|
|
|
|
// NB: this function assume that the graph's shape is a square
|
|
|
|
//if (curve.type!=Parametric) {
|
|
|
|
// we first check first if the cursor is still over a tangent handle
|
|
/*if (area = (FCT_Area_LeftTan|FCT_Area_RightTan)) {
|
|
if (still over a tangent handle) {
|
|
|
|
}
|
|
area = FCT_Area_None;
|
|
return;
|
|
}*/
|
|
|
|
// Check if the cursor is over a tangent handle
|
|
if (tanHandlesDisplayed) {
|
|
|
|
if (preciseCursorX>=(leftTanHandle.centerX-minDistanceX) && preciseCursorX<=(leftTanHandle.centerX+minDistanceX+0.00001)
|
|
&& preciseCursorY>=(leftTanHandle.centerY-minDistanceY) && preciseCursorY<=(leftTanHandle.centerY+minDistanceY)) {
|
|
area = FCT_Area_LeftTan;
|
|
return;
|
|
}
|
|
if (preciseCursorX>=(rightTanHandle.centerX-minDistanceX-0.00001) && preciseCursorX<=(rightTanHandle.centerX+minDistanceX)
|
|
&& preciseCursorY>=(rightTanHandle.centerY-minDistanceY ) && preciseCursorY<=(rightTanHandle.centerY+minDistanceY)) {
|
|
area = FCT_Area_RightTan;
|
|
return;
|
|
}
|
|
}
|
|
|
|
area = FCT_Area_None;
|
|
closest_point = 0;
|
|
lit_point = -1;
|
|
|
|
for (int i = 0; i < (int)curve.x.size(); i++) {
|
|
if (curve.x[i] != -1) {
|
|
dX = curve.x[i] - preciseCursorX;
|
|
absDX = dX>0 ? dX : -dX;
|
|
if (absDX < minDistX) {
|
|
minDistX = absDX;
|
|
closest_point = i;
|
|
lit_point = i;
|
|
}
|
|
if (absDX <= minDistanceX) {
|
|
aboveVLine = true;
|
|
dY = curve.y[i] - preciseCursorY;
|
|
dist = sqrt(dX*dX + dY*dY);
|
|
if (dist < minDist) {
|
|
minDist = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (minDist <= minDistanceX) {
|
|
// the cursor is over the point
|
|
area = FCT_Area_Point;
|
|
}
|
|
else if (aboveVLine) {
|
|
area = FCT_Area_V;
|
|
}
|
|
else {
|
|
// Check if the cursor is in an insertion area
|
|
lit_point = -1;
|
|
if (preciseCursorX>=0.0 && preciseCursorX<=1.0 && preciseCursorY>=0.0 && preciseCursorY<=1.0)
|
|
area = FCT_Area_Insertion;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<double> MyFlatCurve::getPoints () {
|
|
std::vector<double> result;
|
|
/*if (curve.type==FCT_Parametric) {
|
|
result.push_back ((double)(Parametric));
|
|
for (int i=0; i<(int)curve.x.size(); i++) {
|
|
result.push_back (curve.x[i]);
|
|
}
|
|
}
|
|
else {*/
|
|
// the first value gives the type of the curve
|
|
if (curve.type==FCT_Linear)
|
|
result.push_back ((double)(FCT_Linear));
|
|
else if (curve.type==FCT_MinMaxCPoints)
|
|
result.push_back ((double)(FCT_MinMaxCPoints));
|
|
// then we push all the points coordinate
|
|
for (int i=0; i<(int)curve.x.size(); i++) {
|
|
if (curve.x[i]>=0) {
|
|
result.push_back (curve.x[i]);
|
|
result.push_back (curve.y[i]);
|
|
result.push_back (curve.leftTangent[i]);
|
|
result.push_back (curve.rightTangent[i]);
|
|
}
|
|
}
|
|
//}
|
|
return result;
|
|
}
|
|
|
|
void MyFlatCurve::setPoints (const std::vector<double>& p) {
|
|
int ix = 0;
|
|
FlatCurveType t = (FlatCurveType)p[ix++];
|
|
curve.type = t;
|
|
if (t==FCT_MinMaxCPoints) {
|
|
curve.x.clear ();
|
|
curve.y.clear ();
|
|
curve.leftTangent.clear();
|
|
curve.rightTangent.clear();
|
|
for (int i=0; i<(int)p.size()/4; i++) {
|
|
curve.x.push_back (p[ix++]);
|
|
curve.y.push_back (p[ix++]);
|
|
curve.leftTangent.push_back (p[ix++]);
|
|
curve.rightTangent.push_back (p[ix++]);
|
|
}
|
|
}
|
|
pixmap.clear ();
|
|
queue_draw ();
|
|
}
|
|
|
|
void MyFlatCurve::setType (FlatCurveType t) {
|
|
|
|
curve.type = t;
|
|
pixmap.clear ();
|
|
}
|
|
|
|
/*int flatmchistupdate (void* data) {
|
|
|
|
gdk_threads_enter ();
|
|
|
|
MyFlatCurveIdleHelper* mcih = (MyFlatCurveIdleHelper*)data;
|
|
|
|
if (mcih->destroyed) {
|
|
if (mcih->pending == 1)
|
|
delete mcih;
|
|
else
|
|
mcih->pending--;
|
|
gdk_threads_leave ();
|
|
return 0;
|
|
}
|
|
|
|
mcih->clearPixmap ();
|
|
mcih->myCurve->queue_draw ();
|
|
|
|
mcih->pending--;
|
|
gdk_threads_leave ();
|
|
return 0;
|
|
}*/
|
|
|
|
/*void MyFlatCurve::updateBackgroundHistogram (unsigned int* hist) {
|
|
|
|
if (hist!=NULL) {
|
|
memcpy (bghist, hist, 256*sizeof(unsigned int));
|
|
bghistvalid = true;
|
|
}
|
|
else
|
|
bghistvalid = false;
|
|
|
|
mcih->pending++;
|
|
g_idle_add (flatmchistupdate, mcih);
|
|
|
|
}*/
|
|
|
|
void MyFlatCurve::reset() {
|
|
innerWidth = get_allocation().get_width() - RADIUS * 2;
|
|
innerHeight = get_allocation().get_height() - RADIUS * 2;
|
|
|
|
switch (curve.type) {
|
|
case FCT_MinMaxCPoints :
|
|
defaultCurve();
|
|
lit_point = -1;
|
|
interpolate ();
|
|
break;
|
|
//case Parametric :
|
|
// Nothing to do (?)
|
|
default:
|
|
break;
|
|
}
|
|
draw();
|
|
}
|
|
|
|
void MyFlatCurve::defaultCurve () {
|
|
|
|
curve.x.clear();
|
|
curve.y.clear();
|
|
curve.leftTangent.clear();
|
|
curve.rightTangent.clear();
|
|
|
|
// Point for RGBCMY colors
|
|
for (int i=0; i<6; i++) {
|
|
curve.x.push_back((1./6.)*i);
|
|
curve.y.push_back(0.5);
|
|
curve.leftTangent.push_back(0.35);
|
|
curve.rightTangent.push_back(0.35);
|
|
}
|
|
|
|
}
|