|
|
/*
|
|
|
* KmPlot - a math. function plotter for the KDE-Desktop
|
|
|
*
|
|
|
* Copyright (C) 1998, 1999 Klaus-Dieter Möller
|
|
|
* 2000, 2002 kd.moeller@t-online.de
|
|
|
*
|
|
|
* This file is part of the KDE Project.
|
|
|
* KmPlot is part of the KDE-EDU Project.
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
* (at your option) any later version.
|
|
|
*
|
|
|
* This program 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 General Public License for more details.
|
|
|
*
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
*
|
|
|
*/
|
|
|
|
|
|
// TQt includes
|
|
|
#include <tqbitmap.h>
|
|
|
#include <tqcursor.h>
|
|
|
#include <tqdatastream.h>
|
|
|
#include <tqpicture.h>
|
|
|
#include <tqslider.h>
|
|
|
#include <tqtooltip.h>
|
|
|
#include <tqwhatsthis.h>
|
|
|
|
|
|
// KDE includes
|
|
|
#include <tdeaction.h>
|
|
|
#include <tdeapplication.h>
|
|
|
#include <tdeglobal.h>
|
|
|
#include <kiconloader.h>
|
|
|
#include <tdelocale.h>
|
|
|
#include <tdemessagebox.h>
|
|
|
#include <tdepopupmenu.h>
|
|
|
#include <kprogress.h>
|
|
|
|
|
|
// local includes
|
|
|
#include "editfunction.h"
|
|
|
#include "keditparametric.h"
|
|
|
#include "kminmax.h"
|
|
|
#include "settings.h"
|
|
|
#include "ksliderwindow.h"
|
|
|
#include "View.h"
|
|
|
#include "View.moc"
|
|
|
|
|
|
//minimum and maximum x range. Should always be accessible.
|
|
|
double View::xmin = 0;
|
|
|
double View::xmax = 0;
|
|
|
|
|
|
|
|
|
View::View(bool const r, bool &mo, TDEPopupMenu *p, TQWidget* parent, const char* name ) : DCOPObject("View"), TQWidget( parent, name , WStaticContents ), buffer( width(), height() ), m_popupmenu(p), m_modified(mo), m_readonly(r), m_dcop_client(TDEApplication::kApplication()->dcopClient())
|
|
|
{
|
|
|
csmode = csparam = -1;
|
|
|
cstype = 0;
|
|
|
areaDraw = false;
|
|
|
areaUfkt = 0;
|
|
|
areaPMode = 0;
|
|
|
areaMin = areaMax = 0.0;
|
|
|
w = h = 0;
|
|
|
s = 0.0;
|
|
|
fcx = 0;
|
|
|
fcy = 0;
|
|
|
csxpos = 0.0;
|
|
|
csypos = 0.0;
|
|
|
rootflg = false;
|
|
|
tlgx = tlgy = drskalx = drskaly = 0.0;;
|
|
|
stepWidth = 0.0;
|
|
|
ymin = 0.0;;
|
|
|
ymax = 0.0;;
|
|
|
m_printHeaderTable = false;
|
|
|
stop_calculating = false;
|
|
|
m_minmax = 0;
|
|
|
isDrawing = false;
|
|
|
m_popupmenushown = 0;
|
|
|
|
|
|
m_parser = new XParser(mo);
|
|
|
init();
|
|
|
csflg=0;
|
|
|
csmode=-1;
|
|
|
backgroundcolor = Settings::backgroundcolor();
|
|
|
invertColor(backgroundcolor,inverted_backgroundcolor);
|
|
|
setBackgroundColor(backgroundcolor);
|
|
|
setMouseTracking(true);
|
|
|
rootflg = false;
|
|
|
for( int number = 0; number < SLIDER_COUNT; number++ )
|
|
|
sliders[ number ] = 0;
|
|
|
updateSliders();
|
|
|
m_popupmenushown = 0;
|
|
|
m_popupmenu->insertTitle( "",10);
|
|
|
zoom_mode = Z_Normal;
|
|
|
isDrawing=false;
|
|
|
areaDraw = false;
|
|
|
}
|
|
|
|
|
|
void View::setMinMaxDlg(KMinMax *minmaxdlg)
|
|
|
{
|
|
|
m_minmax = minmaxdlg;
|
|
|
}
|
|
|
|
|
|
View::~View()
|
|
|
{
|
|
|
delete m_parser;
|
|
|
}
|
|
|
|
|
|
XParser* View::parser()
|
|
|
{
|
|
|
return m_parser;
|
|
|
}
|
|
|
|
|
|
void View::draw(TQPaintDevice *dev, int form)
|
|
|
{
|
|
|
int lx, ly;
|
|
|
float sf;
|
|
|
TQRect rc;
|
|
|
TQPainter DC; // our painter
|
|
|
DC.begin(dev); // start painting widget
|
|
|
rc=DC.viewport();
|
|
|
w=rc.width();
|
|
|
h=rc.height();
|
|
|
|
|
|
setPlotRange();
|
|
|
setScaling();
|
|
|
|
|
|
if(form==0) // screen
|
|
|
{
|
|
|
ref=TQPoint(120, 100);
|
|
|
lx=(int)((xmax-xmin)*100.*drskalx/tlgx);
|
|
|
ly=(int)((ymax-ymin)*100.*drskaly/tlgy);
|
|
|
DC.scale((float)h/(float)(ly+2*ref.y()), (float)h/(float)(ly+2*ref.y()));
|
|
|
if(DC.xForm(TQPoint(lx+2*ref.x(), ly)).x() > DC.viewport().right())
|
|
|
{
|
|
|
DC.resetXForm();
|
|
|
DC.scale((float)w/(float)(lx+2*ref.x()), (float)w/(float)(lx+2*ref.x()));
|
|
|
}
|
|
|
wm=DC.worldMatrix();
|
|
|
s=DC.xForm(TQPoint(1000, 0)).x()/1000.;
|
|
|
dgr.Create( ref, lx, ly, xmin, xmax, ymin, ymax );
|
|
|
}
|
|
|
else if(form==1) // printer
|
|
|
{
|
|
|
sf=72./254.; // 72dpi
|
|
|
ref=TQPoint(100, 100);
|
|
|
lx=(int)((xmax-xmin)*100.*drskalx/tlgx);
|
|
|
ly=(int)((ymax-ymin)*100.*drskaly/tlgy);
|
|
|
DC.scale(sf, sf);
|
|
|
s=1.;
|
|
|
m_printHeaderTable = ( ( KPrinter* ) dev )->option( "app-kmplot-printtable" ) != "-1";
|
|
|
drawHeaderTable( &DC );
|
|
|
dgr.Create( ref, lx, ly, xmin, xmax, ymin, ymax );
|
|
|
if ( ( (KPrinter* )dev )->option( "app-kmplot-printbackground" ) == "-1" )
|
|
|
DC.fillRect( dgr.GetFrame(), backgroundcolor); //draw a colored background
|
|
|
//DC.end();
|
|
|
//((TQPixmap *)dev)->fill(TQColor("#FF00FF"));
|
|
|
//DC.begin(dev);
|
|
|
}
|
|
|
else if(form==2) // svg
|
|
|
{
|
|
|
ref=TQPoint(0, 0);
|
|
|
lx=(int)((xmax-xmin)*100.*drskalx/tlgx);
|
|
|
ly=(int)((ymax-ymin)*100.*drskaly/tlgy);
|
|
|
dgr.Create( ref, lx, ly, xmin, xmax, ymin, ymax );
|
|
|
DC.translate(-dgr.GetFrame().left(), -dgr.GetFrame().top());
|
|
|
s=1.;
|
|
|
}
|
|
|
else if(form==3) // bmp, png
|
|
|
{
|
|
|
sf=180./254.; // 180dpi
|
|
|
ref=TQPoint(0, 0);
|
|
|
lx=(int)((xmax-xmin)*100.*drskalx/tlgx);
|
|
|
ly=(int)((ymax-ymin)*100.*drskaly/tlgy);
|
|
|
dgr.Create( ref, lx, ly, xmin, xmax, ymin, ymax );
|
|
|
DC.end();
|
|
|
((TQPixmap *)dev)->resize((int)(dgr.GetFrame().width()*sf), (int)(dgr.GetFrame().height()*sf));
|
|
|
((TQPixmap *)dev)->fill(backgroundcolor);
|
|
|
DC.begin(dev);
|
|
|
DC.translate(-dgr.GetFrame().left()*sf, -dgr.GetFrame().top()*sf);
|
|
|
DC.scale(sf, sf);
|
|
|
s=1.;
|
|
|
}
|
|
|
|
|
|
dgr.borderThickness=(uint)(4*s);
|
|
|
dgr.axesLineWidth = (uint)( Settings::axesLineWidth()*s );
|
|
|
dgr.gridLineWidth = (uint)( Settings::gridLineWidth()*s );
|
|
|
dgr.ticWidth = (uint)( Settings::ticWidth()*s );
|
|
|
dgr.ticLength = (uint)( Settings::ticLength() );
|
|
|
dgr.axesColor = Settings::axesColor().rgb();
|
|
|
dgr.gridColor=Settings::gridColor().rgb();
|
|
|
dgr.Skal( tlgx, tlgy );
|
|
|
|
|
|
if ( form!=0 && areaDraw)
|
|
|
{
|
|
|
areaUnderGraph(areaUfkt, areaPMode, areaMin,areaMax, areaParameter, &DC);
|
|
|
areaDraw = false;
|
|
|
if (stop_calculating)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
dgr.Plot(&DC);
|
|
|
PlotArea=dgr.GetPlotArea();
|
|
|
area=DC.xForm(PlotArea);
|
|
|
hline.resize(area.width(), 1);
|
|
|
vline.resize(1, area.height());
|
|
|
stepWidth=Settings::stepWidth();
|
|
|
|
|
|
isDrawing=true;
|
|
|
setCursor(TQt::WaitCursor );
|
|
|
stop_calculating = false;
|
|
|
for(TQValueVector<Ufkt>::iterator ufkt=m_parser->ufkt.begin(); ufkt!=m_parser->ufkt.end() && !stop_calculating; ++ufkt)
|
|
|
if ( !ufkt->fname.isEmpty() )
|
|
|
plotfkt(ufkt, &DC);
|
|
|
|
|
|
isDrawing=false;
|
|
|
restoreCursor();
|
|
|
csflg=0;
|
|
|
DC.end(); // painting done
|
|
|
}
|
|
|
|
|
|
|
|
|
void View::plotfkt(Ufkt *ufkt, TQPainter *pDC)
|
|
|
{
|
|
|
char p_mode;
|
|
|
int iy, k, ke, mflg;
|
|
|
double x, y, dmin, dmax;
|
|
|
TQPoint p1, p2;
|
|
|
TQPen pen;
|
|
|
pen.setCapStyle(TQt::RoundCap);
|
|
|
iy=0;
|
|
|
y=0.0;
|
|
|
|
|
|
char const fktmode=ufkt->fstr[0].latin1();
|
|
|
if(fktmode=='y') return ;
|
|
|
|
|
|
dmin=ufkt->dmin;
|
|
|
dmax=ufkt->dmax;
|
|
|
|
|
|
if(!ufkt->usecustomxmin)
|
|
|
{
|
|
|
if(fktmode=='r')
|
|
|
dmin=0.;
|
|
|
else if ( fktmode == 'x' )
|
|
|
dmin = -M_PI;
|
|
|
else
|
|
|
dmin = xmin;
|
|
|
}
|
|
|
if(!ufkt->usecustomxmax)
|
|
|
{
|
|
|
if(fktmode=='r')
|
|
|
dmax=2*M_PI;
|
|
|
else if ( fktmode == 'x' )
|
|
|
dmax = M_PI;
|
|
|
else
|
|
|
dmax = xmax;
|
|
|
}
|
|
|
double dx;
|
|
|
if(fktmode=='r')
|
|
|
if ( Settings::useRelativeStepWidth() )
|
|
|
dx=stepWidth*0.05/(dmax-dmin);
|
|
|
else
|
|
|
dx=stepWidth;
|
|
|
else
|
|
|
if ( Settings::useRelativeStepWidth() )
|
|
|
dx=stepWidth*(dmax-dmin)/area.width();
|
|
|
else
|
|
|
dx=stepWidth;
|
|
|
|
|
|
if(fktmode=='x')
|
|
|
iy = m_parser->ixValue(ufkt->id)+1;
|
|
|
p_mode=0;
|
|
|
pen.setWidth((int)(ufkt->linewidth*s) );
|
|
|
pen.setColor(ufkt->color);
|
|
|
pDC->setPen(pen);
|
|
|
|
|
|
while(1)
|
|
|
{
|
|
|
k=0;
|
|
|
ke=ufkt->parameters.count();
|
|
|
do
|
|
|
{
|
|
|
kdDebug() << "drawing " << ufkt->id << endl;
|
|
|
if ( p_mode == 3 && stop_calculating)
|
|
|
break;
|
|
|
if( ufkt->use_slider == -1 )
|
|
|
{
|
|
|
if ( !ufkt->parameters.isEmpty() )
|
|
|
ufkt->setParameter( ufkt->parameters[k].value );
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if ( KSliderWindow * sw = sliders[ ufkt->use_slider ] )
|
|
|
ufkt->setParameter( sw->slider->value() );
|
|
|
}
|
|
|
|
|
|
mflg=2;
|
|
|
if ( p_mode == 3)
|
|
|
{
|
|
|
if ( ufkt->integral_use_precision )
|
|
|
if ( Settings::useRelativeStepWidth() )
|
|
|
dx = ufkt->integral_precision*(dmax-dmin)/area.width();
|
|
|
else
|
|
|
dx = ufkt->integral_precision;
|
|
|
startProgressBar((int)double((dmax-dmin)/dx)/2);
|
|
|
x = ufkt->oldx = ufkt->startx; //the initial x-point
|
|
|
ufkt->oldy = ufkt->starty;
|
|
|
ufkt->oldyprim = ufkt->integral_precision;
|
|
|
paintEvent(0);
|
|
|
}
|
|
|
else
|
|
|
x=dmin;
|
|
|
bool forward_direction;
|
|
|
|
|
|
if (dmin<0 && dmax<0)
|
|
|
forward_direction = false;
|
|
|
else
|
|
|
forward_direction = true;
|
|
|
|
|
|
if ( p_mode != 0 || ufkt->f_mode) // if not the function is hidden
|
|
|
while ((x>=dmin && x<=dmax) || (p_mode == 3 && x>=dmin && !forward_direction) || (p_mode == 3 && x<=dmax && forward_direction))
|
|
|
{
|
|
|
if ( p_mode == 3 && stop_calculating)
|
|
|
{
|
|
|
p_mode=1;
|
|
|
x=dmax+1;
|
|
|
continue;
|
|
|
}
|
|
|
switch(p_mode)
|
|
|
{
|
|
|
case 0:
|
|
|
y=m_parser->fkt(ufkt, x);
|
|
|
break;
|
|
|
case 1:
|
|
|
y=m_parser->a1fkt(ufkt, x);
|
|
|
break;
|
|
|
case 2:
|
|
|
y=m_parser->a2fkt(ufkt, x);
|
|
|
break;
|
|
|
case 3:
|
|
|
{
|
|
|
y = m_parser->euler_method(x, ufkt);
|
|
|
if ( int(x*100)%2==0)
|
|
|
{
|
|
|
TDEApplication::kApplication()->processEvents(); //makes the program usable when drawing a complicated integral function
|
|
|
increaseProgressBar();
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(fktmode=='r')
|
|
|
{
|
|
|
p2.setX(dgr.Transx(y*cos(x)));
|
|
|
p2.setY(dgr.Transy(y*sin(x)));
|
|
|
}
|
|
|
else if(fktmode=='x')
|
|
|
{
|
|
|
p2.setX(dgr.Transx(y));
|
|
|
p2.setY(dgr.Transy(m_parser->fkt(iy, x)));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
p2.setX(dgr.Transx(x));
|
|
|
p2.setY(dgr.Transy(y));
|
|
|
}
|
|
|
|
|
|
if ( dgr.xclipflg || dgr.yclipflg )
|
|
|
{
|
|
|
//if(mflg>=1)
|
|
|
p1=p2;
|
|
|
/*else
|
|
|
{
|
|
|
pDC->drawLine(p1, p2);
|
|
|
p1=p2;
|
|
|
mflg=1;
|
|
|
}*/
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if(mflg<=1)
|
|
|
pDC->drawLine(p1, p2);
|
|
|
p1=p2;
|
|
|
mflg=0;
|
|
|
}
|
|
|
|
|
|
if (p_mode==3)
|
|
|
{
|
|
|
if ( forward_direction)
|
|
|
{
|
|
|
x=x+dx;
|
|
|
if (x>dmax && p_mode== 3)
|
|
|
{
|
|
|
forward_direction = false;
|
|
|
x = ufkt->oldx = ufkt->startx;
|
|
|
ufkt->oldy = ufkt->starty;
|
|
|
ufkt->oldyprim = ufkt->integral_precision;
|
|
|
paintEvent(0);
|
|
|
mflg=2;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
x=x-dx; // go backwards
|
|
|
}
|
|
|
else
|
|
|
x=x+dx;
|
|
|
}
|
|
|
}
|
|
|
while(++k<ke);
|
|
|
|
|
|
if(ufkt->f1_mode==1 && p_mode< 1) //draw the 1st derivative
|
|
|
{
|
|
|
p_mode=1;
|
|
|
pen.setWidth((int)(ufkt->f1_linewidth*s) );
|
|
|
pen.setColor(ufkt->f1_color);
|
|
|
pDC->setPen(pen);
|
|
|
}
|
|
|
else if(ufkt->f2_mode==1 && p_mode< 2) //draw the 2nd derivative
|
|
|
{
|
|
|
p_mode=2;
|
|
|
pen.setWidth((int)(ufkt->f2_linewidth*s) );
|
|
|
pen.setColor(ufkt->f2_color);
|
|
|
pDC->setPen(pen);
|
|
|
}
|
|
|
else if( ufkt->integral_mode==1 && p_mode< 3) //draw the integral
|
|
|
{
|
|
|
p_mode=3;
|
|
|
pen.setWidth((int)(ufkt->integral_linewidth*s) );
|
|
|
pen.setColor(ufkt->integral_color);
|
|
|
pDC->setPen(pen);
|
|
|
}
|
|
|
else break; //otherwise stop
|
|
|
}
|
|
|
if ( stopProgressBar() )
|
|
|
if( stop_calculating)
|
|
|
KMessageBox::error(this,i18n("The drawing was cancelled by the user."));
|
|
|
}
|
|
|
|
|
|
void View::drawHeaderTable(TQPainter *pDC)
|
|
|
{
|
|
|
TQString alx, aly, atx, aty, dfx, dfy;
|
|
|
|
|
|
if( m_printHeaderTable )
|
|
|
{
|
|
|
pDC->translate(250., 150.);
|
|
|
pDC->setPen(TQPen(black, (int)(5.*s)));
|
|
|
pDC->setFont(TQFont( Settings::headerTableFont(), 30) );
|
|
|
puts( Settings::headerTableFont().latin1() );
|
|
|
TQString minStr = Settings::xMin();
|
|
|
TQString maxStr = Settings::xMax();
|
|
|
getMinMax( Settings::xRange(), minStr, maxStr);
|
|
|
alx="[ "+minStr+" | "+maxStr+" ]";
|
|
|
minStr = Settings::yMin();
|
|
|
maxStr = Settings::yMax();
|
|
|
getMinMax( Settings::yRange(), minStr, maxStr);
|
|
|
aly="[ "+minStr+" | "+maxStr+" ]";
|
|
|
setpi(&alx);
|
|
|
setpi(&aly);
|
|
|
atx="1E = "+tlgxstr;
|
|
|
setpi(&atx);
|
|
|
aty="1E = "+tlgystr;
|
|
|
setpi(&aty);
|
|
|
dfx="1E = "+drskalxstr+" cm";
|
|
|
setpi(&dfx);
|
|
|
dfy="1E = "+drskalystr+" cm";
|
|
|
setpi(&dfy);
|
|
|
|
|
|
pDC->drawRect(0, 0, 1500, 230);
|
|
|
pDC->Lineh(0, 100, 1500);
|
|
|
pDC->Linev(300, 0, 230);
|
|
|
pDC->Linev(700, 0, 230);
|
|
|
pDC->Linev(1100, 0, 230);
|
|
|
|
|
|
pDC->drawText(0, 0, 300, 100, AlignCenter, i18n("Parameters:"));
|
|
|
pDC->drawText(300, 0, 400, 100, AlignCenter, i18n("Plotting Area"));
|
|
|
pDC->drawText(700, 0, 400, 100, AlignCenter, i18n("Axes Division"));
|
|
|
pDC->drawText(1100, 0, 400, 100, AlignCenter, i18n("Printing Format"));
|
|
|
pDC->drawText(0, 100, 300, 65, AlignCenter, i18n("x-Axis:"));
|
|
|
pDC->drawText(0, 165, 300, 65, AlignCenter, i18n("y-Axis:"));
|
|
|
pDC->drawText(300, 100, 400, 65, AlignCenter, alx);
|
|
|
pDC->drawText(300, 165, 400, 65, AlignCenter, aly);
|
|
|
pDC->drawText(700, 100, 400, 65, AlignCenter, atx);
|
|
|
pDC->drawText(700, 165, 400, 65, AlignCenter, aty);
|
|
|
pDC->drawText(1100, 100, 400, 65, AlignCenter, dfx);
|
|
|
pDC->drawText(1100, 165, 400, 65, AlignCenter, dfy);
|
|
|
|
|
|
pDC->drawText(0, 300, i18n("Functions:"));
|
|
|
pDC->Lineh(0, 320, 700);
|
|
|
int ypos = 380;
|
|
|
//for(uint ix=0; ix<m_parser->countFunctions() && !stop_calculating; ++ix)
|
|
|
for(TQValueVector<Ufkt>::iterator it=m_parser->ufkt.begin(); it!=m_parser->ufkt.end() && !stop_calculating; ++it)
|
|
|
{
|
|
|
pDC->drawText(100, ypos, it->fstr);
|
|
|
ypos+=60;
|
|
|
}
|
|
|
pDC->translate(-60., ypos+100.);
|
|
|
}
|
|
|
else pDC->translate(150., 150.);
|
|
|
}
|
|
|
|
|
|
|
|
|
void View::getMinMax( int koord, TQString &mini, TQString &maxi )
|
|
|
{
|
|
|
switch(koord)
|
|
|
{
|
|
|
case 0:
|
|
|
mini="-8.0";
|
|
|
maxi="8.0";
|
|
|
break;
|
|
|
case 1:
|
|
|
mini="-5.0";
|
|
|
maxi="5.0";
|
|
|
break;
|
|
|
case 2:
|
|
|
mini="0.0";
|
|
|
maxi="16.0";
|
|
|
break;
|
|
|
case 3:
|
|
|
mini="0.0";
|
|
|
maxi="10.0";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void View::setpi(TQString *s)
|
|
|
{
|
|
|
int i;
|
|
|
TQChar c(960);
|
|
|
|
|
|
while((i=s->find('p')) != -1) s->replace(i, 2, &c, 1);
|
|
|
}
|
|
|
|
|
|
|
|
|
bool View::root(double *x0, Ufkt *it)
|
|
|
{
|
|
|
if(rootflg)
|
|
|
return false;
|
|
|
double yn;
|
|
|
double x=csxpos;
|
|
|
double y=fabs(csypos);
|
|
|
double dx=0.1;
|
|
|
while(1)
|
|
|
{
|
|
|
if((yn=fabs(m_parser->fkt(it, x-dx))) < y)
|
|
|
{
|
|
|
x-=dx;
|
|
|
y=yn;
|
|
|
}
|
|
|
else if((yn=fabs(m_parser->fkt(it, x+dx))) < y)
|
|
|
{
|
|
|
x+=dx;
|
|
|
y=yn;
|
|
|
}
|
|
|
else
|
|
|
dx/=10.;
|
|
|
printf("x=%g, dx=%g, y=%g\n", x, dx, y);
|
|
|
if(y<1e-8)
|
|
|
{
|
|
|
*x0=x;
|
|
|
return true;
|
|
|
}
|
|
|
if(fabs(dx)<1e-8)
|
|
|
return false;
|
|
|
if(x<xmin || x>xmax)
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void View::paintEvent(TQPaintEvent *)
|
|
|
{
|
|
|
TQPainter p;
|
|
|
p.begin(this);
|
|
|
bitBlt( this, 0, 0, &buffer, 0, 0, width(), height() );
|
|
|
p.end();
|
|
|
}
|
|
|
|
|
|
void View::resizeEvent(TQResizeEvent *)
|
|
|
{
|
|
|
if (isDrawing) //stop drawing integrals
|
|
|
{
|
|
|
stop_calculating = true; //stop drawing
|
|
|
return;
|
|
|
}
|
|
|
buffer.resize(size() );
|
|
|
drawPlot();
|
|
|
}
|
|
|
|
|
|
void View::drawPlot()
|
|
|
{
|
|
|
if( m_minmax->isShown() )
|
|
|
m_minmax->updateFunctions();
|
|
|
buffer.fill(backgroundcolor);
|
|
|
draw(&buffer, 0);
|
|
|
TQPainter p;
|
|
|
p.begin(this);
|
|
|
bitBlt( this, 0, 0, &buffer, 0, 0, width(), height() );
|
|
|
p.end();
|
|
|
}
|
|
|
|
|
|
void View::mouseMoveEvent(TQMouseEvent *e)
|
|
|
{
|
|
|
if ( isDrawing)
|
|
|
return;
|
|
|
if (zoom_mode==4 && e->stateAfter() != TQt::NoButton)
|
|
|
{
|
|
|
TQPainter p;
|
|
|
p.begin(this);
|
|
|
bitBlt( this, 0, 0, &buffer, 0, 0, width(), height() );
|
|
|
p.end();
|
|
|
|
|
|
TQPainter painter(this);
|
|
|
TQPen pen(TQt::white, 1, TQt::DotLine);
|
|
|
painter.setRasterOp (TQt::XorROP);
|
|
|
painter.setPen(pen);
|
|
|
painter.setBackgroundMode (TQt::OpaqueMode);
|
|
|
painter.setBackgroundColor (TQt::blue);
|
|
|
|
|
|
painter.drawRect(rectangle_point.x(), rectangle_point.y(), e->pos().x()-rectangle_point.x(), e->pos().y()-rectangle_point.y());
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
if ( zoom_mode!=0)
|
|
|
return;
|
|
|
if( m_popupmenushown>0 && !m_popupmenu->isShown() )
|
|
|
{
|
|
|
if ( m_popupmenushown==1)
|
|
|
csmode=-1;
|
|
|
m_popupmenushown = 0;
|
|
|
return;
|
|
|
}
|
|
|
if(csflg==1) // Fadenkreuz l<>chen
|
|
|
{
|
|
|
bitBlt(this, area.left(), fcy, &hline, 0, 0, area.width(), 1);
|
|
|
bitBlt(this, fcx, area.top(), &vline, 0, 0, 1, area.height());
|
|
|
csflg=0;
|
|
|
}
|
|
|
|
|
|
if(area.contains(e->pos()) || (e->button()==TQt::LeftButton && e->state()==TQt::LeftButton && csxpos>xmin && csxpos<xmax))
|
|
|
{
|
|
|
TQPoint ptd, ptl;
|
|
|
TQPainter DC;
|
|
|
bool out_of_bounds = false;
|
|
|
|
|
|
DC.begin(this);
|
|
|
DC.setWindow(0, 0, w, h);
|
|
|
DC.setWorldMatrix(wm);
|
|
|
ptl=DC.xFormDev(e->pos());
|
|
|
Ufkt *it = 0;
|
|
|
if( csmode >= 0 && csmode <= (int)m_parser->countFunctions() )
|
|
|
{
|
|
|
int const ix = m_parser->ixValue(csmode);
|
|
|
if (ix!=-1 && ((!m_parser->ufkt[ix].usecustomxmin) || (m_parser->ufkt[ix].usecustomxmin && csxpos>m_parser->ufkt[ix].dmin)) && ((!m_parser->ufkt[ix].usecustomxmax)||(m_parser->ufkt[ix].usecustomxmax && csxpos<m_parser->ufkt[ix].dmax)) )
|
|
|
{
|
|
|
it = &m_parser->ufkt[ix];
|
|
|
if( it->use_slider == -1 )
|
|
|
{
|
|
|
if( it->parameters.isEmpty() )
|
|
|
it->setParameter( it->parameters[csparam].value );
|
|
|
}
|
|
|
else
|
|
|
it->setParameter(sliders[ it->use_slider ]->slider->value() );
|
|
|
if ( cstype == 0)
|
|
|
ptl.setY(dgr.Transy(csypos=m_parser->fkt( it, csxpos=dgr.Transx(ptl.x()))));
|
|
|
else if ( cstype == 1)
|
|
|
ptl.setY(dgr.Transy(csypos=m_parser->a1fkt( it, csxpos=dgr.Transx(ptl.x()) )));
|
|
|
else if ( cstype == 2)
|
|
|
ptl.setY(dgr.Transy(csypos=m_parser->a2fkt( it, csxpos=dgr.Transx(ptl.x()))));
|
|
|
|
|
|
if ( csypos<ymin || csypos>ymax) //the ypoint is not visible
|
|
|
out_of_bounds = true;
|
|
|
else if(fabs(dgr.Transy(ptl.y())) < (xmax-xmin)/80)
|
|
|
{
|
|
|
double x0;
|
|
|
if(root(&x0, it))
|
|
|
{
|
|
|
TQString str=" ";
|
|
|
str+=i18n("root");
|
|
|
setStatusBar(str+TQString().sprintf(": x0= %+.5f", x0), 3);
|
|
|
rootflg=true;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
setStatusBar("", 3);
|
|
|
rootflg=false;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
csxpos=dgr.Transx(ptl.x());
|
|
|
csypos=dgr.Transy(ptl.y());
|
|
|
csflg = 1;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
csxpos=dgr.Transx(ptl.x());
|
|
|
csypos=dgr.Transy(ptl.y());
|
|
|
}
|
|
|
ptd=DC.xForm(ptl);
|
|
|
DC.end();
|
|
|
TQString sx, sy;
|
|
|
if (out_of_bounds)
|
|
|
{
|
|
|
sx = sy = "";
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
sx.sprintf(" x= %+.2f", (float)dgr.Transx(ptl.x()));//csxpos);
|
|
|
sy.sprintf(" y= %+.2f", csypos);
|
|
|
}
|
|
|
if(csflg==0) // Hintergrund speichern
|
|
|
{
|
|
|
bitBlt(&hline, 0, 0, this, area.left(), fcy=ptd.y(), area.width(), 1);
|
|
|
bitBlt(&vline, 0, 0, this, fcx=ptd.x(), area.top(), 1, area.height());
|
|
|
// Fadenkreuz zeichnen
|
|
|
TQPen pen;
|
|
|
if ( csmode == -1)
|
|
|
pen.setColor(inverted_backgroundcolor);
|
|
|
else
|
|
|
{
|
|
|
if ( csmode == -1)
|
|
|
pen.setColor(inverted_backgroundcolor);
|
|
|
else
|
|
|
{
|
|
|
switch (cstype)
|
|
|
{
|
|
|
case 0:
|
|
|
pen.setColor( it->color);
|
|
|
break;
|
|
|
case 1:
|
|
|
pen.setColor( it->f1_color);
|
|
|
break;
|
|
|
case 2:
|
|
|
pen.setColor( it->f2_color);
|
|
|
break;
|
|
|
default:
|
|
|
pen.setColor(inverted_backgroundcolor);
|
|
|
}
|
|
|
if ( pen.color() == backgroundcolor) // if the "Fadenkreuz" has the same color as the background, the "Fadenkreuz" will have the inverted color of background so you can see it easier
|
|
|
pen.setColor(inverted_backgroundcolor);
|
|
|
}
|
|
|
}
|
|
|
DC.begin(this);
|
|
|
DC.setPen(pen);
|
|
|
DC.Lineh(area.left(), fcy, area.right());
|
|
|
DC.Linev(fcx, area.bottom(), area.top());
|
|
|
DC.end();
|
|
|
}
|
|
|
csflg=1;
|
|
|
setCursor(TQt::blankCursor);
|
|
|
setStatusBar(sx, 1);
|
|
|
setStatusBar(sy, 2);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
setCursor(arrowCursor);
|
|
|
setStatusBar("", 1);
|
|
|
setStatusBar("", 2);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
void View::mousePressEvent(TQMouseEvent *e)
|
|
|
{
|
|
|
if ( m_popupmenushown>0)
|
|
|
return;
|
|
|
|
|
|
if (isDrawing)
|
|
|
{
|
|
|
stop_calculating = true; //stop drawing
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if ( zoom_mode==Z_Rectangular ) //rectangle zoom
|
|
|
{
|
|
|
zoom_mode=Z_Center;
|
|
|
rectangle_point = e->pos();
|
|
|
return;
|
|
|
}
|
|
|
else if ( zoom_mode==Z_ZoomIn ) //zoom in
|
|
|
{
|
|
|
TQPainter DC;
|
|
|
DC.begin(this);
|
|
|
DC.setWindow(0, 0, w, h);
|
|
|
DC.setWorldMatrix(wm);
|
|
|
double real = dgr.Transx(DC.xFormDev(e->pos()).x());
|
|
|
|
|
|
double const diffx = (xmax-xmin)*(double)Settings::zoomInStep()/100;
|
|
|
double const diffy = (ymax-ymin)*(double)Settings::zoomInStep()/100;
|
|
|
|
|
|
if ( diffx < 0.00001 || diffy < 0.00001)
|
|
|
return;
|
|
|
|
|
|
Settings::setXMin( Parser::number( real-double(diffx) ) );
|
|
|
Settings::setXMax( Parser::number( real+double(diffx) ) );
|
|
|
|
|
|
real = dgr.Transy(DC.xFormDev(e->pos()).y());
|
|
|
Settings::setYMin( Parser::number( real-double(diffy) ) );
|
|
|
Settings::setYMax( Parser::number( real+double(diffy) ) );
|
|
|
|
|
|
Settings::setXRange(4); //custom x-range
|
|
|
Settings::setYRange(4); //custom y-range
|
|
|
drawPlot(); //update all graphs
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
else if ( zoom_mode==3 ) //zoom out
|
|
|
{
|
|
|
TQPainter DC;
|
|
|
DC.begin(this);
|
|
|
DC.setWindow(0, 0, w, h);
|
|
|
DC.setWorldMatrix(wm);
|
|
|
double real = dgr.Transx(DC.xFormDev(e->pos()).x());
|
|
|
|
|
|
double const diffx = (xmax-xmin)*(((double)Settings::zoomOutStep()/100) +1);
|
|
|
double const diffy = (ymax-ymin)*(((double)Settings::zoomOutStep()/100) +1);
|
|
|
|
|
|
if ( diffx > 1000000 || diffy > 1000000)
|
|
|
return;
|
|
|
|
|
|
Settings::setXMin( Parser::number( real-double(diffx) ) );
|
|
|
Settings::setXMax( Parser::number( real+double(diffx) ) );
|
|
|
|
|
|
real = dgr.Transy(DC.xFormDev(e->pos()).y());
|
|
|
Settings::setYMin( Parser::number( real-double(diffy) ) );
|
|
|
Settings::setYMax( Parser::number( real+double(diffy) ) );
|
|
|
|
|
|
Settings::setXRange(4); //custom x-range
|
|
|
Settings::setYRange(4); //custom y-range
|
|
|
drawPlot(); //update all graphs
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
else if ( zoom_mode==5 ) //center
|
|
|
{
|
|
|
TQPainter DC;
|
|
|
DC.begin(this);
|
|
|
DC.setWindow(0, 0, w, h);
|
|
|
DC.setWorldMatrix(wm);
|
|
|
double real = dgr.Transx(DC.xFormDev(e->pos()).x());
|
|
|
|
|
|
double const diffx = (xmax-xmin)/2;
|
|
|
double const diffy = (ymax-ymin)/2;
|
|
|
|
|
|
Settings::setXMin( Parser::number( real-double(diffx) ) );
|
|
|
Settings::setXMax( Parser::number( real+double(diffx) ) );
|
|
|
|
|
|
real = dgr.Transy(DC.xFormDev(e->pos()).y());
|
|
|
Settings::setYMin( Parser::number( real-double(diffy) ) );
|
|
|
Settings::setYMax( Parser::number( real+double(diffy) ) );
|
|
|
|
|
|
Settings::setXRange(4); //custom x-range
|
|
|
Settings::setYRange(4); //custom y-range
|
|
|
drawPlot(); //update all graphs
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
double const g=tlgy*double(xmax-xmin)/(2*double(ymax-ymin));
|
|
|
if( !m_readonly && e->button()==TQt::RightButton) //clicking with the right mouse button
|
|
|
{
|
|
|
char function_type;
|
|
|
for( TQValueVector<Ufkt>::iterator it = m_parser->ufkt.begin(); it != m_parser->ufkt.end(); ++it)
|
|
|
{
|
|
|
function_type = it->fstr[0].latin1();
|
|
|
if ( function_type=='y' || function_type=='r' || it->fname.isEmpty()) continue;
|
|
|
if (!(((!it->usecustomxmin) || (it->usecustomxmin && csxpos>it->dmin)) && ((!it->usecustomxmax)||(it->usecustomxmax && csxpos<it->dmax)) ))
|
|
|
continue;
|
|
|
kdDebug() << "it:" << it->fstr << endl;
|
|
|
int k=0;
|
|
|
int const ke=it->parameters.count();
|
|
|
do
|
|
|
{
|
|
|
if( it->use_slider == -1 )
|
|
|
{
|
|
|
if ( !it->parameters.isEmpty())
|
|
|
it->setParameter(it->parameters[k].value);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if ( KSliderWindow * sw = sliders[ it->use_slider ] )
|
|
|
it->setParameter( sw->slider->value() );
|
|
|
}
|
|
|
|
|
|
if ( function_type=='x' && fabs(csxpos-m_parser->fkt(it, csxpos))< g && it->fstr.contains('t')==1) //parametric plot
|
|
|
{
|
|
|
TQValueVector<Ufkt>::iterator ufkt_y = it+1;
|
|
|
if ( fabs(csypos-m_parser->fkt(ufkt_y, csxpos)<g) && ufkt_y->fstr.contains('t')==1)
|
|
|
{
|
|
|
if ( csmode == -1)
|
|
|
{
|
|
|
csmode=it->id;
|
|
|
cstype=0;
|
|
|
csparam = k;
|
|
|
m_popupmenushown = 1;
|
|
|
}
|
|
|
else
|
|
|
m_popupmenushown = 2;
|
|
|
TQString y_name( ufkt_y->fstr );
|
|
|
m_popupmenu->setItemEnabled(m_popupmenu->idAt(m_popupmenu->count()-1),false);
|
|
|
m_popupmenu->setItemEnabled(m_popupmenu->idAt(m_popupmenu->count()-2),false);
|
|
|
m_popupmenu->setItemEnabled(m_popupmenu->idAt(m_popupmenu->count()-3),false);
|
|
|
m_popupmenu->setItemEnabled(m_popupmenu->idAt(m_popupmenu->count()-4),false);
|
|
|
m_popupmenu->changeTitle(10,ufkt_y->fstr+";"+y_name);
|
|
|
m_popupmenu->exec(TQCursor::pos());
|
|
|
m_popupmenu->setItemEnabled(m_popupmenu->idAt(m_popupmenu->count()-1),true);
|
|
|
m_popupmenu->setItemEnabled(m_popupmenu->idAt(m_popupmenu->count()-2),true);
|
|
|
m_popupmenu->setItemEnabled(m_popupmenu->idAt(m_popupmenu->count()-3),true);
|
|
|
m_popupmenu->setItemEnabled(m_popupmenu->idAt(m_popupmenu->count()-4),true);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
else if( fabs(csypos-m_parser->fkt(it, csxpos))< g && it->f_mode)
|
|
|
{
|
|
|
if ( csmode == -1)
|
|
|
{
|
|
|
csmode=it->id;
|
|
|
cstype=0;
|
|
|
csparam = k;
|
|
|
m_popupmenushown = 1;
|
|
|
}
|
|
|
else
|
|
|
m_popupmenushown = 2;
|
|
|
m_popupmenu->changeTitle(10, it->fstr);
|
|
|
m_popupmenu->exec(TQCursor::pos());
|
|
|
return;
|
|
|
}
|
|
|
else if(fabs(csypos-m_parser->a1fkt( it, csxpos))< g && it->f1_mode)
|
|
|
{
|
|
|
if ( csmode == -1)
|
|
|
{
|
|
|
csmode=it->id;
|
|
|
cstype=1;
|
|
|
csparam = k;
|
|
|
m_popupmenushown = 1;
|
|
|
}
|
|
|
else
|
|
|
m_popupmenushown = 2;
|
|
|
TQString function = it->fstr;
|
|
|
function = function.left(function.find('(')) + '\'';
|
|
|
m_popupmenu->changeTitle(10, function);
|
|
|
m_popupmenu->exec(TQCursor::pos());
|
|
|
return;
|
|
|
}
|
|
|
else if(fabs(csypos-m_parser->a2fkt(it, csxpos))< g && it->f2_mode)
|
|
|
{
|
|
|
if ( csmode == -1)
|
|
|
{
|
|
|
csmode=it->id;
|
|
|
cstype=2;
|
|
|
csparam = k;
|
|
|
m_popupmenushown = 1;
|
|
|
}
|
|
|
else
|
|
|
m_popupmenushown = 2;
|
|
|
TQString function = it->fstr;
|
|
|
function = function.left(function.find('(')) + "\'\'";
|
|
|
m_popupmenu->changeTitle(10, function);
|
|
|
m_popupmenu->exec(TQCursor::pos());
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
while(++k<ke);
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
if(e->button()!=TQt::LeftButton) return ;
|
|
|
if(csmode>=0) //disable trace mode if trace mode is enable
|
|
|
{
|
|
|
csmode=-1;
|
|
|
setStatusBar("",3);
|
|
|
setStatusBar("",4);
|
|
|
mouseMoveEvent(e);
|
|
|
return ;
|
|
|
}
|
|
|
for( TQValueVector<Ufkt>::iterator it = m_parser->ufkt.begin(); it != m_parser->ufkt.end(); ++it)
|
|
|
{
|
|
|
if (it->fname.isEmpty() )
|
|
|
continue;
|
|
|
switch(it->fstr[0].latin1())
|
|
|
{
|
|
|
case 'x': case 'y': case 'r': continue; // Not possible to catch
|
|
|
}
|
|
|
if (!(((!it->usecustomxmin) || (it->usecustomxmin && csxpos>it->dmin)) && ((!it->usecustomxmax)||(it->usecustomxmax && csxpos<it->dmax)) ))
|
|
|
continue;
|
|
|
int k=0;
|
|
|
int const ke=it->parameters.count();
|
|
|
do
|
|
|
{
|
|
|
if( it->use_slider == -1 )
|
|
|
{
|
|
|
if ( !it->parameters.isEmpty() )
|
|
|
it->setParameter( it->parameters[k].value );
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if ( KSliderWindow * sw = sliders[ it->use_slider ] )
|
|
|
it->setParameter( sw->slider->value() );
|
|
|
}
|
|
|
if(fabs(csypos-m_parser->fkt(it, csxpos))< g && it->f_mode)
|
|
|
{
|
|
|
csmode=it->id;
|
|
|
cstype=0;
|
|
|
csparam = k;
|
|
|
m_minmax->selectItem();
|
|
|
setStatusBar(it->fstr,4);
|
|
|
mouseMoveEvent(e);
|
|
|
return;
|
|
|
}
|
|
|
if(fabs(csypos-m_parser->a1fkt( it, csxpos))< g && it->f1_mode)
|
|
|
{
|
|
|
csmode=it->id;
|
|
|
cstype=1;
|
|
|
csparam = k;
|
|
|
m_minmax->selectItem();
|
|
|
TQString function = it->fstr;
|
|
|
function = function.left(function.find('(')) + '\'';
|
|
|
setStatusBar(function,4);
|
|
|
mouseMoveEvent(e);
|
|
|
return;
|
|
|
}
|
|
|
if(fabs(csypos-m_parser->a2fkt(it, csxpos))< g && it->f2_mode)
|
|
|
{
|
|
|
csmode=it->id;
|
|
|
cstype=2;
|
|
|
csparam = k;
|
|
|
m_minmax->selectItem();
|
|
|
TQString function = it->fstr;
|
|
|
function = function.left(function.find('(')) + "\'\'";
|
|
|
setStatusBar(function,4);
|
|
|
mouseMoveEvent(e);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
while(++k<ke);
|
|
|
}
|
|
|
|
|
|
csmode=-1;
|
|
|
}
|
|
|
|
|
|
|
|
|
void View::mouseReleaseEvent ( TQMouseEvent * e )
|
|
|
{
|
|
|
if ( zoom_mode == Z_Center )
|
|
|
{
|
|
|
zoom_mode = Z_Rectangular;
|
|
|
if( (e->pos().x() - rectangle_point.x() >= -2) && (e->pos().x() - rectangle_point.x() <= 2) ||
|
|
|
(e->pos().y() - rectangle_point.y() >= -2) && (e->pos().y() - rectangle_point.y() <= 2) )
|
|
|
{
|
|
|
update();
|
|
|
return;
|
|
|
}
|
|
|
TQPainter DC;
|
|
|
DC.begin(this);
|
|
|
bitBlt( this, 0, 0, &buffer, 0, 0, width(), height() );
|
|
|
DC.setWindow(0, 0, w, h);
|
|
|
DC.setWorldMatrix(wm);
|
|
|
|
|
|
TQPoint p=DC.xFormDev(e->pos());
|
|
|
double real1x = dgr.Transx(p.x() ) ;
|
|
|
double real1y = dgr.Transy(p.y() ) ;
|
|
|
p=DC.xFormDev(rectangle_point);
|
|
|
double real2x = dgr.Transx(p.x() ) ;
|
|
|
double real2y = dgr.Transy(p.y() ) ;
|
|
|
|
|
|
|
|
|
if ( real1x>xmax || real2x>xmax || real1x<xmin || real2x<xmin ||
|
|
|
real1y>ymax || real2y>ymax || real1y<ymin || real2y<ymin )
|
|
|
return; //out of bounds
|
|
|
|
|
|
//setting new x-boundaries
|
|
|
if( real1x < real2x )
|
|
|
{
|
|
|
if( real2x - real1x < 0.00001)
|
|
|
return;
|
|
|
Settings::setXMin( Parser::number( real1x ) );
|
|
|
Settings::setXMax( Parser::number( real2x ) );
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (real1x - real2x < 0.00001)
|
|
|
return;
|
|
|
Settings::setXMin( Parser::number( real2x ) );
|
|
|
Settings::setXMax( Parser::number( real1x ) );
|
|
|
}
|
|
|
//setting new y-boundaries
|
|
|
if( real1y < real2y )
|
|
|
{
|
|
|
if( real2y - real1y < 0.00001)
|
|
|
return;
|
|
|
Settings::setYMin( Parser::number( real1y ) );
|
|
|
Settings::setYMax( Parser::number( real2y ) );
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if( real1y - real2y < 0.00001)
|
|
|
return;
|
|
|
Settings::setYMin( Parser::number( real2y ) );
|
|
|
Settings::setYMax( Parser::number( real1y ) );
|
|
|
}
|
|
|
Settings::setXRange(4); //custom x-range
|
|
|
Settings::setYRange(4); //custom y-range
|
|
|
drawPlot(); //update all graphs
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void View::coordToMinMax( const int koord, const TQString &minStr, const TQString &maxStr,
|
|
|
double &min, double &max )
|
|
|
{
|
|
|
switch ( koord )
|
|
|
{
|
|
|
case 0:
|
|
|
min = -8.0;
|
|
|
max = 8.0;
|
|
|
break;
|
|
|
case 1:
|
|
|
min = -5.0;
|
|
|
max = 5.0;
|
|
|
break;
|
|
|
case 2:
|
|
|
min = 0.0;
|
|
|
max = 16.0;
|
|
|
break;
|
|
|
case 3:
|
|
|
min = 0.0;
|
|
|
max = 10.0;
|
|
|
break;
|
|
|
case 4:
|
|
|
min = m_parser->eval( minStr );
|
|
|
max = m_parser->eval( maxStr );
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void View::setPlotRange()
|
|
|
{
|
|
|
coordToMinMax( Settings::xRange(), Settings::xMin(), Settings::xMax(), xmin, xmax );
|
|
|
coordToMinMax( Settings::yRange(), Settings::yMin(), Settings::yMax(), ymin, ymax );
|
|
|
}
|
|
|
|
|
|
void View::setScaling()
|
|
|
{
|
|
|
TQString units[ 9 ] = { "10", "5", "2", "1", "0.5", "pi/2", "pi/3", "pi/4",i18n("automatic") };
|
|
|
|
|
|
if( Settings::xScaling() == 8) //automatic x-scaling
|
|
|
{
|
|
|
tlgx = double(xmax-xmin)/16;
|
|
|
tlgxstr = units[ Settings::xScaling() ];
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
tlgxstr = units[ Settings::xScaling() ];
|
|
|
tlgx = m_parser->eval( tlgxstr );
|
|
|
}
|
|
|
|
|
|
if( Settings::yScaling() == 8) //automatic y-scaling
|
|
|
{
|
|
|
tlgy = double(ymax-ymin)/16;
|
|
|
tlgystr = units[ Settings::yScaling() ];
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
tlgystr = units[ Settings::yScaling() ];
|
|
|
tlgy = m_parser->eval( tlgystr );
|
|
|
}
|
|
|
|
|
|
drskalxstr = units[ Settings::xPrinting() ];
|
|
|
drskalx = m_parser->eval( drskalxstr );
|
|
|
drskalystr = units[ Settings::yPrinting() ];
|
|
|
drskaly = m_parser->eval( drskalystr );
|
|
|
}
|
|
|
|
|
|
void View::getSettings()
|
|
|
{
|
|
|
m_parser->setAngleMode( Settings::anglemode() );
|
|
|
m_parser->linewidth0 = Settings::gridLineWidth();
|
|
|
|
|
|
backgroundcolor = Settings::backgroundcolor();
|
|
|
invertColor(backgroundcolor,inverted_backgroundcolor);
|
|
|
setBackgroundColor(backgroundcolor);
|
|
|
}
|
|
|
|
|
|
void View::init()
|
|
|
{
|
|
|
getSettings();
|
|
|
TQValueVector<Ufkt>::iterator it = m_parser->ufkt.begin();
|
|
|
it->fname="";
|
|
|
while ( m_parser->ufkt.count() > 1)
|
|
|
m_parser->Parser::delfkt( &m_parser->ufkt.last() );
|
|
|
}
|
|
|
|
|
|
|
|
|
void View::stopDrawing()
|
|
|
{
|
|
|
if (isDrawing)
|
|
|
stop_calculating = true;
|
|
|
}
|
|
|
|
|
|
void View::findMinMaxValue(Ufkt *ufkt, char p_mode, bool minimum, double &dmin, double &dmax, const TQString &str_parameter)
|
|
|
{
|
|
|
double x, y = 0;
|
|
|
double result_x = 0;
|
|
|
double result_y = 0;
|
|
|
bool start = true;
|
|
|
|
|
|
// TODO: parameter sliders
|
|
|
if ( !ufkt->parameters.isEmpty() )
|
|
|
{
|
|
|
for ( TQValueList<ParameterValueItem>::Iterator it = ufkt->parameters.begin(); it != ufkt->parameters.end(); ++it )
|
|
|
{
|
|
|
if ( (*it).expression == str_parameter)
|
|
|
{
|
|
|
ufkt->setParameter( (*it).value );
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
isDrawing=true;
|
|
|
setCursor(TQt::WaitCursor );
|
|
|
|
|
|
double dx;
|
|
|
if ( p_mode == 3)
|
|
|
{
|
|
|
stop_calculating = false;
|
|
|
if ( ufkt->integral_use_precision )
|
|
|
if ( ufkt->integral_use_precision )
|
|
|
dx = ufkt->integral_precision*(dmax-dmin)/area.width();
|
|
|
else
|
|
|
dx = ufkt->integral_precision;
|
|
|
else
|
|
|
if ( ufkt->integral_use_precision )
|
|
|
dx = stepWidth*(dmax-dmin)/area.width();
|
|
|
else
|
|
|
dx = stepWidth;
|
|
|
startProgressBar((int)double((dmax-dmin)/dx)/2);
|
|
|
x = ufkt->oldx = ufkt->startx; //the initial x-point
|
|
|
ufkt->oldy = ufkt->starty;
|
|
|
ufkt->oldyprim = ufkt->integral_precision;
|
|
|
paintEvent(0);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
dx = stepWidth*(dmax-dmin)/area.width();
|
|
|
x=dmin;
|
|
|
}
|
|
|
|
|
|
bool forward_direction;
|
|
|
if (dmin<0 && dmax<0)
|
|
|
forward_direction = false;
|
|
|
else
|
|
|
forward_direction = true;
|
|
|
while ((x>=dmin && x<=dmax) || (p_mode == 3 && x>=dmin && !forward_direction) || (p_mode == 3 && x<=dmax && forward_direction))
|
|
|
{
|
|
|
if ( p_mode == 3 && stop_calculating)
|
|
|
{
|
|
|
p_mode = 1;
|
|
|
x=dmax+1;
|
|
|
continue;
|
|
|
}
|
|
|
switch(p_mode)
|
|
|
{
|
|
|
case 0:
|
|
|
y=m_parser->fkt(ufkt, x);
|
|
|
break;
|
|
|
|
|
|
case 1:
|
|
|
{
|
|
|
y=m_parser->a1fkt( ufkt, x);
|
|
|
break;
|
|
|
}
|
|
|
case 2:
|
|
|
{
|
|
|
y=m_parser->a2fkt(ufkt, x);
|
|
|
break;
|
|
|
}
|
|
|
case 3:
|
|
|
{
|
|
|
y = m_parser->euler_method(x, ufkt);
|
|
|
if ( int(x*100)%2==0)
|
|
|
{
|
|
|
TDEApplication::kApplication()->processEvents(); //makes the program usable when drawing a complicated integral function
|
|
|
increaseProgressBar();
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if ( !isnan(x) && !isnan(y) )
|
|
|
{
|
|
|
kdDebug() << "x " << x << endl;
|
|
|
kdDebug() << "y " << y << endl;
|
|
|
if (x>=dmin && x<=dmax)
|
|
|
{
|
|
|
if ( start)
|
|
|
{
|
|
|
result_x = x;
|
|
|
result_y = y;
|
|
|
start=false;
|
|
|
}
|
|
|
else if ( minimum &&y <=result_y)
|
|
|
{
|
|
|
result_x = x;
|
|
|
result_y = y;
|
|
|
}
|
|
|
else if ( !minimum && y >=result_y)
|
|
|
{
|
|
|
result_x = x;
|
|
|
result_y = y;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (p_mode==3)
|
|
|
{
|
|
|
if ( forward_direction)
|
|
|
{
|
|
|
x=x+dx;
|
|
|
if (x>dmax && p_mode== 3)
|
|
|
{
|
|
|
forward_direction = false;
|
|
|
x = ufkt->oldx = ufkt->startx;
|
|
|
ufkt->oldy = ufkt->starty;
|
|
|
ufkt->oldyprim = ufkt->integral_precision;
|
|
|
paintEvent(0);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
x=x-dx; // go backwards
|
|
|
}
|
|
|
else
|
|
|
x=x+dx;
|
|
|
}
|
|
|
stopProgressBar();
|
|
|
isDrawing=false;
|
|
|
restoreCursor();
|
|
|
|
|
|
dmin = int(result_x*1000)/double(1000);
|
|
|
dmax = int(result_y*1000)/double(1000);
|
|
|
|
|
|
switch (p_mode)
|
|
|
{
|
|
|
case 0:
|
|
|
dmax=m_parser->fkt(ufkt, dmin);
|
|
|
break;
|
|
|
case 1:
|
|
|
dmax=m_parser->a1fkt(ufkt, dmin);
|
|
|
break;
|
|
|
case 2:
|
|
|
dmax=m_parser->a2fkt(ufkt, dmin);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void View::getYValue(Ufkt *ufkt, char p_mode, double x, double &y, const TQString &str_parameter)
|
|
|
{
|
|
|
// TODO: parameter sliders
|
|
|
if ( !ufkt->parameters.isEmpty() )
|
|
|
{
|
|
|
for ( TQValueList<ParameterValueItem>::Iterator it = ufkt->parameters.begin(); it != ufkt->parameters.end(); ++it )
|
|
|
{
|
|
|
if ( (*it).expression == str_parameter)
|
|
|
{
|
|
|
ufkt->setParameter((*it).value);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
switch (p_mode)
|
|
|
{
|
|
|
case 0:
|
|
|
y= m_parser->fkt(ufkt, x);
|
|
|
break;
|
|
|
case 1:
|
|
|
y=m_parser->a1fkt( ufkt, x);
|
|
|
break;
|
|
|
case 2:
|
|
|
y=m_parser->a2fkt( ufkt, x);
|
|
|
break;
|
|
|
case 3:
|
|
|
double dmin = ufkt->dmin;
|
|
|
double dmax = ufkt->dmax;
|
|
|
const double target = x; //this is the x-value the user had chosen
|
|
|
bool forward_direction;
|
|
|
if ( target>=0)
|
|
|
forward_direction = true;
|
|
|
else
|
|
|
forward_direction = false;
|
|
|
|
|
|
if(dmin==dmax) //no special plot range is specified. Use the screen border instead.
|
|
|
{
|
|
|
dmin=xmin;
|
|
|
dmax=xmax;
|
|
|
}
|
|
|
|
|
|
double dx;
|
|
|
if ( ufkt->integral_use_precision )
|
|
|
dx = ufkt->integral_precision*(dmax-dmin)/area.width();
|
|
|
else
|
|
|
dx=stepWidth*(dmax-dmin)/area.width();
|
|
|
|
|
|
stop_calculating = false;
|
|
|
isDrawing=true;
|
|
|
setCursor(TQt::WaitCursor );
|
|
|
bool target_found=false;
|
|
|
startProgressBar((int) double((dmax-dmin)/dx)/2);
|
|
|
x = ufkt->oldx = ufkt->startx; //the initial x-point
|
|
|
ufkt->oldy = ufkt->starty;
|
|
|
ufkt->oldyprim = ufkt->integral_precision;
|
|
|
paintEvent(0);
|
|
|
while (x>=dmin && !stop_calculating && !target_found)
|
|
|
{
|
|
|
y = m_parser->euler_method( x, ufkt );
|
|
|
if ( int(x*100)%2==0)
|
|
|
{
|
|
|
TDEApplication::kApplication()->processEvents(); //makes the program usable when drawing a complicated integral function
|
|
|
increaseProgressBar();
|
|
|
}
|
|
|
|
|
|
if ( (x+dx > target && forward_direction) || ( x+dx < target && !forward_direction)) //right x-value is found
|
|
|
target_found = true;
|
|
|
|
|
|
|
|
|
|
|
|
if (forward_direction)
|
|
|
{
|
|
|
x=x+dx;
|
|
|
if (x>dmax)
|
|
|
{
|
|
|
forward_direction = false;
|
|
|
x = ufkt->oldx = ufkt->startx;
|
|
|
ufkt->oldy = ufkt->starty;
|
|
|
ufkt->oldyprim = ufkt->integral_precision;
|
|
|
paintEvent(0);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
x=x-dx; // go backwards
|
|
|
}
|
|
|
stopProgressBar();
|
|
|
isDrawing=false;
|
|
|
restoreCursor();
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void View::keyPressEvent( TQKeyEvent * e)
|
|
|
{
|
|
|
if ( zoom_mode != Z_Normal && e->key() == TQt::Key_Escape )
|
|
|
{
|
|
|
resetZoom();
|
|
|
return;
|
|
|
}
|
|
|
if ( zoom_mode == Z_Center) //drawing a rectangle
|
|
|
{
|
|
|
zoom_mode = Z_Rectangular;
|
|
|
update();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (isDrawing)
|
|
|
{
|
|
|
stop_calculating=true;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (csmode==-1 ) return;
|
|
|
|
|
|
TQMouseEvent *event;
|
|
|
if (e->key() == TQt::Key_Left )
|
|
|
event = new TQMouseEvent(TQEvent::MouseMove,TQPoint(fcx-1,fcy-1),TQt::LeftButton,TQt::LeftButton);
|
|
|
else if (e->key() == TQt::Key_Right )
|
|
|
event = new TQMouseEvent(TQEvent::MouseMove,TQPoint(fcx+1,fcy+1),TQt::LeftButton,TQt::LeftButton);
|
|
|
else if (e->key() == TQt::Key_Up || e->key() == TQt::Key_Down) //switch graph in trace mode
|
|
|
{
|
|
|
TQValueVector<Ufkt>::iterator it = &m_parser->ufkt[m_parser->ixValue(csmode)];
|
|
|
int const ke=it->parameters.count();
|
|
|
if (ke>0)
|
|
|
{
|
|
|
csparam++;
|
|
|
if (csparam >= ke)
|
|
|
csparam=0;
|
|
|
}
|
|
|
if (csparam==0)
|
|
|
{
|
|
|
int const old_csmode=csmode;
|
|
|
char const old_cstype = cstype;
|
|
|
bool start = true;
|
|
|
bool found = false;
|
|
|
while ( 1 )
|
|
|
{
|
|
|
if ( old_csmode==csmode && !start)
|
|
|
{
|
|
|
cstype=old_cstype;
|
|
|
break;
|
|
|
}
|
|
|
kdDebug() << "csmode: " << csmode << endl;
|
|
|
switch(it->fstr[0].latin1())
|
|
|
{
|
|
|
case 'x':
|
|
|
case 'y':
|
|
|
case 'r':
|
|
|
break;
|
|
|
default:
|
|
|
{
|
|
|
for (cstype=0;cstype<3;cstype++) //going through the function, the first and the second derivative
|
|
|
{
|
|
|
if (start)
|
|
|
{
|
|
|
if ( cstype==2)
|
|
|
cstype=0;
|
|
|
else
|
|
|
cstype=old_cstype+1;
|
|
|
start=false;
|
|
|
}
|
|
|
kdDebug() << " cstype: " << (int)cstype << endl;
|
|
|
switch (cstype)
|
|
|
{
|
|
|
case (0):
|
|
|
if (it->f_mode )
|
|
|
found=true;
|
|
|
break;
|
|
|
case (1):
|
|
|
if ( it->f1_mode )
|
|
|
found=true;
|
|
|
break;
|
|
|
case (2):
|
|
|
if ( it->f2_mode )
|
|
|
found=true;
|
|
|
break;
|
|
|
}
|
|
|
if (found)
|
|
|
break;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if (found)
|
|
|
break;
|
|
|
|
|
|
if ( ++it == m_parser->ufkt.end())
|
|
|
it = m_parser->ufkt.begin();
|
|
|
csmode = it->id;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
kdDebug() << "************************" << endl;
|
|
|
kdDebug() << "csmode: " << (int)csmode << endl;
|
|
|
kdDebug() << "cstype: " << (int)cstype << endl;
|
|
|
kdDebug() << "csparam: " << csparam << endl;
|
|
|
|
|
|
//change function in the statusbar
|
|
|
switch (cstype )
|
|
|
{
|
|
|
case 0:
|
|
|
setStatusBar(it->fstr,4);
|
|
|
break;
|
|
|
case 1:
|
|
|
{
|
|
|
TQString function = it->fstr;
|
|
|
function = function.left(function.find('(')) + '\'';
|
|
|
setStatusBar(function,4);
|
|
|
break;
|
|
|
}
|
|
|
case 2:
|
|
|
{
|
|
|
TQString function = it->fstr;
|
|
|
function = function.left(function.find('(')) + "\'\'";
|
|
|
setStatusBar(function,4);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
event = new TQMouseEvent(TQEvent::MouseMove,TQPoint(fcx,fcy),TQt::LeftButton,TQt::LeftButton);
|
|
|
}
|
|
|
else if ( e->key() == TQt::Key_Space )
|
|
|
{
|
|
|
event = new TQMouseEvent(TQEvent::MouseButtonPress,TQCursor::pos(),TQt::RightButton,TQt::RightButton);
|
|
|
mousePressEvent(event);
|
|
|
delete event;
|
|
|
return;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
event = new TQMouseEvent(TQEvent::MouseButtonPress,TQPoint(fcx,fcy),TQt::LeftButton,TQt::LeftButton);
|
|
|
mousePressEvent(event);
|
|
|
delete event;
|
|
|
return;
|
|
|
}
|
|
|
mouseMoveEvent(event);
|
|
|
delete event;
|
|
|
}
|
|
|
|
|
|
void View::areaUnderGraph( Ufkt *ufkt, char const p_mode, double &dmin, double &dmax, const TQString &str_parameter, TQPainter *DC )
|
|
|
{
|
|
|
double x, y = 0;
|
|
|
float calculated_area=0;
|
|
|
int rectheight;
|
|
|
areaMin = dmin;
|
|
|
TQPoint p;
|
|
|
TQColor color;
|
|
|
switch(p_mode)
|
|
|
{
|
|
|
case 0:
|
|
|
color = ufkt->color;
|
|
|
break;
|
|
|
case 1:
|
|
|
color = ufkt->f1_color;
|
|
|
break;
|
|
|
case 2:
|
|
|
color = ufkt->f2_color;
|
|
|
break;
|
|
|
case 3:
|
|
|
color = ufkt->integral_color;
|
|
|
break;
|
|
|
}
|
|
|
if ( DC == 0) //screen
|
|
|
{
|
|
|
int ly;
|
|
|
buffer.fill(backgroundcolor);
|
|
|
DC = new TQPainter(&buffer);
|
|
|
ly=(int)((ymax-ymin)*100.*drskaly/tlgy);
|
|
|
DC->scale((float)h/(float)(ly+2*ref.y()), (float)h/(float)(ly+2*ref.y()));
|
|
|
}
|
|
|
|
|
|
if(dmin==dmax) //no special plot range is specified. Use the screen border instead.
|
|
|
{
|
|
|
dmin=xmin;
|
|
|
dmax=xmax;
|
|
|
}
|
|
|
|
|
|
// TODO: parameter sliders
|
|
|
if ( !ufkt->parameters.isEmpty() )
|
|
|
{
|
|
|
for ( TQValueList<ParameterValueItem>::Iterator it = ufkt->parameters.begin(); it != ufkt->parameters.end(); ++it )
|
|
|
{
|
|
|
if ( (*it).expression == str_parameter)
|
|
|
{
|
|
|
ufkt->setParameter((*it).value);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
double dx;
|
|
|
if ( p_mode == 3)
|
|
|
{
|
|
|
stop_calculating = false;
|
|
|
if ( ufkt->integral_use_precision )
|
|
|
dx = ufkt->integral_precision*(dmax-dmin)/area.width();
|
|
|
else
|
|
|
dx = stepWidth*(dmax-dmin)/area.width();
|
|
|
startProgressBar((int)double((dmax-dmin)/dx)/2);
|
|
|
x = ufkt->oldx = ufkt->startx; //the initial x-point
|
|
|
ufkt->oldy = ufkt->starty;
|
|
|
ufkt->oldyprim = ufkt->integral_precision;
|
|
|
//paintEvent(0);
|
|
|
|
|
|
/*TQPainter p;
|
|
|
p.begin(this);
|
|
|
bitBlt( this, 0, 0, &buffer, 0, 0, width(), height() );
|
|
|
p.end();*/
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
dx = stepWidth*(dmax-dmin)/area.width();
|
|
|
x=dmin;
|
|
|
}
|
|
|
|
|
|
|
|
|
int const origoy = dgr.Transy(0.0);
|
|
|
int const rectwidth = dgr.Transx(dx)- dgr.Transx(0.0)+1;
|
|
|
|
|
|
setCursor(TQt::WaitCursor );
|
|
|
isDrawing=true;
|
|
|
|
|
|
bool forward_direction;
|
|
|
if (dmin<0 && dmax<0)
|
|
|
forward_direction = false;
|
|
|
else
|
|
|
forward_direction = true;
|
|
|
|
|
|
int intervals = tqRound((dmax-dmin)/dx);
|
|
|
int at = 0;
|
|
|
|
|
|
while ((at<=intervals) || (p_mode == 3 && x>=dmin && !forward_direction) || (p_mode == 3 && x<=dmax && forward_direction))
|
|
|
{
|
|
|
if ( p_mode != 3 )
|
|
|
x = (intervals-at)*dmin + at*dmax;
|
|
|
++at;
|
|
|
|
|
|
if ( p_mode == 3 && stop_calculating)
|
|
|
{
|
|
|
if (forward_direction)
|
|
|
x=dmin-1;
|
|
|
else
|
|
|
x=dmax+1;
|
|
|
break;
|
|
|
continue;
|
|
|
}
|
|
|
switch(p_mode)
|
|
|
{
|
|
|
case 0:
|
|
|
y=m_parser->fkt( ufkt, x);
|
|
|
break;
|
|
|
|
|
|
case 1:
|
|
|
y=m_parser->a1fkt( ufkt, x);
|
|
|
break;
|
|
|
case 2:
|
|
|
y=m_parser->a2fkt( ufkt, x);
|
|
|
break;
|
|
|
case 3:
|
|
|
{
|
|
|
y = m_parser->euler_method(x, ufkt);
|
|
|
if ( int(x*100)%2==0)
|
|
|
{
|
|
|
TDEApplication::kApplication()->processEvents(); //makes the program usable when drawing a complicated integral function
|
|
|
increaseProgressBar();
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
p.setX(dgr.Transx(x));
|
|
|
p.setY(dgr.Transy(y));
|
|
|
if (dmin<=x && x<=dmax)
|
|
|
{
|
|
|
if( dgr.xclipflg || dgr.yclipflg ) //out of bounds
|
|
|
{
|
|
|
if (y>-10e10 && y<10e10)
|
|
|
{
|
|
|
if ( y<0)
|
|
|
rectheight = origoy-p.y() ;
|
|
|
else
|
|
|
rectheight= -1*( p.y()-origoy);
|
|
|
calculated_area = calculated_area + ( dx*y);
|
|
|
DC->fillRect(p.x(),p.y(),rectwidth,rectheight,color);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if ( y<0)
|
|
|
rectheight = origoy-p.y();
|
|
|
else
|
|
|
rectheight = -1*( p.y()-origoy);
|
|
|
|
|
|
calculated_area = calculated_area + (dx*y);
|
|
|
/*kdDebug() << "Area: " << area << endl;
|
|
|
kdDebug() << "x:" << p.height() << endl;
|
|
|
kdDebug() << "y:" << p.y() << endl;
|
|
|
kdDebug() << "*************" << endl;*/
|
|
|
|
|
|
DC->fillRect(p.x(),p.y(),rectwidth,rectheight,color);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (p_mode==3)
|
|
|
{
|
|
|
if ( forward_direction)
|
|
|
{
|
|
|
x=x+dx;
|
|
|
if (x>dmax && p_mode== 3)
|
|
|
{
|
|
|
forward_direction = false;
|
|
|
x = ufkt->oldx = ufkt->startx;
|
|
|
ufkt->oldy = ufkt->starty;
|
|
|
ufkt->oldyprim = ufkt->integral_precision;
|
|
|
paintEvent(0);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
x=x-dx; // go backwards
|
|
|
}
|
|
|
else
|
|
|
x=x+dx;
|
|
|
}
|
|
|
if ( stopProgressBar() )
|
|
|
{
|
|
|
if( stop_calculating)
|
|
|
{
|
|
|
KMessageBox::error(this,i18n("The drawing was cancelled by the user."));
|
|
|
isDrawing=false;
|
|
|
restoreCursor();
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
isDrawing=false;
|
|
|
restoreCursor();
|
|
|
|
|
|
|
|
|
areaUfkt = ufkt;
|
|
|
areaPMode = p_mode;
|
|
|
areaMax = dmax;
|
|
|
areaParameter = str_parameter;
|
|
|
|
|
|
if ( DC->device() == &buffer) //draw the graphs to the screen
|
|
|
{
|
|
|
areaDraw=true;
|
|
|
DC->end();
|
|
|
setFocus();
|
|
|
update();
|
|
|
draw(&buffer,0);
|
|
|
}
|
|
|
|
|
|
if ( calculated_area>0)
|
|
|
dmin = int(calculated_area*1000)/double(1000);
|
|
|
else
|
|
|
dmin = int(calculated_area*1000)/double(1000)*-1; //don't answer with a negative number
|
|
|
}
|
|
|
|
|
|
bool View::isCalculationStopped()
|
|
|
{
|
|
|
if ( stop_calculating)
|
|
|
{
|
|
|
stop_calculating = false;
|
|
|
return true;
|
|
|
}
|
|
|
else
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
void View::updateSliders()
|
|
|
{
|
|
|
for( int number = 0; number < SLIDER_COUNT; number++)
|
|
|
{
|
|
|
if (sliders[ number ])
|
|
|
{
|
|
|
sliders[ number ]->hide();
|
|
|
mnuSliders[ number ]->setChecked(false); //uncheck the slider-item in the menu
|
|
|
}
|
|
|
}
|
|
|
|
|
|
for(TQValueVector<Ufkt>::iterator it=m_parser->ufkt.begin(); it!=m_parser->ufkt.end(); ++it)
|
|
|
{
|
|
|
if (it->fname.isEmpty() ) continue;
|
|
|
if( it->use_slider > -1 && (it->f_mode || it->f1_mode || it->f2_mode || it->integral_mode))
|
|
|
{
|
|
|
// create the slider if it not exists already
|
|
|
if ( sliders[ it->use_slider ] == 0 )
|
|
|
{
|
|
|
sliders[ it->use_slider ] = new KSliderWindow( this, it->use_slider);
|
|
|
connect( sliders[ it->use_slider ]->slider, TQ_SIGNAL( valueChanged( int ) ), this, TQ_SLOT( drawPlot() ) );
|
|
|
connect( sliders[ it->use_slider ], TQ_SIGNAL( windowClosed( int ) ), this , TQ_SLOT( sliderWindowClosed(int) ) );
|
|
|
mnuSliders[ it->use_slider ]->setChecked(true); //set the slider-item in the menu
|
|
|
}
|
|
|
sliders[ it->use_slider ]->show();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void View::mnuHide_clicked()
|
|
|
{
|
|
|
if ( csmode == -1 )
|
|
|
return;
|
|
|
|
|
|
Ufkt *ufkt = &m_parser->ufkt[ m_parser->ixValue(csmode)];
|
|
|
switch (cstype )
|
|
|
{
|
|
|
case 0:
|
|
|
ufkt->f_mode=0;
|
|
|
break;
|
|
|
case 1:
|
|
|
ufkt->f1_mode=0;
|
|
|
break;
|
|
|
case 2:
|
|
|
ufkt->f2_mode=0;
|
|
|
break;
|
|
|
}
|
|
|
drawPlot();
|
|
|
m_modified = true;
|
|
|
updateSliders();
|
|
|
if (csmode==-1)
|
|
|
return;
|
|
|
if ( !ufkt->f_mode && !ufkt->f1_mode && !ufkt->f2_mode) //all graphs for the function are hidden
|
|
|
{
|
|
|
csmode=-1;
|
|
|
TQMouseEvent *event = new TQMouseEvent(TQMouseEvent::KeyPress,TQCursor::pos(),TQt::LeftButton,TQt::LeftButton);
|
|
|
mousePressEvent(event); //leave trace mode
|
|
|
delete event;
|
|
|
return;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
TQKeyEvent *event = new TQKeyEvent(TQKeyEvent::KeyPress,TQt::Key_Up ,TQt::Key_Up ,0);
|
|
|
keyPressEvent(event); //change selected graph
|
|
|
delete event;
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
void View::mnuRemove_clicked()
|
|
|
{
|
|
|
if ( csmode == -1 )
|
|
|
return;
|
|
|
|
|
|
if ( KMessageBox::warningContinueCancel(this,i18n("Are you sure you want to remove this function?"), TQString(), KStdGuiItem::del()) == KMessageBox::Continue )
|
|
|
{
|
|
|
Ufkt *ufkt = &m_parser->ufkt[m_parser->ixValue(csmode)];
|
|
|
char const function_type = ufkt->fstr[0].latin1();
|
|
|
if (!m_parser->delfkt( ufkt ))
|
|
|
return;
|
|
|
|
|
|
if (csmode!=-1) // if trace mode is enabled
|
|
|
{
|
|
|
csmode=-1;
|
|
|
TQMouseEvent *event = new TQMouseEvent(TQMouseEvent::KeyPress,TQCursor::pos(),TQt::LeftButton,TQt::LeftButton);
|
|
|
mousePressEvent(event); //leave trace mode
|
|
|
delete event;
|
|
|
}
|
|
|
|
|
|
drawPlot();
|
|
|
if ( function_type != 'x' && function_type != 'y' && function_type != 'r' )
|
|
|
updateSliders();
|
|
|
m_modified = true;
|
|
|
}
|
|
|
}
|
|
|
void View::mnuEdit_clicked()
|
|
|
{
|
|
|
if ( csmode == -1 )
|
|
|
return;
|
|
|
if ( m_parser->ufkt[m_parser->ixValue(csmode)].fstr[0] == 'x') // a parametric function
|
|
|
{
|
|
|
int y_index = csmode+1; //the y-function
|
|
|
if ( y_index == (int)m_parser->countFunctions())
|
|
|
y_index=0;
|
|
|
KEditParametric* editParametric = new KEditParametric( m_parser, this );
|
|
|
editParametric->setCaption(i18n( "New Parametric Plot" ));
|
|
|
editParametric->initDialog( csmode,y_index );
|
|
|
if( editParametric->exec() == TQDialog::Accepted )
|
|
|
{
|
|
|
drawPlot();
|
|
|
m_modified = true;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
else // a plot function
|
|
|
{
|
|
|
EditFunction* editFunction = new EditFunction( m_parser, this );
|
|
|
editFunction->setCaption(i18n( "Edit Function Plot" ));
|
|
|
editFunction->initDialog( csmode );
|
|
|
if( editFunction->exec() == TQDialog::Accepted )
|
|
|
{
|
|
|
drawPlot();
|
|
|
updateSliders();
|
|
|
m_modified = true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void View::mnuCopy_clicked()
|
|
|
{
|
|
|
if ( csmode == -1 )
|
|
|
return;
|
|
|
|
|
|
if ( m_parser->sendFunction(csmode) )
|
|
|
m_modified = true;
|
|
|
}
|
|
|
|
|
|
void View::mnuMove_clicked()
|
|
|
{
|
|
|
if ( csmode == -1 )
|
|
|
return;
|
|
|
|
|
|
if ( m_parser->sendFunction(csmode) )
|
|
|
{
|
|
|
if (!m_parser->delfkt(csmode) )
|
|
|
return;
|
|
|
drawPlot();
|
|
|
m_modified = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void View::mnuNoZoom_clicked()
|
|
|
{
|
|
|
setCursor(TQt::ArrowCursor);
|
|
|
zoom_mode = Z_Normal;
|
|
|
}
|
|
|
|
|
|
void View::mnuRectangular_clicked()
|
|
|
{
|
|
|
if ( zoom_mode == Z_Rectangular )
|
|
|
resetZoom();
|
|
|
else
|
|
|
{
|
|
|
setCursor(TQt::CrossCursor);
|
|
|
zoom_mode = Z_Rectangular;
|
|
|
}
|
|
|
}
|
|
|
void View::mnuZoomIn_clicked()
|
|
|
{
|
|
|
if ( zoom_mode == Z_ZoomIn )
|
|
|
resetZoom();
|
|
|
else
|
|
|
{
|
|
|
setCursor( TQCursor( SmallIcon( "magnify", 32), 10, 10 ) );
|
|
|
zoom_mode = Z_ZoomIn;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void View::mnuZoomOut_clicked()
|
|
|
{
|
|
|
if ( zoom_mode == Z_ZoomOut )
|
|
|
resetZoom();
|
|
|
else
|
|
|
{
|
|
|
setCursor( TQCursor( SmallIcon( "lessen", 32), 10, 10 ) );
|
|
|
zoom_mode = Z_ZoomOut;
|
|
|
}
|
|
|
}
|
|
|
void View::mnuCenter_clicked()
|
|
|
{
|
|
|
if ( zoom_mode == Z_Center )
|
|
|
resetZoom();
|
|
|
else
|
|
|
{
|
|
|
setCursor(TQt::PointingHandCursor);
|
|
|
zoom_mode = Z_Center;
|
|
|
}
|
|
|
}
|
|
|
void View::mnuTrig_clicked()
|
|
|
{
|
|
|
if ( Settings::anglemode()==0 ) //radians
|
|
|
{
|
|
|
Settings::setXMin("-(47/24)pi");
|
|
|
Settings::setXMax("(47/24)pi");
|
|
|
}
|
|
|
else //degrees
|
|
|
{
|
|
|
Settings::setXMin("-352.5" );
|
|
|
Settings::setXMax("352.5" );
|
|
|
}
|
|
|
Settings::setYMin("-4");
|
|
|
Settings::setYMax("4");
|
|
|
|
|
|
Settings::setXRange(4); //custom x-range
|
|
|
Settings::setYRange(4); //custom y-range
|
|
|
drawPlot(); //update all graphs
|
|
|
}
|
|
|
void View::invertColor(TQColor &org, TQColor &inv)
|
|
|
{
|
|
|
int r = org.red()-255;
|
|
|
if ( r<0) r=r*-1;
|
|
|
int g = org.green()-255;
|
|
|
if ( g<0) g=g*-1;
|
|
|
int b = org.blue()-255;
|
|
|
if ( b<0) b=b*-1;
|
|
|
|
|
|
inv.setRgb(r,g,b);
|
|
|
}
|
|
|
void View::restoreCursor()
|
|
|
{
|
|
|
switch (zoom_mode)
|
|
|
{
|
|
|
case Z_Normal: //no zoom
|
|
|
setCursor(TQt::ArrowCursor);
|
|
|
break;
|
|
|
case Z_Rectangular: //rectangle zoom
|
|
|
setCursor(TQt::CrossCursor);
|
|
|
break;
|
|
|
case Z_ZoomIn: //zoom in
|
|
|
setCursor( TQCursor( SmallIcon( "magnify", 32), 10, 10 ) );
|
|
|
break;
|
|
|
case Z_ZoomOut: //zoom out
|
|
|
setCursor( TQCursor( SmallIcon( "lessen", 32), 10, 10 ) );
|
|
|
break;
|
|
|
case Z_Center: //center a point
|
|
|
setCursor(TQt::PointingHandCursor);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool View::event( TQEvent * e )
|
|
|
{
|
|
|
if ( e->type() == TQEvent::WindowDeactivate && isDrawing)
|
|
|
{
|
|
|
stop_calculating = true;
|
|
|
return true;
|
|
|
}
|
|
|
return TQWidget::event(e); //send the information further
|
|
|
}
|
|
|
|
|
|
void View::setStatusBar(const TQString &text, const int id)
|
|
|
{
|
|
|
if ( m_readonly) //if KmPlot is shown as a KPart with e.g Konqueror, it is only possible to change the status bar in one way: to call setStatusBarText
|
|
|
{
|
|
|
switch (id)
|
|
|
{
|
|
|
case 1:
|
|
|
m_statusbartext1 = text;
|
|
|
break;
|
|
|
case 2:
|
|
|
m_statusbartext2 = text;
|
|
|
break;
|
|
|
case 3:
|
|
|
m_statusbartext3 = text;
|
|
|
break;
|
|
|
case 4:
|
|
|
m_statusbartext4 = text;
|
|
|
break;
|
|
|
default:
|
|
|
return;
|
|
|
}
|
|
|
TQString statusbartext = m_statusbartext1;
|
|
|
if ( !m_statusbartext1.isEmpty() && !m_statusbartext2.isEmpty() )
|
|
|
statusbartext.append(" | ");
|
|
|
statusbartext.append(m_statusbartext2);
|
|
|
if ( !m_statusbartext2.isEmpty() && !m_statusbartext3.isEmpty() )
|
|
|
statusbartext.append(" | ");
|
|
|
statusbartext.append(m_statusbartext3);
|
|
|
if ( (!m_statusbartext2.isEmpty() || !m_statusbartext3.isEmpty() ) && !m_statusbartext4.isEmpty() )
|
|
|
statusbartext.append(" | ");
|
|
|
statusbartext.append(m_statusbartext4);
|
|
|
emit setStatusBarText(statusbartext);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
TQByteArray parameters;
|
|
|
TQDataStream arg( parameters, IO_WriteOnly);
|
|
|
arg << text << id;
|
|
|
m_dcop_client->send(m_dcop_client->appId(), "KmPlotShell","setStatusBarText(TQString,int)", parameters);
|
|
|
}
|
|
|
}
|
|
|
void View::startProgressBar(int steps)
|
|
|
{
|
|
|
TQByteArray data;
|
|
|
TQDataStream stream(data, IO_WriteOnly);
|
|
|
stream << steps;
|
|
|
m_dcop_client->send(m_dcop_client->appId(), "KmPlotShell","startProgressBar(int)", data);
|
|
|
}
|
|
|
bool View::stopProgressBar()
|
|
|
{
|
|
|
TQCString replyType;
|
|
|
TQByteArray replyData;
|
|
|
m_dcop_client->call(m_dcop_client->appId(), "KmPlotShell","stopProgressBar()", TQByteArray(), replyType, replyData);
|
|
|
bool result;
|
|
|
TQDataStream stream(replyData, IO_ReadOnly);
|
|
|
stream >> result;
|
|
|
return result;
|
|
|
}
|
|
|
void View::increaseProgressBar()
|
|
|
{
|
|
|
m_dcop_client->send(m_dcop_client->appId(), "KmPlotShell","increaseProgressBar()", TQByteArray());
|
|
|
}
|
|
|
|
|
|
void View::sliderWindowClosed(int num)
|
|
|
{
|
|
|
mnuSliders[num]->setChecked(false);
|
|
|
}
|