Curve editor modified to better handle subpixel positionning of the points, and better handle pen devices. Modifier keys are still valid.
This commit is contained in:
596
rtgui/mycurve.cc
596
rtgui/mycurve.cc
@@ -25,13 +25,18 @@ MyCurve::MyCurve () : listener(NULL), activeParam(-1), bghistvalid(false) {
|
|||||||
|
|
||||||
cursor_type = CSArrow;
|
cursor_type = CSArrow;
|
||||||
curve.type = Spline;
|
curve.type = Spline;
|
||||||
height = 0;
|
innerWidth = get_allocation().get_width() - RADIUS * 2;
|
||||||
|
innerHeight = get_allocation().get_height() - RADIUS * 2;
|
||||||
|
prevInnerHeight = innerHeight;
|
||||||
grab_point = -1;
|
grab_point = -1;
|
||||||
lit_point = -1;
|
lit_point = -1;
|
||||||
|
source = GDK_SOURCE_MOUSE;
|
||||||
|
buttonPressed = false;
|
||||||
|
|
||||||
|
set_extension_events(Gdk::EXTENSION_EVENTS_CURSOR);
|
||||||
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);
|
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);
|
||||||
curve.y.push_back(0);
|
curve.y.push_back(0);
|
||||||
curve.x.push_back(1);
|
curve.x.push_back(1);
|
||||||
@@ -96,44 +101,42 @@ std::vector<double> MyCurve::get_vector (int veclen) {
|
|||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyCurve::interpolate (int width, int height) {
|
void MyCurve::interpolate () {
|
||||||
|
|
||||||
this->height = height;
|
prevInnerHeight = innerHeight;
|
||||||
point.resize (width);
|
point.resize (innerWidth);
|
||||||
std::vector<double> vector = get_vector (width);
|
std::vector<double> vector = get_vector (innerWidth);
|
||||||
this->height = height;
|
prevInnerHeight = innerHeight;
|
||||||
for (int i = 0; i < width; ++i)
|
for (int i = 0; i < innerWidth; ++i)
|
||||||
point[i] = Gdk::Point (RADIUS + i, RADIUS + height - (int)((height-1) * vector[i] + 0.5));
|
point[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
|
||||||
upoint.clear ();
|
upoint.clear ();
|
||||||
lpoint.clear ();
|
lpoint.clear ();
|
||||||
|
|
||||||
if (curve.type==Parametric && activeParam>0) {
|
if (curve.type==Parametric && activeParam>0) {
|
||||||
double tmp = curve.x[activeParam-1];
|
double tmp = curve.x[activeParam-1];
|
||||||
if (activeParam>=4) {
|
if (activeParam>=4) {
|
||||||
upoint.resize(width);
|
upoint.resize(innerWidth);
|
||||||
lpoint.resize(width);
|
lpoint.resize(innerWidth);
|
||||||
curve.x[activeParam-1] = 100;
|
curve.x[activeParam-1] = 100;
|
||||||
vector = get_vector (width);
|
vector = get_vector (innerWidth);
|
||||||
for (int i = 0; i < width; ++i)
|
for (int i = 0; i < innerWidth; ++i)
|
||||||
upoint[i] = Gdk::Point (RADIUS + i, RADIUS + height - (int)((height-1) * vector[i] + 0.5));
|
upoint[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
|
||||||
curve.x[activeParam-1] = -100;
|
curve.x[activeParam-1] = -100;
|
||||||
vector = get_vector (width);
|
vector = get_vector (innerWidth);
|
||||||
for (int i = 0; i < width; ++i)
|
for (int i = 0; i < innerWidth; ++i)
|
||||||
lpoint[i] = Gdk::Point (RADIUS + i, RADIUS + height - (int)((height-1) * vector[i] + 0.5));
|
lpoint[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
|
||||||
curve.x[activeParam-1] = tmp;
|
curve.x[activeParam-1] = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyCurve::draw (int width, int height, int handle) {
|
void MyCurve::draw (int handle) {
|
||||||
// width and heigth are the size of the graph
|
|
||||||
|
|
||||||
if (!pixmap)
|
if (!pixmap)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// re-calculate curve if dimensions changed
|
// re-calculate curve if dimensions changed
|
||||||
if (this->height != height || point.size() != width)
|
if (prevInnerHeight != innerHeight || point.size() != innerWidth)
|
||||||
interpolate (width, height);
|
interpolate ();
|
||||||
|
|
||||||
Gtk::StateType state = Gtk::STATE_NORMAL;
|
Gtk::StateType state = Gtk::STATE_NORMAL;
|
||||||
if (!is_sensitive())
|
if (!is_sensitive())
|
||||||
@@ -145,7 +148,7 @@ void MyCurve::draw (int width, int height, int handle) {
|
|||||||
// bounding rectangle
|
// bounding rectangle
|
||||||
Gdk::Color c = style->get_bg (state);
|
Gdk::Color c = style->get_bg (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->rectangle (0, 0, width + RADIUS*2, height + RADIUS*2);
|
cr->rectangle (0, 0, innerWidth + RADIUS*2, innerHeight + RADIUS*2);
|
||||||
cr->fill ();
|
cr->fill ();
|
||||||
|
|
||||||
// histogram in the background
|
// histogram in the background
|
||||||
@@ -157,17 +160,17 @@ void MyCurve::draw (int width, int height, int handle) {
|
|||||||
histheight = bghist[i];
|
histheight = bghist[i];
|
||||||
// draw histogram
|
// draw histogram
|
||||||
cr->set_line_width (1.0);
|
cr->set_line_width (1.0);
|
||||||
double stepSize = (width-1) / 256.0;
|
double stepSize = (innerWidth-1) / 256.0;
|
||||||
cr->move_to (RADIUS, height-1+RADIUS);
|
cr->move_to (RADIUS, innerHeight-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)(innerHeight-2) / histheight;
|
||||||
if (val>height-1)
|
if (val>innerHeight-1)
|
||||||
val = height-1;
|
val = innerHeight-1;
|
||||||
if (i>0)
|
if (i>0)
|
||||||
cr->line_to (i*stepSize+RADIUS, height-1+RADIUS-val);
|
cr->line_to (i*stepSize+RADIUS, innerHeight-1+RADIUS-val);
|
||||||
}
|
}
|
||||||
cr->line_to (width-1+RADIUS, height-1+RADIUS);
|
cr->line_to (innerWidth-1+RADIUS, innerHeight-1+RADIUS);
|
||||||
cr->fill ();
|
cr->fill ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,10 +180,10 @@ void MyCurve::draw (int width, int height, 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());
|
||||||
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, MAX(0,i * height / 4 - 1) + RADIUS);
|
cr->move_to (RADIUS, MAX(0,i * innerHeight / 4 - 1) + RADIUS);
|
||||||
cr->line_to (width + RADIUS, MAX(0,i * height / 4 - 1) + RADIUS);
|
cr->line_to (innerWidth + RADIUS, MAX(0,i * innerHeight / 4 - 1) + RADIUS);
|
||||||
cr->move_to (MAX(0,i * width / 4 - 1) + RADIUS, RADIUS);
|
cr->move_to (MAX(0,i * innerWidth / 4 - 1) + RADIUS, RADIUS);
|
||||||
cr->line_to (MAX(0,i * width / 4 - 1) + RADIUS, height + RADIUS);
|
cr->line_to (MAX(0,i * innerWidth / 4 - 1) + RADIUS, innerHeight + RADIUS);
|
||||||
}
|
}
|
||||||
cr->stroke ();
|
cr->stroke ();
|
||||||
|
|
||||||
@@ -189,8 +192,8 @@ void MyCurve::draw (int width, int height, int handle) {
|
|||||||
std::valarray<double> ds (1);
|
std::valarray<double> ds (1);
|
||||||
ds[0] = 4;
|
ds[0] = 4;
|
||||||
cr->set_dash (ds, 0);
|
cr->set_dash (ds, 0);
|
||||||
cr->move_to (RADIUS, height + RADIUS);
|
cr->move_to (RADIUS, innerHeight + RADIUS);
|
||||||
cr->line_to (width + RADIUS, RADIUS);
|
cr->line_to (innerWidth + RADIUS, RADIUS);
|
||||||
cr->stroke ();
|
cr->stroke ();
|
||||||
cr->unset_dash ();
|
cr->unset_dash ();
|
||||||
|
|
||||||
@@ -219,8 +222,8 @@ void MyCurve::draw (int width, int height, int handle) {
|
|||||||
cr->set_source_rgb (0.0, 0.0, 0.0);
|
cr->set_source_rgb (0.0, 0.0, 0.0);
|
||||||
std::vector<double> points = getPoints();
|
std::vector<double> points = getPoints();
|
||||||
for (int i = 1; i < points.size(); ) {
|
for (int i = 1; i < points.size(); ) {
|
||||||
double x = ((width-1) * points[i++] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, width);
|
double x = ((innerWidth-1) * points[i++] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth);
|
||||||
double y = height - ((height-1) * points[i++] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, height);
|
double y = innerHeight - ((innerHeight-1) * points[i++] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight);
|
||||||
if (i==3)
|
if (i==3)
|
||||||
cr->move_to (x, y);
|
cr->move_to (x, y);
|
||||||
else
|
else
|
||||||
@@ -238,278 +241,236 @@ void MyCurve::draw (int width, int height, int handle) {
|
|||||||
cr->stroke ();
|
cr->stroke ();
|
||||||
|
|
||||||
// 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);
|
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 = ((innerWidth-1) * curve.x[i] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth);
|
||||||
double y = height - ((height-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, height);
|
double y = innerHeight - ((innerHeight-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight);
|
||||||
|
|
||||||
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 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
get_window()->draw_drawable (style->get_fg_gc (state), pixmap, 0, 0, 0, 0, width + RADIUS * 2, height + RADIUS * 2);
|
get_window()->draw_drawable (style->get_fg_gc (state), pixmap, 0, 0, 0, 0, innerWidth + RADIUS * 2, innerHeight + RADIUS * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyCurve::handleEvents (GdkEvent* event) {
|
bool MyCurve::handleEvents (GdkEvent* event) {
|
||||||
|
|
||||||
CursorShape new_type = cursor_type;
|
CursorShape new_type = cursor_type;
|
||||||
int src, dst;
|
int src, dst;
|
||||||
GdkEventMotion *mevent;
|
unsigned int x, y;
|
||||||
std::vector<double>::iterator itx, ity;
|
GdkEventMotion *mevent;
|
||||||
|
std::vector<double>::iterator itx, ity;
|
||||||
|
double moveX, moveY; // translation vector of the point
|
||||||
|
|
||||||
Glib::RefPtr<Gdk::Display> rt_display = Gtk::Widget::get_display();
|
//Glib::RefPtr<Gdk::Display> rt_display = Gtk::Widget::get_display();
|
||||||
Glib::RefPtr<Gdk::Screen> rt_screen = Gtk::Widget::get_screen();
|
//Glib::RefPtr<Gdk::Screen> rt_screen = Gtk::Widget::get_screen();
|
||||||
|
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
int num = curve.x.size();
|
||||||
|
|
||||||
/* width and height are the size of the graph */
|
/* innerWidth and innerHeight are the size of the graph */
|
||||||
int width = get_allocation().get_width() - RADIUS * 2;
|
innerWidth = get_allocation().get_width() - RADIUS * 2;
|
||||||
int height = get_allocation().get_height() - RADIUS * 2;
|
innerHeight = get_allocation().get_height() - RADIUS * 2;
|
||||||
|
|
||||||
if ((width < 0) || (height < 0))
|
double minDistanceX = (double)(MIN_DISTANCE) / (double)(innerWidth-1);
|
||||||
return false;
|
double minDistanceY = (double)(MIN_DISTANCE) / (double)(innerHeight-1);
|
||||||
|
|
||||||
/* get the pointer position */
|
if ((innerWidth < 0) || (innerHeight < 0))
|
||||||
int tx, ty;
|
return false;
|
||||||
Gdk::ModifierType gm;
|
|
||||||
get_window()->get_pointer (tx, ty, gm);
|
|
||||||
int x = CLAMP ((tx - RADIUS), 0, width-1); // X position of the pointer from the origin of the graph
|
|
||||||
int y = height-1 - CLAMP ((ty - RADIUS), 0, height-1); // Y position of the pointer from the origin of the graph
|
|
||||||
|
|
||||||
unsigned int distance_x = ~0U, distance_y = ~0U;
|
switch (event->type) {
|
||||||
int num = curve.x.size();
|
case Gdk::CONFIGURE:
|
||||||
int closest_point = -1;
|
if (pixmap)
|
||||||
|
pixmap.clear ();
|
||||||
|
|
||||||
if (curve.type!=Parametric) {
|
case Gdk::EXPOSE:
|
||||||
for (int i = 0; i < num; ++i) {
|
if (!pixmap) {
|
||||||
int cx = (int)((width-1) * curve.x[i] + 0.5); //project (c->ctlpoint[i][0], min_x, c->max_x, width);
|
pixmap = Gdk::Pixmap::create (get_window(), get_allocation().get_width(), get_allocation().get_height());
|
||||||
int cy = (int)((height-1) * curve.y[i] + 0.5); //project (c->ctlpoint[i][0], min_x, c->max_x, width);
|
interpolate ();
|
||||||
unsigned int curr_dist_x = abs (x - cx);
|
}
|
||||||
unsigned int curr_dist_y = abs (y - cy);
|
draw (lit_point);
|
||||||
if (curr_dist_x < distance_x) {
|
break;
|
||||||
distance_x = curr_dist_x;
|
|
||||||
distance_y = curr_dist_y;
|
|
||||||
closest_point = i;
|
|
||||||
}
|
|
||||||
else if (curr_dist_x == distance_x && curr_dist_y < distance_y) {
|
|
||||||
// there is mode than 1 point for that X coordinate, we select the point closest to the cursor
|
|
||||||
distance_y = curr_dist_y;
|
|
||||||
closest_point = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (event->type) {
|
case Gdk::BUTTON_PRESS:
|
||||||
case Gdk::CONFIGURE:
|
if (curve.type!=Parametric) {
|
||||||
if (pixmap)
|
if (event->button.button == 1) {
|
||||||
pixmap.clear ();
|
buttonPressed = true;
|
||||||
|
add_modal_grab ();
|
||||||
|
|
||||||
case Gdk::EXPOSE:
|
//we memorize the input device that "pressed" in the editor, to avoid unwanted motion from
|
||||||
// When does this event occurs ???
|
//an eventual mouse connected
|
||||||
if (!pixmap) {
|
source = event->button.device->source;
|
||||||
pixmap = Gdk::Pixmap::create (get_window(), get_allocation().get_width(), get_allocation().get_height());
|
|
||||||
interpolate (width, height);
|
|
||||||
}
|
|
||||||
draw (width, height, lit_point);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Gdk::BUTTON_PRESS:
|
// get the pointer position
|
||||||
if (curve.type!=Parametric) {
|
getCursorPosition(event);
|
||||||
add_modal_grab ();
|
findClosestPoint();
|
||||||
|
|
||||||
// get cursor position
|
new_type = CSMove;
|
||||||
Gdk::ModifierType mod_type;
|
if (distanceX > minDistanceX) {
|
||||||
rt_display->get_pointer(cursor_x, cursor_y, mod_type);
|
/* insert a new control point */
|
||||||
|
if (num > 0) {
|
||||||
|
if (clampedX > curve.x[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++;
|
||||||
|
|
||||||
new_type = CSEmpty;
|
// the graph is refreshed only if a new point is created (snaped to a pixel)
|
||||||
if (distance_x > MIN_DISTANCE) {
|
curve.x[closest_point] = clampedX;
|
||||||
/* insert a new control point */
|
curve.y[closest_point] = clampedY;
|
||||||
if (num > 0) {
|
|
||||||
int cx = (int)((width-1)*curve.x[closest_point]+0.5);
|
|
||||||
if (x > cx)
|
|
||||||
++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 (snaped to a pixel)
|
interpolate ();
|
||||||
curve.x[closest_point] = (double) x / (width-1);
|
draw (closest_point);
|
||||||
curve.y[closest_point] = (double) y / (height-1);
|
notifyListener ();
|
||||||
interpolate (width, height);
|
}
|
||||||
draw (width, height, closest_point);
|
grab_point = closest_point;
|
||||||
}
|
|
||||||
grab_point = closest_point;
|
|
||||||
lit_point = closest_point;
|
|
||||||
ugp_x = curve.x[closest_point];
|
|
||||||
ugp_y = curve.y[closest_point];
|
|
||||||
notifyListener ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
retval = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Gdk::BUTTON_RELEASE:
|
|
||||||
if (curve.type!=Parametric) {
|
|
||||||
remove_modal_grab ();
|
|
||||||
int previous_lit_point = lit_point;
|
|
||||||
/* delete inactive points: */
|
|
||||||
itx = curve.x.begin();
|
|
||||||
ity = curve.y.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];
|
|
||||||
++dst;
|
|
||||||
++itx;
|
|
||||||
++ity;
|
|
||||||
}
|
|
||||||
if (dst < src) {
|
|
||||||
curve.x.erase (itx, curve.x.end());
|
|
||||||
curve.y.erase (ity, curve.y.end());
|
|
||||||
if (curve.x.size() <= 0) {
|
|
||||||
curve.x.push_back (0);
|
|
||||||
curve.y.push_back (0);
|
|
||||||
interpolate (width, height);
|
|
||||||
draw (width, height, lit_point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (distance_x <= MIN_DISTANCE) {
|
|
||||||
new_type = CSMove;
|
|
||||||
lit_point = closest_point;
|
lit_point = closest_point;
|
||||||
|
ugpX = curve.x[closest_point];
|
||||||
|
ugpY = curve.y[closest_point];
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
new_type = CSPlus;
|
retval = true;
|
||||||
lit_point = -1;
|
break;
|
||||||
}
|
|
||||||
if (lit_point != previous_lit_point)
|
|
||||||
draw (width, height, lit_point);
|
|
||||||
grab_point = -1;
|
|
||||||
retval = true;
|
|
||||||
notifyListener ();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Gdk::LEAVE_NOTIFY:
|
case Gdk::BUTTON_RELEASE:
|
||||||
// Pointer can LEAVE even when dragging the point, so we don't modify the cursor in this case
|
if (curve.type!=Parametric) {
|
||||||
// The cursor will have to LEAVE another time after the drag...
|
if (event->button.device->source == source) {
|
||||||
if (grab_point == -1)
|
if (event->button.button == 1) {
|
||||||
new_type = CSArrow;
|
buttonPressed = false;
|
||||||
break;
|
}
|
||||||
|
if (!buttonPressed) {
|
||||||
|
/* get the pointer position */
|
||||||
|
getCursorPosition(event);
|
||||||
|
findClosestPoint();
|
||||||
|
|
||||||
case Gdk::MOTION_NOTIFY:
|
remove_modal_grab ();
|
||||||
mevent = (GdkEventMotion *) event;
|
int previous_lit_point = lit_point;
|
||||||
|
/* delete inactive points: */
|
||||||
|
itx = curve.x.begin();
|
||||||
|
ity = curve.y.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];
|
||||||
|
++dst;
|
||||||
|
++itx;
|
||||||
|
++ity;
|
||||||
|
}
|
||||||
|
if (dst < src) {
|
||||||
|
curve.x.erase (itx, curve.x.end());
|
||||||
|
curve.y.erase (ity, curve.y.end());
|
||||||
|
if (curve.x.size() <= 0) {
|
||||||
|
curve.x.push_back (0);
|
||||||
|
curve.y.push_back (0);
|
||||||
|
interpolate ();
|
||||||
|
draw (lit_point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (distanceX <= minDistanceX) {
|
||||||
|
new_type = CSMove;
|
||||||
|
lit_point = closest_point;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new_type = CSPlus;
|
||||||
|
lit_point = -1;
|
||||||
|
}
|
||||||
|
if (lit_point != previous_lit_point)
|
||||||
|
draw (lit_point);
|
||||||
|
grab_point = -1;
|
||||||
|
retval = true;
|
||||||
|
notifyListener ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (curve.type == Linear || curve.type == Spline || curve.type == NURBS) {
|
case Gdk::LEAVE_NOTIFY:
|
||||||
if (grab_point == -1) {
|
// Pointer can LEAVE even when dragging the point, so we don't modify the cursor in this case
|
||||||
int previous_lit_point = lit_point;
|
// The cursor will have to LEAVE another time after the drag...
|
||||||
/* if no point is grabbed... */
|
if (!buttonPressed)
|
||||||
if (distance_x <= MIN_DISTANCE) {
|
if (grab_point == -1) {
|
||||||
new_type = CSMove;
|
new_type = CSArrow;
|
||||||
|
lit_point = -1;
|
||||||
|
draw (lit_point);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Gdk::MOTION_NOTIFY:
|
||||||
|
if (curve.type == Linear || curve.type == Spline || curve.type == NURBS) {
|
||||||
|
// get the pointer position
|
||||||
|
getCursorPosition(event);
|
||||||
|
|
||||||
|
if (grab_point == -1) {
|
||||||
|
// there's no point currently being moved
|
||||||
|
int previous_lit_point = lit_point;
|
||||||
|
findClosestPoint();
|
||||||
|
if (distanceX <= minDistanceX) {
|
||||||
|
new_type = CSMove;
|
||||||
lit_point = closest_point;
|
lit_point = closest_point;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
new_type = CSPlus;
|
new_type = CSPlus;
|
||||||
lit_point = -1;
|
lit_point = -1;
|
||||||
}
|
}
|
||||||
if ((new_type != cursor_type) || (lit_point != previous_lit_point))
|
if (lit_point != previous_lit_point)
|
||||||
draw (width, height, lit_point);
|
draw (lit_point);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int new_cursor_x, new_cursor_y;
|
// a point is being moved
|
||||||
double factor = 0.5;
|
|
||||||
|
|
||||||
// get cursor position
|
// bounds of the grabbed point
|
||||||
Gdk::ModifierType mod_type;
|
double leftBound = (grab_point == 0 ) ? 0. : curve.x[grab_point-1];
|
||||||
rt_display->get_pointer(new_cursor_x, new_cursor_y, mod_type);
|
double rightBound = (grab_point == num-1) ? 1. : curve.x[grab_point+1];
|
||||||
|
double const bottomBound = 0.;
|
||||||
|
double const topBound = 1.;
|
||||||
|
|
||||||
// set the dragging factor
|
double leftDeletionBound = leftBound - minDistanceX;
|
||||||
int control_key = gm & GDK_CONTROL_MASK;
|
double rightDeletionBound = rightBound + minDistanceX;
|
||||||
int shift_key = gm & GDK_SHIFT_MASK;
|
double bottomDeletionBound = bottomBound - minDistanceY;
|
||||||
|
double topDeletionBound = topBound + minDistanceY;
|
||||||
|
|
||||||
// what is the speed factor
|
// we memorize the previous position of the point, for optimization purpose
|
||||||
if (control_key && shift_key) factor = 0.005;
|
double prevPosX = curve.x[grab_point];
|
||||||
else if (shift_key) factor = 0.02;
|
double prevPosY = curve.y[grab_point];
|
||||||
else if (control_key) factor = 0.1;
|
|
||||||
|
|
||||||
// calculate the delta in [0.0 ; 1.0] range
|
// we memorize the previous position of the point, for optimization purpose
|
||||||
double delta_x = (double)(new_cursor_x - cursor_x) * factor / (double)(width-1);
|
ugpX += deltaX;
|
||||||
double delta_y = (double)(cursor_y - new_cursor_y) * factor / (double)(height-1);
|
ugpY += deltaY;
|
||||||
|
|
||||||
// bounds of the grabed point
|
// handling limitations along X axis
|
||||||
double leftbound = (grab_point == 0) ? 0. : curve.x[grab_point-1];
|
if (ugpX >= rightDeletionBound && (grab_point > 0 && grab_point < (num-1))) {
|
||||||
double rightbound = (grab_point == num-1) ? 1. : curve.x[grab_point+1];
|
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);
|
else if (ugpX <= leftDeletionBound && (grab_point > 0 && grab_point < (num-1))) {
|
||||||
|
curve.x[grab_point] = -1.;
|
||||||
// modification of the unclamped grabed point
|
}
|
||||||
bool delete_me = false;
|
else
|
||||||
// Handling limitations along X axis
|
// nextPosX is in bounds
|
||||||
if (ugp_x >= leftbound && ugp_x <= rightbound) {
|
curve.x[grab_point] = CLAMP(ugpX, leftBound, rightBound);
|
||||||
ugp_x += delta_x;
|
|
||||||
if (ugp_x > rightbound) {
|
|
||||||
if (grab_point == num-1)
|
|
||||||
curve.x[grab_point] = 1.;
|
|
||||||
else
|
|
||||||
if (num == 2)
|
|
||||||
curve.x[grab_point] = rightbound;
|
|
||||||
else
|
|
||||||
curve.x[grab_point] = -1.;
|
|
||||||
}
|
|
||||||
else if (ugp_x < leftbound) {
|
|
||||||
if (grab_point == 0)
|
|
||||||
curve.x[grab_point] = 0.;
|
|
||||||
else
|
|
||||||
if (num == 2)
|
|
||||||
curve.x[grab_point] = leftbound;
|
|
||||||
else
|
|
||||||
curve.x[grab_point] = -1.;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
curve.x[grab_point] = ugp_x;
|
|
||||||
}
|
|
||||||
else if (ugp_x > rightbound && delta_x < 0.)
|
|
||||||
curve.x[grab_point] = ugp_x = rightbound;
|
|
||||||
else if (ugp_x < leftbound && delta_x > 0.)
|
|
||||||
curve.x[grab_point] = ugp_x = leftbound;
|
|
||||||
|
|
||||||
// Handling limitations along Y axis
|
// Handling limitations along Y axis
|
||||||
if (ugp_y >= bottombound && ugp_y <= topbound) {
|
if (ugpY >= topDeletionBound && grab_point != 0 && grab_point != num-1) {
|
||||||
ugp_y += delta_y;
|
curve.x[grab_point] = -1.;
|
||||||
if (ugp_y > topbound) {
|
}
|
||||||
if (grab_point == 0 || grab_point == num-1)
|
else if (ugpY <= bottomDeletionBound && grab_point != 0 && grab_point != num-1) {
|
||||||
curve.y[grab_point] = 1.;
|
curve.x[grab_point] = -1.;
|
||||||
else
|
}
|
||||||
curve.x[grab_point] = -1.;
|
else
|
||||||
}
|
// nextPosY is in the bounds
|
||||||
else if (ugp_y < bottombound) {
|
curve.y[grab_point] = CLAMP(ugpY, 0.0, 1.0);
|
||||||
if (grab_point == 0 || grab_point == num-1)
|
|
||||||
curve.y[grab_point] = 0.;
|
|
||||||
else
|
|
||||||
curve.x[grab_point] = -1.;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
curve.y[grab_point] = CLAMP(ugp_y, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
else if (ugp_y > 1. && delta_y < 0.)
|
|
||||||
curve.y[grab_point] = ugp_y = 1.0;
|
|
||||||
else if (ugp_y < 0. && delta_y > 0.)
|
|
||||||
curve.y[grab_point] = ugp_y = 0.;
|
|
||||||
else if ((grab_point > 0 && grab_point < num-1) && (ugp_y > topbound || ugp_y < bottombound))
|
|
||||||
curve.x[grab_point] = -1.;
|
|
||||||
|
|
||||||
interpolate (width, height);
|
if (curve.x[grab_point] != prevPosX || curve.y[grab_point] != prevPosY) {
|
||||||
|
// we recalculate the curve only if we have to
|
||||||
// move the cursor back (to avoid being limited by the screen)
|
interpolate ();
|
||||||
rt_display->warp_pointer(rt_screen, cursor_x, cursor_y);
|
draw (lit_point);
|
||||||
|
notifyListener ();
|
||||||
draw (width, height, lit_point);
|
}
|
||||||
notifyListener ();
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = true;
|
retval = true;
|
||||||
@@ -525,6 +486,91 @@ bool MyCurve::handleEvents (GdkEvent* event) {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyCurve::getCursorPosition(GdkEvent* event) {
|
||||||
|
int tx, ty;
|
||||||
|
int prevCursorX, prevCursorY;
|
||||||
|
double incrementX = 1. / (double)(innerWidth-1);
|
||||||
|
double incrementY = 1. / (double)(innerHeight-1);
|
||||||
|
|
||||||
|
// getting the cursor position
|
||||||
|
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 (grab_point != -1) {
|
||||||
|
prevCursorX = cursorX;
|
||||||
|
prevCursorY = cursorY;
|
||||||
|
}
|
||||||
|
cursorX = tx - RADIUS;
|
||||||
|
cursorY = (innerHeight-1) - (ty - RADIUS);
|
||||||
|
|
||||||
|
// update deltaX/Y if the user drags a point
|
||||||
|
if (grab_point != -1) {
|
||||||
|
// 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
|
||||||
|
if (control_key && shift_key) { incrementX *= 0.01; incrementY *= 0.01; }
|
||||||
|
else if (shift_key) { incrementX *= 0.07; incrementY *= 0.07; }
|
||||||
|
else if (control_key) { incrementX *= 0.25; incrementY *= 0.25; }
|
||||||
|
|
||||||
|
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 {
|
||||||
|
double tempCursorX = cursorX * incrementX;
|
||||||
|
double tempCursorY = cursorY * incrementY;
|
||||||
|
clampedX = CLAMP (tempCursorX, 0., 1.); // X position of the pointer from the origin of the graph
|
||||||
|
clampedY = CLAMP (tempCursorY, 0., 1.); // Y position of the pointer from the origin of the graph
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyCurve::findClosestPoint() {
|
||||||
|
distanceX = 10.0; distanceY = 10.0;
|
||||||
|
closest_point = -1;
|
||||||
|
|
||||||
|
if (curve.type!=Parametric) {
|
||||||
|
for (int i = 0; i < curve.x.size(); i++) {
|
||||||
|
double dX = curve.x[i] - clampedX;
|
||||||
|
double dY = curve.y[i] - clampedY;
|
||||||
|
double currDistX = dX < 0. ? -dX : dX; //abs (dX);
|
||||||
|
double currDistY = dY < 0. ? -dY : dY; //abs (dY);
|
||||||
|
if (currDistX < distanceX) {
|
||||||
|
distanceX = currDistX;
|
||||||
|
distanceY = currDistY;
|
||||||
|
closest_point = i;
|
||||||
|
}
|
||||||
|
else if (currDistX == distanceX && currDistY < distanceY) {
|
||||||
|
// there is more than 1 point for that X coordinate, we select the closest point to the cursor
|
||||||
|
distanceY = currDistY;
|
||||||
|
closest_point = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<double> MyCurve::getPoints () {
|
std::vector<double> MyCurve::getPoints () {
|
||||||
|
|
||||||
std::vector<double> result;
|
std::vector<double> result;
|
||||||
@@ -632,8 +678,8 @@ void MyCurve::updateBackgroundHistogram (unsigned int* hist) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MyCurve::reset() {
|
void MyCurve::reset() {
|
||||||
int width = get_allocation().get_width() - RADIUS * 2;
|
innerWidth = get_allocation().get_width() - RADIUS * 2;
|
||||||
int height = get_allocation().get_height() - RADIUS * 2;
|
innerHeight = get_allocation().get_height() - RADIUS * 2;
|
||||||
|
|
||||||
switch (curve.type) {
|
switch (curve.type) {
|
||||||
case Spline :
|
case Spline :
|
||||||
@@ -646,12 +692,12 @@ void MyCurve::reset() {
|
|||||||
curve.y.push_back(1.);
|
curve.y.push_back(1.);
|
||||||
grab_point = -1;
|
grab_point = -1;
|
||||||
lit_point = -1;
|
lit_point = -1;
|
||||||
interpolate (width, height);
|
interpolate ();
|
||||||
break;
|
break;
|
||||||
case Parametric :
|
case Parametric :
|
||||||
// Nothing to do (?)
|
// Nothing to do (?)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
draw(width, height, -1);
|
draw(-1);
|
||||||
}
|
}
|
||||||
|
@@ -55,29 +55,45 @@ struct MyCurveIdleHelper {
|
|||||||
|
|
||||||
class MyCurve : public Gtk::DrawingArea {
|
class MyCurve : public Gtk::DrawingArea {
|
||||||
|
|
||||||
friend int mchistupdate (void* data);
|
friend int mchistupdate (void* data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CurveListener* listener;
|
CurveListener* listener;
|
||||||
CurveDescr curve;
|
CurveDescr curve;
|
||||||
CursorShape cursor_type;
|
CursorShape cursor_type;
|
||||||
Glib::RefPtr<Gdk::Pixmap> pixmap;
|
Glib::RefPtr<Gdk::Pixmap> pixmap;
|
||||||
int height;
|
int innerWidth; // inner width of the editor, allocated by the system
|
||||||
int grab_point;
|
int innerHeight; // inner height of the editor, allocated by the system
|
||||||
int lit_point;
|
int prevInnerHeight;// previous inner height of the editor
|
||||||
int last;
|
int grab_point; // the point that the user is moving
|
||||||
|
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 last;
|
||||||
|
Gdk::ModifierType mod_type;
|
||||||
|
int cursorX; // X coordinate in the graph of the cursor
|
||||||
|
int cursorY; // Y coordinate in the graph of the cursor
|
||||||
|
double clampedX; // clamped grabbed point X coordinates in the [0;1] range
|
||||||
|
double clampedY; // clamped grabbed point Y coordinates in the [0;1] range
|
||||||
|
double deltaX; // signed X distance of the cursor between two consecutive MOTION_NOTIFY
|
||||||
|
double deltaY; // signed Y distance of the cursor between two consecutive MOTION_NOTIFY
|
||||||
|
double distanceX; // X distance from the cursor to the closest point
|
||||||
|
double distanceY; // Y distance from the cursor to the closest point
|
||||||
|
double ugpX; // unclamped grabbed point X coordinate in the graph
|
||||||
|
double ugpY; // unclamped grabbed point Y coordinate in the graph
|
||||||
|
GdkInputSource source;
|
||||||
std::vector<Gdk::Point> point;
|
std::vector<Gdk::Point> point;
|
||||||
std::vector<Gdk::Point> upoint;
|
std::vector<Gdk::Point> upoint;
|
||||||
std::vector<Gdk::Point> lpoint;
|
std::vector<Gdk::Point> lpoint;
|
||||||
int activeParam;
|
int activeParam;
|
||||||
unsigned int bghist[256];
|
unsigned int bghist[256]; // histogram values
|
||||||
bool bghistvalid;
|
bool bghistvalid;
|
||||||
|
bool buttonPressed;
|
||||||
MyCurveIdleHelper* mcih;
|
MyCurveIdleHelper* mcih;
|
||||||
int cursor_x, cursor_y;
|
|
||||||
double ugp_x, ugp_y; // unclamped grabbed point coordinates
|
void draw (int handle);
|
||||||
|
void interpolate ();
|
||||||
void draw (int width, int height, int handle);
|
void getCursorPosition(GdkEvent* event);
|
||||||
void interpolate (int width, int height);
|
void findClosestPoint();
|
||||||
std::vector<double> get_vector (int veclen);
|
std::vector<double> get_vector (int veclen);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Reference in New Issue
Block a user