Qucs-GUI
0.0.19
|
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 }