Enhanced curve editor :

- graphical celan up (surrounding frame deleted, histogram realigned)
- a feedback tell what point is going to move
- on Button press, the point doesn't move to the cursor anymore. Instead, the cursor
  is hidden during the drag and reappear in the same place it disappeared
- by default, a 0.5 factor is used to move the point during the drag
  (i.e. you have to move the move of 2 pixel to move the point of one pixel)
- keyboard can be used to fine tune the point position (subpixel placement) :
   - CTRL : factor = 0.1
   - SHIFT : factor = 0.02
   - CTRL+SHIFT : factor = 0.005

In the mean time, i had to create a new "Empty" cursor to hide it.
A new method has been created to easily modify the cursor of the main window.
This commit is contained in:
Hombre
2010-07-05 14:54:34 +02:00
parent 6d5fc87c3d
commit 28feec5dd9
5 changed files with 191 additions and 93 deletions

View File

@@ -30,21 +30,25 @@ void CursorManager::init (Glib::RefPtr<Gdk::Window> mainWin) {
cCropMove = new Gdk::Cursor (Gdk::FLEUR); cCropMove = new Gdk::Cursor (Gdk::FLEUR);
cCropMoving = new Gdk::Cursor (Gdk::HAND2); cCropMoving = new Gdk::Cursor (Gdk::HAND2);
cCropSelection = new Gdk::Cursor (Gdk::CROSSHAIR); cCropSelection = new Gdk::Cursor (Gdk::CROSSHAIR);
#ifdef _WIN32 cAdd = new Gdk::Cursor (Gdk::PLUS);
cNormal = new Gdk::Cursor (Gdk::LAST_CURSOR); //#ifdef _WIN32
#else // cNormal = new Gdk::Cursor (Gdk::LAST_CURSOR);
//#else
cNormal = new Gdk::Cursor (Gdk::ARROW); cNormal = new Gdk::Cursor (Gdk::ARROW);
#endif //#endif
Glib::RefPtr<Gdk::Pixbuf> hand = safe_create_from_file(argv0+"/images/openhand22.png"); Glib::RefPtr<Gdk::Pixbuf> hand = safe_create_from_file(argv0+"/images/openhand22.png");
Glib::RefPtr<Gdk::Pixbuf> close_hand = safe_create_from_file(argv0+"/images/closedhand22.png"); Glib::RefPtr<Gdk::Pixbuf> close_hand = safe_create_from_file(argv0+"/images/closedhand22.png");
Glib::RefPtr<Gdk::Pixbuf> wbpick = safe_create_from_file(argv0+"/images/wbpicker16.png"); Glib::RefPtr<Gdk::Pixbuf> wbpick = safe_create_from_file(argv0+"/images/wbpicker16.png");
cHand = hand ? new Gdk::Cursor (cNormal->get_display(), hand, 10, 10) : new Gdk::Cursor (Gdk::HAND2); Glib::RefPtr<Gdk::Pixbuf> empty = safe_create_from_file(argv0+"/images/empty.png");
cHand = hand ? new Gdk::Cursor (cNormal->get_display(), hand, 10, 10) : new Gdk::Cursor (Gdk::HAND2);
cClosedHand = close_hand ? new Gdk::Cursor (cNormal->get_display(), close_hand, 10, 10) : new Gdk::Cursor (Gdk::HAND2); cClosedHand = close_hand ? new Gdk::Cursor (cNormal->get_display(), close_hand, 10, 10) : new Gdk::Cursor (Gdk::HAND2);
cWB = wbpick ? new Gdk::Cursor (cNormal->get_display(), wbpick, 1, 12) : new Gdk::Cursor (Gdk::ARROW); cWB = wbpick ? new Gdk::Cursor (cNormal->get_display(), wbpick, 1, 12) : new Gdk::Cursor (Gdk::ARROW);
cHidden = empty ? new Gdk::Cursor (cNormal->get_display(), empty, 12, 12) : new Gdk::Cursor (Gdk::FLEUR);
mainWindow = mainWin; mainWindow = mainWin;
} }
/* Set the cursor of the given window */
void CursorManager::setCursor (Glib::RefPtr<Gdk::Window> window, CursorShape shape) { void CursorManager::setCursor (Glib::RefPtr<Gdk::Window> window, CursorShape shape) {
if (shape==CSArrow) if (shape==CSArrow)
@@ -67,6 +71,14 @@ void CursorManager::setCursor (Glib::RefPtr<Gdk::Window> window, CursorShape sha
window->set_cursor (*cCropSelection); window->set_cursor (*cCropSelection);
else if (shape==CSStraighten) else if (shape==CSStraighten)
window->set_cursor (*cCropSelection); window->set_cursor (*cCropSelection);
else if (shape==CSPlus)
window->set_cursor (*cAdd);
else if (shape==CSEmpty)
window->set_cursor (*cHidden);
} }
/* Set the cursor of the main window */
void CursorManager::setCursor (CursorShape shape) {
setCursor(mainWindow, shape);
}

View File

@@ -21,7 +21,7 @@
#include <gtkmm.h> #include <gtkmm.h>
enum CursorShape {CSArrow, CSOpenHand, CSClosedHand, CSMove, CSResizeWidth, CSResizeHeight, CSResizeDiagonal, CSSpotWB, CSCropSelect, CSStraighten}; enum CursorShape {CSArrow, CSOpenHand, CSClosedHand, CSMove, CSResizeWidth, CSResizeHeight, CSResizeDiagonal, CSSpotWB, CSCropSelect, CSStraighten, CSPlus, CSEmpty};
class CursorManager { class CursorManager {
@@ -33,14 +33,17 @@ class CursorManager {
Gdk::Cursor* cCropMoving; Gdk::Cursor* cCropMoving;
Gdk::Cursor* cNormal; Gdk::Cursor* cNormal;
Gdk::Cursor* cCropSelection; Gdk::Cursor* cCropSelection;
Gdk::Cursor* cAdd;
Gdk::Cursor* cHand; Gdk::Cursor* cHand;
Gdk::Cursor* cClosedHand; Gdk::Cursor* cClosedHand;
Gdk::Cursor* cWB; Gdk::Cursor* cWB;
Gdk::Cursor* cHidden;
Glib::RefPtr<Gdk::Window> mainWindow; Glib::RefPtr<Gdk::Window> mainWindow;
public: public:
void init (Glib::RefPtr<Gdk::Window> mainWin); void init (Glib::RefPtr<Gdk::Window> mainWin);
void setCursor (Glib::RefPtr<Gdk::Window> window, CursorShape shape); void setCursor (Glib::RefPtr<Gdk::Window> window, CursorShape shape);
void setCursor (CursorShape shape);
}; };
extern CursorManager cursorManager; extern CursorManager cursorManager;

View File

@@ -40,12 +40,16 @@ CurveEditor::CurveEditor () : cl(NULL), activeParamControl(-1), realized(false),
// custom curve // custom curve
customCurveBox = new Gtk::VBox (); customCurveBox = new Gtk::VBox ();
Gtk::HBox* tmpa = Gtk::manage (new Gtk::HBox ());
customCurve = Gtk::manage (new MyCurve ()); customCurve = Gtk::manage (new MyCurve ());
Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); Gtk::Table* cctab = Gtk::manage (new Gtk::Table (2,1));
af->add (*customCurve); //Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false));
customCurve->set_size_request (-1, 200); //af->add (*customCurve);
customCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS);
customCurve->setType (Spline); customCurve->setType (Spline);
customCurveBox->pack_start (*af, Gtk::PACK_EXPAND_WIDGET); tmpa->pack_start (*customCurve, true, false, 4);
customCurveBox->pack_start (*tmpa, true, true,4);
//customCurveBox->set_size_request (0, -1);
Gtk::HBox* bbox = Gtk::manage (new Gtk::HBox ()); Gtk::HBox* bbox = Gtk::manage (new Gtk::HBox ());
save = Gtk::manage (new Gtk::Button ()); save = Gtk::manage (new Gtk::Button ());
@@ -67,19 +71,19 @@ CurveEditor::CurveEditor () : cl(NULL), activeParamControl(-1), realized(false),
// parametric curve // parametric curve
paramCurveBox = new Gtk::VBox (); paramCurveBox = new Gtk::VBox ();
paramCurve = Gtk::manage (new MyCurve ()); paramCurve = Gtk::manage (new MyCurve ());
Gtk::Table* ctab = Gtk::manage (new Gtk::Table (2,1)); Gtk::Table* paramctab = Gtk::manage (new Gtk::Table (2,1));
Gtk::AspectFrame* afp = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); //Gtk::AspectFrame* afp = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false));
afp->add (*paramCurve); //afp->add (*paramCurve);
paramCurve->set_size_request (200, 200); paramCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS);
paramCurve->setType (Parametric); paramCurve->setType (Parametric);
shcSelector = Gtk::manage (new SHCSelector ()); shcSelector = Gtk::manage (new SHCSelector ());
shcSelector->set_size_request (200, 20); shcSelector->set_size_request (GRAPH_SIZE, 20);
ctab->attach (*afp, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); paramctab->attach (*paramCurve, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, RADIUS+2, RADIUS+2);
ctab->attach (*shcSelector, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); paramctab->attach (*shcSelector, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, RADIUS+2, 2);
Gtk::HBox* tmpb = Gtk::manage (new Gtk::HBox ()); Gtk::HBox* tmpb = Gtk::manage (new Gtk::HBox ());
tmpb->pack_start (*ctab, true, false); tmpb->pack_start (*paramctab, true, false);
paramCurveBox->pack_start (*tmpb, true, true); paramCurveBox->pack_start (*tmpb, true, true);

View File

@@ -19,18 +19,17 @@
#include <mycurve.h> #include <mycurve.h>
#include <curves.h> #include <curves.h>
#include <string.h> #include <string.h>
#include <gdkmm/types.h>
#define RADIUS 3 /* radius of the control points */
#define MIN_DISTANCE 8 /* min distance between control points */
MyCurve::MyCurve () : listener(NULL), activeParam(-1), bghistvalid(false) { MyCurve::MyCurve () : listener(NULL), activeParam(-1), bghistvalid(false) {
cursor_type = Gdk::TOP_LEFT_ARROW; cursor_type = CSArrow;
curve.type = Spline; curve.type = Spline;
height = 0; height = 0;
grab_point = -1; grab_point = -1;
lit_point = -1;
add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK); add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK);
signal_event().connect( sigc::mem_fun(*this, &MyCurve::handleEvents) ); signal_event().connect( sigc::mem_fun(*this, &MyCurve::handleEvents) );
curve.x.push_back(0); curve.x.push_back(0);
@@ -126,7 +125,8 @@ void MyCurve::interpolate (int width, int height) {
} }
} }
void MyCurve::draw (int width, int height) { void MyCurve::draw (int width, int height, int handle) {
// width and heigth are the size of the graph
if (!pixmap) if (!pixmap)
return; return;
@@ -135,7 +135,6 @@ void MyCurve::draw (int width, int height) {
if (this->height != height || point.size() != width) if (this->height != height || point.size() != width)
interpolate (width, height); interpolate (width, height);
Gtk::StateType state = Gtk::STATE_NORMAL; Gtk::StateType state = Gtk::STATE_NORMAL;
if (!is_sensitive()) if (!is_sensitive())
state = Gtk::STATE_INSENSITIVE; state = Gtk::STATE_INSENSITIVE;
@@ -159,16 +158,16 @@ void MyCurve::draw (int width, int height) {
// draw histogram // draw histogram
cr->set_line_width (1.0); cr->set_line_width (1.0);
double stepSize = (width-1) / 256.0; double stepSize = (width-1) / 256.0;
cr->move_to (0, height-1); cr->move_to (RADIUS, height-1+RADIUS);
cr->set_source_rgb (0.75, 0.75, 0.75); cr->set_source_rgb (0.75, 0.75, 0.75);
for (int i=0; i<256; i++) { for (int i=0; i<256; i++) {
double val = bghist[i] * (double)(height-2) / histheight; double val = bghist[i] * (double)(height-2) / histheight;
if (val>height-1) if (val>height-1)
val = height-1; val = height-1;
if (i>0) if (i>0)
cr->line_to (i*stepSize, height-1-val); cr->line_to (i*stepSize+RADIUS, height-1+RADIUS-val);
} }
cr->line_to (width-1, height-1); cr->line_to (width-1+RADIUS, height-1+RADIUS);
cr->fill (); cr->fill ();
} }
@@ -178,10 +177,10 @@ void MyCurve::draw (int width, int height) {
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->set_antialias (Cairo::ANTIALIAS_NONE); cr->set_antialias (Cairo::ANTIALIAS_NONE);
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
cr->move_to (RADIUS, i * height / 4 + RADIUS); cr->move_to (RADIUS, MAX(0,i * height / 4 - 1) + RADIUS);
cr->line_to (width + RADIUS, i * height / 4 + RADIUS); cr->line_to (width + RADIUS, MAX(0,i * height / 4 - 1) + RADIUS);
cr->move_to (i * width / 4 + RADIUS, RADIUS); cr->move_to (MAX(0,i * width / 4 - 1) + RADIUS, RADIUS);
cr->line_to (i * width / 4 + RADIUS, height + RADIUS); cr->line_to (MAX(0,i * width / 4 - 1) + RADIUS, height + RADIUS);
} }
cr->stroke (); cr->stroke ();
@@ -195,6 +194,7 @@ void MyCurve::draw (int width, int height) {
cr->stroke (); cr->stroke ();
cr->unset_dash (); cr->unset_dash ();
cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
cr->set_line_width (1.0); cr->set_line_width (1.0);
@@ -221,10 +221,11 @@ void MyCurve::draw (int width, int height) {
// draw bullets // draw bullets
if (curve.type!=Parametric) if (curve.type!=Parametric)
for (int i = 0; i < curve.x.size(); ++i) { for (int i = 0; i < curve.x.size(); ++i) {
cr->set_source_rgb ((i == handle ? 1.0 : 0.0), 0.0, 0.0);
double x = ((width-1) * curve.x[i] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, width); double x = ((width-1) * curve.x[i] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, width);
double y = height - ((height-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, height); double y = height - ((height-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, height);
cr->arc (x, y, RADIUS, 0, 2*M_PI); cr->arc (x, y, RADIUS+0.5, 0, 2*M_PI);
cr->fill (); cr->fill ();
} }
@@ -233,13 +234,17 @@ void MyCurve::draw (int width, int height) {
bool MyCurve::handleEvents (GdkEvent* event) { bool MyCurve::handleEvents (GdkEvent* event) {
Gdk::CursorType new_type = cursor_type; CursorShape new_type = cursor_type;
int src, dst; int src, dst;
GdkEventMotion *mevent; GdkEventMotion *mevent;
std::vector<double>::iterator itx, ity; std::vector<double>::iterator itx, ity;
Glib::RefPtr<Gdk::Display> rt_display = Gtk::Widget::get_display();
Glib::RefPtr<Gdk::Screen> rt_screen = Gtk::Widget::get_screen();
bool retval = false; bool retval = false;
/* width and height are the size of the graph */
int width = get_allocation().get_width() - RADIUS * 2; int width = get_allocation().get_width() - RADIUS * 2;
int height = get_allocation().get_height() - RADIUS * 2; int height = get_allocation().get_height() - RADIUS * 2;
@@ -250,12 +255,12 @@ bool MyCurve::handleEvents (GdkEvent* event) {
int tx, ty; int tx, ty;
Gdk::ModifierType gm; Gdk::ModifierType gm;
get_window()->get_pointer (tx, ty, gm); get_window()->get_pointer (tx, ty, gm);
int x = CLAMP ((tx - RADIUS), 0, width-1); int x = CLAMP ((tx - RADIUS), 0, width-1); // X position of the pointer from the origin of the graph
int y = CLAMP ((ty - RADIUS), 0, height-1); int y = height-1 - CLAMP ((ty - RADIUS), 0, height-1); // Y position of the pointer from the origin of the graph
unsigned int distance = ~0U; unsigned int distance = ~0U;
int num = curve.x.size(); int num = curve.x.size();
int closest_point = 0; int closest_point = -1;
if (curve.type!=Parametric) { if (curve.type!=Parametric) {
for (int i = 0; i < num; ++i) { for (int i = 0; i < num; ++i) {
@@ -273,17 +278,23 @@ bool MyCurve::handleEvents (GdkEvent* event) {
pixmap.clear (); pixmap.clear ();
case Gdk::EXPOSE: case Gdk::EXPOSE:
// When does this event occurs ???
if (!pixmap) { if (!pixmap) {
pixmap = Gdk::Pixmap::create (get_window(), get_allocation().get_width(), get_allocation().get_height()); pixmap = Gdk::Pixmap::create (get_window(), get_allocation().get_width(), get_allocation().get_height());
interpolate (width, height); interpolate (width, height);
} }
draw (width, height); draw (width, height, lit_point);
break; break;
case Gdk::BUTTON_PRESS: case Gdk::BUTTON_PRESS:
if (curve.type!=Parametric) { if (curve.type!=Parametric) {
add_modal_grab (); add_modal_grab ();
new_type = Gdk::PLUS;
// get cursor position
Gdk::ModifierType mod_type;
rt_display->get_pointer(cursor_x, cursor_y, mod_type);
new_type = CSEmpty;
if (distance > MIN_DISTANCE) { if (distance > MIN_DISTANCE) {
/* insert a new control point */ /* insert a new control point */
if (num > 0) { if (num > 0) {
@@ -294,24 +305,30 @@ bool MyCurve::handleEvents (GdkEvent* event) {
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++; }
curve.x.insert (itx, 0); curve.x.insert (itx, 0);
curve.y.insert (ity, 0); curve.y.insert (ity, 0);
num++; num++;
}
grab_point = closest_point; // the graph is refreshed only if a new point is created (snaped to a pixel)
curve.x[grab_point] = (double) x / (width-1); curve.x[closest_point] = (double) x / (width-1);
curve.y[grab_point] = (double) (height-y) / (height-1); curve.y[closest_point] = (double) y / (height-1);
interpolate (width, height); interpolate (width, height);
notifyListener (); draw (width, height, closest_point);
break; }
grab_point = closest_point;
lit_point = closest_point;
ugp_x = curve.x[closest_point];
ugp_y = curve.y[closest_point];
notifyListener ();
break;
} }
draw (width, height);
retval = true; retval = true;
break; break;
case Gdk::BUTTON_RELEASE: case Gdk::BUTTON_RELEASE:
if (curve.type!=Parametric) { if (curve.type!=Parametric) {
remove_modal_grab (); remove_modal_grab ();
int previous_lit_point = lit_point;
/* delete inactive points: */ /* delete inactive points: */
itx = curve.x.begin(); itx = curve.x.begin();
ity = curve.y.begin(); ity = curve.y.begin();
@@ -330,61 +347,115 @@ bool MyCurve::handleEvents (GdkEvent* event) {
curve.x.push_back (0); curve.x.push_back (0);
curve.y.push_back (0); curve.y.push_back (0);
interpolate (width, height); interpolate (width, height);
draw (width, height); draw (width, height, lit_point);
} }
} }
new_type = Gdk::FLEUR; if (distance <= MIN_DISTANCE) {
new_type = CSMove;
lit_point = closest_point;
}
else {
new_type = CSPlus;
lit_point = -1;
}
if (lit_point != previous_lit_point)
draw (width, height, lit_point);
grab_point = -1; grab_point = -1;
retval = true; retval = true;
notifyListener (); notifyListener ();
} }
break; 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 (grab_point == -1)
new_type = CSArrow;
break;
case Gdk::MOTION_NOTIFY: case Gdk::MOTION_NOTIFY:
mevent = (GdkEventMotion *) event; mevent = (GdkEventMotion *) event;
if (curve.type == Linear || curve.type == Spline) { if (curve.type == Linear || curve.type == Spline) {
if (grab_point == -1) { if (grab_point == -1) {
int previous_lit_point = lit_point;
/* if no point is grabbed... */ /* if no point is grabbed... */
if (distance <= MIN_DISTANCE) if (distance <= MIN_DISTANCE) {
new_type = Gdk::FLEUR; new_type = CSMove;
else lit_point = closest_point;
new_type = Gdk::PLUS; }
else {
new_type = CSPlus;
lit_point = -1;
}
if ((new_type != cursor_type) || (lit_point != previous_lit_point))
draw (width, height, lit_point);
} }
else { else {
/* drag the grabbed point */ int new_cursor_x, new_cursor_y;
new_type = Gdk::FLEUR; double factor = 0.5;
int leftbound = -MIN_DISTANCE;
if (grab_point > 0)
leftbound = (int)((width-1)*curve.x[grab_point-1]+0.5);
int rightbound = width + RADIUS * 2 + MIN_DISTANCE; // get cursor position
if (grab_point + 1 < num) Gdk::ModifierType mod_type;
rightbound = (int)((width-1)*curve.x[grab_point+1]+0.5); rt_display->get_pointer(new_cursor_x, new_cursor_y, mod_type);
if (tx <= leftbound || tx >= rightbound || ty > height + RADIUS * 2 + MIN_DISTANCE || ty < -MIN_DISTANCE) // set the dragging factor
curve.x[grab_point] = -1.0; int control_key = gm & GDK_CONTROL_MASK;
else { int shift_key = gm & GDK_SHIFT_MASK;
curve.x[grab_point] = (double) x / (width-1);
curve.y[grab_point] = (double) (height-y) / (height-1); // what is the speed factor
if (control_key && shift_key) factor = 0.005;
else if (shift_key) factor = 0.02;
else if (control_key) factor = 0.1;
// calculate the delta in [0.0 ; 1.0] range
double delta_x = (double)(new_cursor_x - cursor_x) * factor / (double)(width-1);
double delta_y = (double)(cursor_y - new_cursor_y) * factor / (double)(height-1);
// modification of the unclamped grabed point
ugp_x += delta_x;
ugp_y += delta_y;
// first and last point cannot be deleted anymore (there's no point to do it)
// for intermediate points, we look if the point must be deleted
if (grab_point > 0 && grab_point < num-1) {
double leftbound = curve.x[grab_point-1];
double rightbound = curve.x[grab_point+1];
double bottombound = (double)(-MIN_DISTANCE) * factor / (double)(height-1);
double topbound = (double)1.0 + (double)(MIN_DISTANCE) * factor / (double)(height-1);
if (ugp_x <= leftbound || ugp_x >= rightbound || ugp_y > topbound || ugp_y < bottombound) {
curve.x[grab_point] = -1.0;
}
}
// first and last points are clamped to the [0.0 ; 1.0] range
if (curve.x[grab_point] != -1.0) {
double new_curve_x = curve.x[grab_point] + delta_x;
double new_curve_y = curve.y[grab_point] + delta_y;
curve.x[grab_point] = CLAMP(new_curve_x,0.0,1.0);
curve.y[grab_point] = CLAMP(new_curve_y,0.0,1.0);
} }
interpolate (width, height); interpolate (width, height);
draw (width, height);
// move the cursor back (to avoid being limited by the screen)
rt_display->warp_pointer(rt_screen, cursor_x, cursor_y);
draw (width, height, lit_point);
notifyListener (); notifyListener ();
} }
} }
if (new_type != cursor_type) {
cursor_type = new_type;
Gdk::Cursor* cursor = new Gdk::Cursor (get_display(), cursor_type);
get_window ()->set_cursor (*cursor);
delete cursor;
}
retval = true; retval = true;
break; break;
default: default:
break; break;
} }
if (new_type != cursor_type) {
cursor_type = new_type;
cursorManager.setCursor(cursor_type);
}
return retval; return retval;
} }

View File

@@ -22,6 +22,11 @@
#include <gtkmm.h> #include <gtkmm.h>
#include <vector> #include <vector>
#include <curvelistener.h> #include <curvelistener.h>
#include <cursormanager.h>
#define RADIUS 3 /* radius of the control points. Assuming that the center of the spot is in the center of the pixel, the real RADIUS will be this value +0.5 */
#define MIN_DISTANCE 8 /* min distance between control points */
#define GRAPH_SIZE 200 /* size of the curve editor graphic */
enum CurveType {Linear, Spline, Parametric}; enum CurveType {Linear, Spline, Parametric};
@@ -46,10 +51,11 @@ class MyCurve : public Gtk::DrawingArea {
protected: protected:
CurveListener* listener; CurveListener* listener;
CurveDescr curve; CurveDescr curve;
Gdk::CursorType cursor_type; CursorShape cursor_type;
Glib::RefPtr<Gdk::Pixmap> pixmap; Glib::RefPtr<Gdk::Pixmap> pixmap;
int height; int height;
int grab_point; int grab_point;
int lit_point;
int last; int last;
std::vector<Gdk::Point> point; std::vector<Gdk::Point> point;
std::vector<Gdk::Point> upoint; std::vector<Gdk::Point> upoint;
@@ -58,8 +64,10 @@ class MyCurve : public Gtk::DrawingArea {
unsigned int bghist[256]; unsigned int bghist[256];
bool bghistvalid; bool bghistvalid;
MyCurveIdleHelper* mcih; MyCurveIdleHelper* mcih;
int cursor_x, cursor_y;
double ugp_x, ugp_y; // unclamped grabed point coordinates
void draw (int width, int height); void draw (int width, int height, int handle);
void interpolate (int width, int height); void interpolate (int width, int height);
std::vector<double> get_vector (int veclen); std::vector<double> get_vector (int veclen);