Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/paintings/arrow.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                                 arrow.cpp
00003                                -----------
00004     begin                : Sun Nov 23 2003
00005     copyright            : (C) 2003 by Michael Margraf
00006     email                : michael.margraf@alumni.tu-berlin.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00023 #include "arrow.h"
00024 #include "arrowdialog.h"
00025 #include "schematic.h"
00026 #include <cmath>
00027 
00028 #include <QPolygon>
00029 #include <QPainter>
00030 #include <QLineEdit>
00031 #include <QPushButton>
00032 #include <QComboBox>
00033 
00034 Arrow::Arrow()
00035 {
00036   Name = "Arrow ";
00037   isSelected = false;
00038   Pen = QPen(QColor());
00039   cx = cy = 0;
00040   x1 = x2 = 0;
00041   y1 = y2 = 0;
00042 
00043   Height = 20.0;
00044   Width  =  8.0;
00045   Style  = 0;   // arrow head not filled
00046   beta   = atan2(double(Width), double(Height));
00047   Length = sqrt(Width*Width + Height*Height);
00048 }
00049 
00050 Arrow::~Arrow()
00051 {
00052 }
00053 
00054 // --------------------------------------------------------------------------
00055 void Arrow::paint(ViewPainter *p)
00056 {
00057   QPolygon Points;
00058   int x1_, y1_, x2_, y2_, x3_, y3_;
00059   if(isSelected) {
00060     p->Painter->setPen(QPen(Qt::darkGray,Pen.width()+5));
00061     p->drawLine(cx, cy, cx+x2, cy+y2);
00062     p->drawLine(cx+x2, cy+y2, cx+xp1, cy+yp1);
00063     p->drawLine(cx+x2, cy+y2, cx+xp2, cy+yp2);
00064     if(Style == 0) {   // arrow head with two lines ?
00065       p->Painter->setPen(QPen(Qt::white, Pen.width(), Pen.style()));
00066       p->drawLine(cx, cy, cx+x2, cy+y2);
00067       p->Painter->setPen(QPen(Qt::white, Pen.width(), Qt::SolidLine));
00068       p->drawLine(cx+x2, cy+y2, cx+xp1, cy+yp1);
00069       p->drawLine(cx+x2, cy+y2, cx+xp2, cy+yp2);
00070     }
00071     else {   // filled arrow head
00072       p->drawLine(cx+xp1, cy+yp1, cx+xp2, cy+yp2);
00073       p->Painter->setPen(QPen(Qt::white, Pen.width(), Pen.style()));
00074       p->drawLine(cx, cy, cx+x2, cy+y2);
00075 
00076       p->Painter->setPen(QPen(Qt::white, Pen.width(), Qt::SolidLine));
00077       p->Painter->setBrush(Qt::white);
00078       p->map(cx+xp1, cy+yp1, x1_, y1_);
00079       p->map(cx+x2, cy+y2, x2_, y2_);
00080       p->map(cx+xp2, cy+yp2, x3_, y3_);
00081       Points.setPoints(3, x1_, y1_, x2_, y2_, x3_, y3_);
00082       p->Painter->drawConvexPolygon(Points);
00083       p->Painter->setBrush(Qt::NoBrush); // no filling for next paintings
00084     }
00085 
00086     p->Painter->setPen(QPen(Qt::darkRed,2));
00087     p->drawResizeRect(cx, cy);  // markers for changing the size
00088     p->drawResizeRect(cx+x2, cy+y2);
00089     return;
00090   }
00091   p->Painter->setPen(Pen);
00092   p->drawLine(cx, cy, cx+x2, cy+y2);
00093   p->Painter->setPen(QPen(Pen.color(), Pen.width(), Qt::SolidLine));
00094   if(Style == 0) {   // arrow head with two lines ?
00095     p->drawLine(cx+x2, cy+y2, cx+xp1, cy+yp1);
00096     p->drawLine(cx+x2, cy+y2, cx+xp2, cy+yp2);
00097   }
00098   else {   // filled arrow head
00099     p->Painter->setBrush(Pen.color());
00100     p->map(cx+xp1, cy+yp1, x1_, y1_);
00101     p->map(cx+x2, cy+y2, x2_, y2_);
00102     p->map(cx+xp2, cy+yp2, x3_, y3_);
00103     Points.setPoints(3, x1_, y1_, x2_, y2_, x3_, y3_);
00104     p->Painter->drawConvexPolygon(Points);
00105     p->Painter->setBrush(Qt::NoBrush); // no filling for next paintings
00106   }
00107 }
00108 
00109 // --------------------------------------------------------------------------
00110 void Arrow::paintScheme(Schematic *p)
00111 {
00112   p->PostPaintEvent(_Line, cx, cy, cx+x2, cy+y2,0,0,false);
00113   p->PostPaintEvent(_Line, cx+x2, cy+y2, cx+xp1, cy+yp1,0,0,false);
00114   p->PostPaintEvent(_Line, cx+x2, cy+y2, cx+xp2, cy+yp2,0,0,false);
00115 }
00116 
00117 // --------------------------------------------------------------------------
00118 void Arrow::getCenter(int& x, int &y)
00119 {
00120   x = cx+(x2>>1);
00121   y = cy+(y2>>1);
00122 }
00123 
00124 // --------------------------------------------------------------------------
00125 // Sets the center of the painting to x/y.
00126 void Arrow::setCenter(int x, int y, bool relative)
00127 {
00128   if(relative) { cx += x;  cy += y; }
00129   else { cx = x-(x2>>1);  cy = y-(y2>>1); }
00130 }
00131 
00132 // --------------------------------------------------------------------------
00133 Painting* Arrow::newOne()
00134 {
00135   return new Arrow();
00136 }
00137 
00138 // --------------------------------------------------------------------------
00139 Element* Arrow::info(QString& Name, char* &BitmapFile, bool getNewOne)
00140 {
00141   Name = QObject::tr("Arrow");
00142   BitmapFile = (char *) "arrow";
00143 
00144   if(getNewOne)  return new Arrow();
00145   return 0;
00146 }
00147 
00148 // --------------------------------------------------------------------------
00149 bool Arrow::load(const QString& s)
00150 {
00151   bool ok;
00152 
00153   QString n;
00154   n  = s.section(' ',1,1);    // cx
00155   cx = n.toInt(&ok);
00156   if(!ok) return false;
00157 
00158   n  = s.section(' ',2,2);    // cy
00159   cy = n.toInt(&ok);
00160   if(!ok) return false;
00161 
00162   n  = s.section(' ',3,3);    // x2
00163   x2 = n.toInt(&ok);
00164   if(!ok) return false;
00165 
00166   n  = s.section(' ',4,4);    // y2
00167   y2 = n.toInt(&ok);
00168   if(!ok) return false;
00169 
00170   n  = s.section(' ',5,5);    // height
00171   Height = n.toDouble(&ok);
00172   if(!ok) return false;
00173 
00174   n  = s.section(' ',6,6);    // width
00175   Width = n.toDouble(&ok);
00176   if(!ok) return false;
00177 
00178   n  = s.section(' ',7,7);    // color
00179   QColor co;
00180   co.setNamedColor(n);
00181   Pen.setColor(co);
00182   if(!Pen.color().isValid()) return false;
00183 
00184   n  = s.section(' ',8,8);    // thickness
00185   Pen.setWidth(n.toInt(&ok));
00186   if(!ok) return false;
00187 
00188   n  = s.section(' ',9,9);    // line style
00189   Pen.setStyle((Qt::PenStyle)n.toInt(&ok));
00190   if(!ok) return false;
00191 
00192   n  = s.section(' ',10,10);    // arrow style
00193   if(!n.isEmpty()) {            // backward compatible
00194     Style = n.toInt(&ok);
00195     if(!ok) return false;
00196   }
00197 
00198   beta   = atan2(double(Width), double(Height));
00199   Length = sqrt(Width*Width + Height*Height);
00200   calcArrowHead();
00201   return true;
00202 }
00203 
00204 // --------------------------------------------------------------------------
00205 QString Arrow::save()
00206 {
00207   QString s = Name+QString::number(cx)+" "+QString::number(cy)+" ";
00208   s += QString::number(x2)+" "+QString::number(y2)+" ";
00209   s += QString::number(int(Height))+" "+QString::number(int(Width))+" ";
00210   s += Pen.color().name()+" "+QString::number(Pen.width())+" ";
00211   s += QString::number(Pen.style()) + " " + QString::number(Style);
00212   return s;
00213 }
00214 
00215 // --------------------------------------------------------------------------
00216 QString Arrow::saveCpp()
00217 {
00218   // arrow not allowed in symbols, thus we use line here
00219   QString s =
00220     QString ("new Line (%1, %2, %3, %4, QPen (QColor (\"%5\"), %6, %7))").
00221     arg(cx+x1).arg(cy+y1).arg(cx+x2).arg(cy+y2).
00222     arg(Pen.color().name()).arg(Pen.width()).arg(toPenString(Pen.style()));
00223   s = "Lines.append (" + s + ");";
00224   return s;
00225 }
00226 
00227 QString Arrow::saveJSON()
00228 {
00229   // arrow not allowed in symbols, thus we use line here
00230   QString s =
00231     QString("{\"type\" : \"arrow\", "
00232        "\"x1\" : %1, \"y1\" : %2, \"x2\" : %3, \"y2\" : %4, "
00233        "\"color\" : \"%5\", \"thick\" : %6, \"style\" : \"%7\"},").
00234        arg(cx+x1).arg(cy+y1).arg(cx+x2).arg(cy+y2).
00235        arg(Pen.color().name()).arg(Pen.width()).arg(toPenString(Pen.style()));
00236   return s;
00237 }
00238 
00239 // --------------------------------------------------------------------------
00240 // Checks if the resize area was clicked.
00241 bool Arrow::resizeTouched(float fX, float fY, float len)
00242 {
00243   float fCX = float(cx),fCY = float(cy);
00244   if(fX < fCX+len) if(fX > fCX-len) if(fY < fCY+len) if(fY > fCY-len) {
00245     State = 1;
00246     return true;
00247   }
00248 
00249   fCX += float(x2);
00250   fCY += float(y2);
00251   if(fX < fCX+len) if(fX > fCX-len) if(fY < fCY+len) if(fY > fCY-len) {
00252     State = 2;
00253     return true;
00254   }
00255 
00256   State = 0;
00257   return false;
00258 }
00259 
00260 // --------------------------------------------------------------------------
00261 // Mouse move action during resize.
00262 void Arrow::MouseResizeMoving(int x, int y, Schematic *p)
00263 {
00264   paintScheme(p);  // erase old painting
00265   if(State == 1) { x2 += cx-x; y2 += cy-y; cx = x; cy = y; } // moving shaft
00266   else { x2 = x-cx;  y2 = y-cy; }  // moving head
00267 
00268   calcArrowHead();
00269   paintScheme(p);  // paint new painting
00270 }
00271 
00272 // --------------------------------------------------------------------------
00273 void Arrow::calcArrowHead()
00274 {
00275   double phi  = atan2(double(y2), double(x2));
00276 
00277   double w = beta+phi;
00278   xp1 = x2-int(Length*cos(w));
00279   yp1 = y2-int(Length*sin(w));
00280 
00281   w = phi-beta;
00282   xp2 = x2-int(Length*cos(w));
00283   yp2 = y2-int(Length*sin(w));
00284 }
00285 
00286 // --------------------------------------------------------------------------
00287 // fx/fy are the precise coordinates, gx/gy are the coordinates set on grid.
00288 // x/y are coordinates without scaling.
00289 void Arrow::MouseMoving(
00290   Schematic *paintScale, int, int, int gx, int gy,
00291   Schematic *p, int x, int y, bool drawn)
00292 {
00293   if(State > 0) {
00294     if(State > 1) {
00295       calcArrowHead();
00296       paintScheme(paintScale);  // erase old painting
00297     }
00298     State++;
00299     x2 = gx-cx;
00300     y2 = gy-cy;
00301     calcArrowHead();
00302     paintScheme(paintScale);  // paint new painting
00303   }
00304   else { cx = gx; cy = gy; }
00305 
00306 
00307 // FIXME #warning  p->setPen(Qt::SolidLine);
00308   if(drawn) {
00309     p->PostPaintEvent(_Line, x1+25, y1, x1+13, y1+12,0,0,true);  // erase old cursor symbol
00310     p->PostPaintEvent(_Line, x1+18, y1+2, x1+25, y1,0,0,true);
00311     p->PostPaintEvent(_Line, x1+23, y1+7, x1+25, y1,0,0,true);
00312   }
00313   x1 = x;
00314   y1 = y;
00315   p->PostPaintEvent(_Line, x1+25, y1, x1+13, y1+12,0,0,true);  // paint new cursor symbol
00316   p->PostPaintEvent(_Line, x1+18, y1+2, x1+25, y1,0,0,true);
00317   p->PostPaintEvent(_Line, x1+23, y1+7, x1+25, y1,0,0,true);
00318 }
00319 
00320 // --------------------------------------------------------------------------
00321 bool Arrow::MousePressing()
00322 {
00323   State++;
00324   if(State > 2) {
00325     x1 = y1 = 0;
00326     State = 0;
00327 
00328     calcArrowHead();
00329     return true;    // painting is ready
00330   }
00331   return false;
00332 }
00333 
00334 // --------------------------------------------------------------------------
00335 // Checks if the coordinates x/y point to the painting.
00336 // 5 is the precision the user must point onto the painting.
00337 bool Arrow::getSelected(float fX, float fY, float w)
00338 {
00339   float A, xn, yn;
00340   // first check if coordinates match the arrow body
00341   fX -= float(cx);
00342   fY -= float(cy);
00343 
00344   if(fX < -w) {
00345     if(fX < float(x2)-w)  // is point between x coordinates ?
00346       goto Head1;
00347   }
00348   else {
00349     if(fX > w)
00350       if(fX > float(x2)+w)
00351         goto Head1;
00352   }
00353 
00354   if(fY < -w) {
00355     if(fY < float(y2)-w)   // is point between y coordinates ?
00356       goto Head1;
00357   }
00358   else {
00359     if(fY > w)
00360       if(fY > float(y2)+w)
00361         goto Head1;
00362   }
00363 
00364   A  = float(x2)*fY - fX*float(y2); // calculate the rectangle area spanned
00365   A *= A;               // avoid the need for square root
00366 
00367   if(A <= w*w*float(x2*x2 + y2*y2))
00368     return true;     // x/y lies on the graph line
00369 
00370 Head1:    // check if coordinates match the first arrow head line
00371   xn = float(xp1-x2);  fX -= float(x2);
00372   yn = float(yp1-y2);  fY -= float(y2);
00373 
00374   if(fX < -w) {
00375     if(fX < xn-w)    // is point between x coordinates ?
00376       goto Head2;
00377   }
00378   else {
00379     if(fX > w)
00380       if(fX > xn+w)
00381         goto Head2;
00382   }
00383 
00384   if(fY < -w) {
00385     if(fY < yn-w)    // is point between y coordinates ?
00386       goto Head2;
00387   }
00388   else
00389     if(fY > w)
00390       if(fY > yn+w)
00391         goto Head2;
00392 
00393   A  = xn*fY - fX*yn;   // calculate the rectangle area spanned
00394   A *= A;               // avoid the need for square root
00395 
00396   if(A <= w*w*(xn*xn + yn*yn))
00397     return true;     // x/y lies on the arrow head
00398 
00399 Head2:    // check if coordinates match the second arrow head line
00400   xn = float(xp2-x2);
00401   yn = float(yp2-y2);
00402 
00403   if(fX < -w) {
00404     if(fX < xn-w)   // is point between x coordinates ?
00405       return false;
00406   }
00407   else
00408     if(fX > w)
00409       if(fX > xn+w)
00410         return false;
00411 
00412   if(fY < -w) {
00413     if(fY < yn-w)   // is point between y coordinates ?
00414       return false;
00415   }
00416   else
00417     if(fY > w)
00418       if(fY > yn+w)
00419         return false;
00420 
00421   A  = xn*fY - fX*yn;   // calculate the rectangle area spanned
00422   A *= A;               // avoid the need for square root
00423 
00424   if(A <= w*w*(xn*xn + yn*yn))
00425     return true;     // x/y lies on the arrow head
00426 
00427   return false;
00428 }
00429 
00430 // --------------------------------------------------------------------------
00431 void Arrow::Bounding(int& _x1, int& _y1, int& _x2, int& _y2)
00432 {
00433   if(x2 < 0) { _x1 = cx+x2; _x2 = cx; }
00434   else { _x1 = cx; _x2 = cx+x2; }
00435 
00436   if(y2 < 0) { _y1 = cy+y2; _y2 = cy; }
00437   else { _y1 = cy; _y2 = cy+y2; }
00438 }
00439 
00440 // --------------------------------------------------------------------------
00441 // Rotates around the center.
00442 void Arrow::rotate()
00443 {
00444   cx += (x2>>1) - (y2>>1);
00445   cy += (x2>>1) + (y2>>1);
00446 
00447   int tmp = x2;
00448   x2  =  y2;
00449   y2  = -tmp;
00450 
00451   tmp =  xp1;
00452   xp1 =  yp1;
00453   yp1 = -tmp;
00454 
00455   tmp =  xp2;
00456   xp2 =  yp2;
00457   yp2 = -tmp;
00458 }
00459 
00460 // --------------------------------------------------------------------------
00461 // Mirrors about center line.
00462 void Arrow::mirrorX()
00463 {
00464   yp1 = -yp1;
00465   yp2 = -yp2;
00466   cy +=  y2;   // change cy after the other changes !
00467   y2  = -y2;
00468 }
00469 
00470 // --------------------------------------------------------------------------
00471 // Mirrors about center line.
00472 void Arrow::mirrorY()
00473 {
00474   xp1 = -xp1;
00475   xp2 = -xp2;
00476   cx +=  x2;   // change cx after the other changes !
00477   x2  = -x2;
00478 }
00479 
00480 // --------------------------------------------------------------------------
00481 // Calls the property dialog for the painting and changes them accordingly.
00482 // If there were changes, it returns 'true'.
00483 bool Arrow::Dialog()
00484 {
00485   bool changed = false;
00486 
00487   ArrowDialog *d = new ArrowDialog();
00488   d->HeadWidth->setText(QString::number(Width));
00489   d->HeadLength->setText(QString::number(Height));
00490 
00491   QPalette palette;
00492   palette.setColor(d->ColorButt->backgroundRole(), Pen.color());
00493   d->ColorButt->setPalette(palette);
00494 
00495   d->LineWidth->setText(QString::number(Pen.width()));
00496   d->SetComboBox(Pen.style());
00497   d->ArrowStyleBox->setCurrentIndex(Style);
00498 
00499   if(d->exec() == QDialog::Rejected) {
00500     delete d;
00501     return false;
00502   }
00503 
00504   if(Width != d->HeadWidth->text().toDouble()) {
00505     Width = d->HeadWidth->text().toDouble();
00506     changed = true;
00507   }
00508   if(Height != d->HeadLength->text().toDouble()) {
00509     Height = d->HeadLength->text().toDouble();
00510     changed = true;
00511   }
00512   if(Pen.color() != d->ColorButt->palette().color(d->ColorButt->backgroundRole())) {
00513     Pen.setColor(d->ColorButt->palette().color(d->ColorButt->backgroundRole()));
00514     changed = true;
00515   }
00516   if(Pen.width() != d->LineWidth->text().toInt()) {
00517     Pen.setWidth(d->LineWidth->text().toInt());
00518     changed = true;
00519   }
00520   if(Pen.style() != d->LineStyle) {
00521     Pen.setStyle(d->LineStyle);
00522     changed = true;
00523   }
00524   if(Style != d->ArrowStyleBox->currentIndex()) {
00525     Style = d->ArrowStyleBox->currentIndex();
00526     changed = true;
00527   }
00528 
00529   beta   = atan2(double(Width), double(Height));
00530   Length = sqrt(Width*Width + Height*Height);
00531   calcArrowHead();
00532 
00533   delete d;
00534   return changed;
00535 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines