// // Copyright 2008 Johannes Hofmann // // This software may be used and distributed according to the terms // of the GNU General Public License, incorporated herein by reference. #include #include #include #include #include #include #include "CurveEditor.H" CurveEditor::CurveEditor(int my_x, int my_y, int my_w, int my_h) : Fl_Widget(my_x, my_y, my_w, my_h) { X = Y = NULL; marked_point = -1; cb = NULL; cb_data = NULL; n = 0; acc = gsl_interp_accel_alloc(); spline = NULL; } void CurveEditor::draw() { double step = 1.0 / w() / 2; fl_color(FL_BLACK); fl_rectf(x(), y(), w(), h()); fl_color(FL_GRAY); fl_line_style(FL_DASH); fl_xyline(x(), y() + h() / 2, x() + w()); fl_yxline(x() + w() / 2, y(), y() + h()); if (n < 3) return; fl_push_clip(x(), y(), w(), h()); fl_color(FL_WHITE); fl_line_style(FL_SOLID); fl_begin_line(); for (double _x = 0.0; _x <= 1.0; _x = _x + step) { double _y = gsl_spline_eval(spline, _x, acc); fl_vertex(x() + _x * w(), y() + h() - h() * _y); } fl_end_line(); for (int i = 0; i < n; i++) fl_rectf((int) rint(x() + w() * X[i] - 2), (int) rint(y() + h() - h() * Y[i] - 2), 4, 4); fl_pop_clip(); } int CurveEditor::handle(int event) { double mark_x = (double) (Fl::event_x() - x()) / w(); double mark_y = 1.0 - (double) (Fl::event_y() - y()) / h(); switch (event) { case FL_PUSH: Fl::focus(this); if (Fl::event_button() == 1) { for (int i = 0; i < n; i++) { if (mark_x >= X[i] - 0.02 && mark_x <= X[i] + 0.02) { marked_point = i; move_point(i, mark_x, mark_y); redraw(); return 1; } } marked_point = add_point(mark_x, mark_y); } return 1; case FL_DRAG: if (marked_point < 0) return 1; if (marked_point > 0 && mark_x <= X[marked_point - 1] || marked_point < n - 1 && mark_x >= X[marked_point + 1]) { remove_point(marked_point); marked_point = -1; if (cb) cb(this, cb_data); } else move_point(marked_point, mark_x, mark_y); return 1; case FL_RELEASE: if (marked_point >= 0) { if (cb) cb(this, cb_data); marked_point = -1; } return 1; case FL_FOCUS: return 1; case FL_UNFOCUS: return 0; } return 0; } int CurveEditor::add_point(double _x, double _y) { int i; if (_x < 0.0 || _x > 1.0 || _y < 0.0 || _y > 1.0) return -1; X = (double*) realloc(X, (n + 1) * sizeof(double)); Y = (double*) realloc(Y, (n + 1) * sizeof(double)); for (i = 0; i < n; i++) { if (_x == X[i]) return -1; if (_x < X[i]) { memmove(&X[i + 1], &X[i], sizeof(double) * (n - i)); memmove(&Y[i + 1], &Y[i], sizeof(double) * (n - i)); break; } } X[i] = _x; Y[i] = _y; n++; init(); return i; } void CurveEditor::init() { if (n < 3) return; if (spline) gsl_spline_free(spline); spline = gsl_spline_alloc(gsl_interp_cspline, n); gsl_spline_init(spline, X, Y, n); redraw(); } void CurveEditor::move_point(int i, double _x, double _y) { if (i >= n || (_x < 0.0 || _x > 1.0 || _y < 0.0 || _y > 1.0) || (i < n - 1 && _x >= X[i + 1]) || (i > 0 && _x <= X[i - 1])) return; X[i] = _x; Y[i] = _y; gsl_spline_init(spline, X, Y, n); redraw(); } void CurveEditor::remove_point(int i) { if (i < 0 || i >= n) return; memmove(&X[i], &X[i + 1], sizeof(double) * (n - i)); memmove(&Y[i], &Y[i + 1], sizeof(double) * (n - i)); n--; init(); } void CurveEditor::get_point(int i, double *_x, double *_y) { if (i < 0 || i >= n) return; *_x = X[i]; *_y = Y[i]; } void CurveEditor::clear() { if (X) free(X); if (Y) free(Y); X = Y = NULL; n = 0; }