summaryrefslogtreecommitdiff
path: root/src/CurveEditor.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/CurveEditor.cxx')
-rw-r--r--src/CurveEditor.cxx185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/CurveEditor.cxx b/src/CurveEditor.cxx
new file mode 100644
index 0000000..a0f4057
--- /dev/null
+++ b/src/CurveEditor.cxx
@@ -0,0 +1,185 @@
+//
+// Copyright 2008 Johannes Hofmann <Johannes.Hofmann@gmx.de>
+//
+// This software may be used and distributed according to the terms
+// of the GNU General Public License, incorporated herein by reference.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+
+#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();
+ int i;
+
+ switch (event) {
+ case FL_PUSH:
+ Fl::focus(this);
+ if (Fl::event_button() == 1) {
+ for (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;
+ } 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;
+}