/* Copyright (C) 2001 Stefan Westerfeld stefan@space.twc.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kgraph.h" #include "kgraph.moc" #include "kgraphline_impl.h" #include "tqpainter.h" #include #include using namespace Arts; using namespace std; KGraph::KGraph( TQWidget * parent, const char * name ) : TQWidget( parent, name ) { setBackgroundColor(white); selectedIndex = -1; minx = miny = 0.0; maxx = maxy = 1.0; } KGraph::~KGraph() { } void KGraph::addLine(Arts::KGraphLine_impl *line) { lines.push_back(line); } void KGraph::redrawLine(Arts::KGraphLine_impl * /*line*/) { repaint(); } void KGraph::removeLine(Arts::KGraphLine_impl *line) { if(line == selectedLine) { selectedLine = 0; selectedIndex = -1; } lines.remove(line); } inline TQPoint KGraph::g2qPoint(const GraphPoint &gp) { return TQPoint(int(((gp.x - minx)/(maxx-minx)) * (width()-1)), int((1.0 - (gp.y - miny)/(maxy-miny)) * (height()-1))); } inline GraphPoint KGraph::q2gPoint(const TQPoint &qp) { return GraphPoint((float(qp.x())/float(width()-1)) * (maxx-minx) + minx, (1.0 - (float(qp.y())/float(height()-1))) * (maxy-miny) + miny); } void KGraph::paintEvent( TQPaintEvent *e ) { TQPainter painter(this); painter.setClipRect(e->rect()); std::list::iterator li; for(li = lines.begin(); li != lines.end(); li++) { KGraphLine_impl *gline = *li; vector::iterator pi; TQPoint lastp; bool first = true; painter.setPen(gline->_color.c_str()); for(pi = gline->_points.begin(); pi != gline->_points.end(); pi++) { TQPoint p = g2qPoint(*pi); if(!first) painter.drawLine(lastp,p); if(gline->_editable) painter.drawEllipse(p.x()-3,p.y()-3,7,7); lastp = p; first = false; } } } void KGraph::mousePressEvent(TQMouseEvent *e) { if(e->button() == Qt::LeftButton || e->button() == Qt::RightButton) { std::list::iterator li; for(li = lines.begin(); li != lines.end(); li++) { KGraphLine_impl *gline = *li; vector::iterator pi; int index = 0; for(pi = gline->_points.begin(); pi != gline->_points.end(); pi++, index++) { TQPoint p = g2qPoint(*pi); int dx = e->x() - p.x(); int dy = e->y() - p.y(); if(::sqrt(double(dx*dx + dy*dy)) < 5.0) { selectedIndex = index; selectedLine = gline; selectedPoint = *pi; } } } } if(selectedIndex >= 0) { // erase point if(e->button() == Qt::RightButton) { if(selectedIndex != 0 && selectedIndex != (( int )( selectedLine->_points.size() )-1)) { vector points; for(int i=0;i<( int )selectedLine->_points.size();i++) { if(selectedIndex != i) points.push_back(selectedLine->_points[i]); } selectedLine->points(points); } selectedLine = 0; selectedIndex = -1; } } else if(e->button() == Qt::LeftButton) { // try to insert a point std::list::iterator li; for(li = lines.begin(); li != lines.end(); li++) { KGraphLine_impl *gline = *li; TQPoint lastp; bool first = true; vector::iterator pi; int index = 0; for(pi = gline->_points.begin(); pi != gline->_points.end(); pi++, index++) { TQPoint p = g2qPoint(*pi); if(!first && (e->x() > lastp.x()+2) && (e->x() < p.x()-2)) { float pos = float(e->x()-lastp.x())/float(p.x()-lastp.x()); int y = (int)((1.0-pos) * lastp.y() + pos * p.y()); if(abs(y-e->y()) < 5) { GraphPoint gp = q2gPoint(TQPoint(e->x(),y)); vector newPoints; for(int i=0;i<( int )gline->_points.size();i++) { if(index == i) newPoints.push_back(gp); newPoints.push_back(gline->_points[i]); } gline->points(newPoints); selectedLine = gline; selectedIndex = index; selectedPoint = gp; return; } } lastp = p; first = false; } } } } void KGraph::mouseMoveEvent(TQMouseEvent *e) { TQPoint pos = e->pos(); if(pos.x() < 0) pos.setX(0); if(pos.y() < 0) pos.setY(0); if(pos.x() >= width()) pos.setX(width()-1); if(pos.y() >= height()) pos.setY(height()-1); if(selectedIndex >= 0) { vector points(selectedLine->_points); if((( int )points.size() <= selectedIndex) || (fabs(selectedPoint.x-points[selectedIndex].x) > 0.000001) || (fabs(selectedPoint.y-points[selectedIndex].y) > 0.000001)) { selectedLine = 0; selectedIndex = -1; return; // line was modified from somewhere else, meanwhile } // I am not sure whether we always want to constrain it that way GraphPoint gp = q2gPoint(pos); selectedPoint.y = gp.y; if(selectedIndex != 0 && selectedIndex != (( int )( points.size() )-1)) { float pixelsize = (maxx-minx)/float(width()-1); if(selectedIndex > 0 && points[selectedIndex-1].x > gp.x) { selectedPoint.x = points[selectedIndex-1].x+pixelsize; } else if(selectedIndex < (( int )( points.size() )-1) && points[selectedIndex+1].x < gp.x) { selectedPoint.x = points[selectedIndex+1].x-pixelsize; } else { selectedPoint.x = gp.x; } } points[selectedIndex] = selectedPoint; selectedLine->points(points); } } void KGraph::mouseReleaseEvent(TQMouseEvent *) { selectedIndex = -1; selectedLine = 0; } // vim: sw=4 ts=4