linkablemapobj.cpp
author insilmaril
Tue Mar 23 11:54:30 2010 +0000 (2010-03-23)
branchrelease-1-12-maintained
changeset 81 876eed30ba3b
parent 0 7a96bd401351
permissions -rw-r--r--
Patch from Xavier Oswald to compile with older compilers
     1 #include <math.h>
     2 #include <cstdlib>
     3 
     4 #include "linkablemapobj.h"
     5 #include "branchobj.h"
     6 #include "mapeditor.h"
     7 
     8 /////////////////////////////////////////////////////////////////
     9 // LinkableMapObj
    10 /////////////////////////////////////////////////////////////////
    11 
    12 LinkableMapObj::LinkableMapObj():MapObj()
    13 {
    14   //  cout << "Const LinkableMapObj ()\n";
    15     init ();
    16 }
    17 
    18 LinkableMapObj::LinkableMapObj(QGraphicsScene* s) :MapObj(s)
    19 {
    20 //    cout << "Const LinkableMapObj (s)\n";
    21     init ();
    22 }
    23 
    24 LinkableMapObj::LinkableMapObj (LinkableMapObj* lmo) : MapObj (lmo->scene)
    25 {
    26     copy (lmo);
    27 }
    28 
    29 LinkableMapObj::~LinkableMapObj()
    30 {
    31     delete (bottomline);
    32 	delLink();
    33 }
    34 
    35 void LinkableMapObj::delLink()
    36 {
    37 	switch (style)
    38 	{
    39 		case Line:
    40 			delete (l);
    41 			break;
    42 		case Parabel:
    43 			while (!segment.isEmpty()) delete segment.takeFirst();
    44 			break;
    45 		case PolyLine:
    46 			delete (p);
    47 			break;
    48 		case PolyParabel:
    49 			delete (p);
    50 			break;
    51 		default:
    52 			break;
    53 	}		
    54 }
    55 
    56 void LinkableMapObj::init ()
    57 {
    58     depth=-1;	
    59 	mapEditor=NULL;
    60     childObj=NULL;
    61     parObj=NULL;
    62     parObjTmpBuf=NULL;
    63     parPos=QPointF(0,0);
    64     childPos=QPointF(0,0);
    65 	link2ParPos=false;
    66     l=NULL;
    67     orientation=UndefinedOrientation;
    68     linkwidth=20;		
    69 	thickness_start=8;
    70     style=UndefinedStyle;
    71 	linkpos=Bottom;
    72     arcsegs=13;
    73     
    74 // TODO instead of linkcolor pen.color() could be used	all around
    75 	pen.setWidth (1);
    76 	pen.setColor (linkcolor);
    77 	pen.setCapStyle ( Qt::RoundCap );
    78 	bottomline=scene->addLine(QLineF(1,1,1,1),pen);
    79     bottomline->setZValue(Z_LINK);
    80     bottomline->show();
    81 
    82     // Prepare showing the selection of a MapObj
    83     selected=false;
    84 
    85 	hideLinkUnselected=false;
    86 
    87 	topPad=botPad=leftPad=rightPad=0;
    88 
    89 	repositionRequest=false;
    90 
    91 	// Rel Positions
    92 	relPos=QPointF(0,0);
    93 	useRelPos=false;
    94 	useOrientation=true;
    95 
    96 	// Reset ID
    97 	objID="";
    98 }
    99 
   100 void LinkableMapObj::copy (LinkableMapObj* other)
   101 {
   102     MapObj::copy(other);
   103 	bboxTotal=other->bboxTotal;
   104     setLinkStyle(other->style);
   105     setLinkColor (other->linkcolor);
   106 	relPos=other->relPos;
   107 	useOrientation=other->useOrientation;
   108 	objID=other->objID;
   109 }
   110 
   111 void LinkableMapObj::setChildObj(LinkableMapObj* o)
   112 {
   113     childObj=o;
   114 }
   115 
   116 void LinkableMapObj::setParObj(LinkableMapObj* o)
   117 {
   118     parObj=o;
   119 	mapEditor=parObj->getMapEditor();
   120 }
   121 
   122 void LinkableMapObj::setParObjTmp(LinkableMapObj*,QPointF,int)
   123 {
   124 }
   125 
   126 void LinkableMapObj::unsetParObjTmp()
   127 {
   128 }
   129 
   130 bool LinkableMapObj::hasParObjTmp()
   131 {
   132 	if (parObjTmpBuf) return true;
   133 	return false;
   134 }
   135 
   136 void LinkableMapObj::setUseRelPos (const bool &b)
   137 {
   138 	useRelPos=b;
   139 }
   140 
   141 void LinkableMapObj::setRelPos()
   142 {
   143 	if (parObj)
   144 	{	
   145 		relPos.setX (absPos.x() - parObj->getChildPos().x() );
   146 		relPos.setY (absPos.y() - parObj->getChildPos().y() );
   147 		parObj->calcBBoxSize();
   148 	}	
   149 }
   150 
   151 void LinkableMapObj::setRelPos(const QPointF &p)
   152 {
   153 	relPos=p;
   154 	if (parObj)
   155 	{		
   156 		parObj->calcBBoxSize();
   157 		requestReposition();
   158 	}
   159 }
   160 
   161 QPointF LinkableMapObj::getRelPos()
   162 {
   163 	if (!parObj) return QPointF();
   164 	return relPos;
   165 }
   166 
   167 qreal LinkableMapObj::getTopPad()
   168 {
   169 	return topPad;
   170 }
   171 
   172 qreal LinkableMapObj::getLeftPad()
   173 {
   174 	return leftPad;
   175 }
   176 
   177 qreal LinkableMapObj::getRightPad()
   178 {
   179 	return rightPad;
   180 }
   181 
   182 LinkableMapObj::Style LinkableMapObj::getDefLinkStyle ()
   183 {
   184 	if (!mapEditor) return UndefinedStyle;
   185 	Style ls=mapEditor->getMapLinkStyle();
   186 	switch (ls)
   187 	{
   188 		case Line: 
   189 			return ls;
   190 			break;
   191 		case Parabel:
   192 			return ls;
   193 			break;
   194 		case PolyLine:	
   195 			if (depth>1)
   196 				return Line;
   197 			else	
   198 				return ls;
   199 			break;
   200 		case PolyParabel:	
   201 			if (depth>1)
   202 				return Parabel;
   203 			else	
   204 				return ls;
   205 			break;
   206 		default: 
   207 			break;	
   208 	}	
   209 	return UndefinedStyle;
   210 }
   211 
   212 void LinkableMapObj::setLinkStyle(Style newstyle)
   213 {
   214 	//if (newstyle=style) return;
   215 	delLink();
   216 		
   217 	style=newstyle;
   218 
   219     if (childObj!=NULL && parObj != NULL)
   220     {
   221 		QGraphicsLineItem *cl;
   222 		switch (style)
   223 		{
   224 			case UndefinedStyle:
   225 				bottomline->hide();
   226 				break;
   227 			case Line: 
   228 				l = scene->addLine(QLineF(1,1,1,1),pen);
   229 				l->setZValue(Z_LINK);
   230 				if (visible)
   231 					l->show();
   232 				else
   233 					l->hide();
   234 				break;
   235 			case Parabel:
   236 				for (int i=0;i<arcsegs;i++)
   237 				{
   238 					cl = scene->addLine(QLineF(i*5,0,i*10,100),pen);
   239 					cl->setZValue(Z_LINK);
   240 					if (visible)
   241 						cl->show();
   242 					else
   243 						cl->hide();
   244 					segment.append(cl);
   245 				}
   246 				pa0.resize (arcsegs+1);
   247 				break;
   248 			case PolyLine:	
   249 				p =scene->addPolygon(QPolygonF(),pen,linkcolor);
   250 				p->setZValue(Z_LINK);
   251 				if (visible)
   252 					p->show();
   253 				else
   254 					p->hide();
   255 				pa0.resize (3);
   256 				break;
   257 			case PolyParabel:	
   258 				p = scene->addPolygon(QPolygonF(),pen,linkcolor);
   259 				p->setZValue(Z_LINK);
   260 				if (visible)
   261 					p->show();
   262 				else
   263 					p->hide();
   264 				pa0.resize (arcsegs*2+2);
   265 				pa1.resize (arcsegs+1);
   266 				pa2.resize (arcsegs+1);
   267 				break;
   268 			default: 
   269 				break;	
   270 		}	
   271 	} 
   272 }
   273 
   274 LinkableMapObj::Style LinkableMapObj::getLinkStyle()
   275 {
   276 	return style;
   277 }
   278 
   279 void LinkableMapObj::setHideLinkUnselected(bool b)
   280 {
   281 	hideLinkUnselected=b;
   282 	setVisibility (visible);
   283 	updateLink();
   284 }
   285 
   286 bool LinkableMapObj::getHideLinkUnselected()
   287 {
   288 	return hideLinkUnselected;
   289 }
   290 
   291 void LinkableMapObj::setLinkPos(Position lp)
   292 {
   293 	linkpos=lp;
   294 }
   295 
   296 LinkableMapObj::Position LinkableMapObj::getLinkPos()
   297 {
   298 	return linkpos;
   299 }
   300 
   301 void LinkableMapObj::setID (const QString &s)
   302 {
   303 	objID=s;
   304 }
   305 
   306 QString LinkableMapObj::getID()
   307 {
   308 	return objID;
   309 }
   310 
   311 void LinkableMapObj::setLinkColor()
   312 {
   313 	// Overloaded in BranchObj and childs
   314 	// here only set default color
   315 	if (mapEditor)
   316 		setLinkColor (mapEditor->getMapDefLinkColor());
   317 }
   318 
   319 void LinkableMapObj::setLinkColor(QColor col)
   320 {
   321 	linkcolor=col;
   322 	pen.setColor(col);
   323     bottomline->setPen( pen );
   324 	switch (style)
   325 	{
   326 		case Line:
   327 			l->setPen( pen);
   328 			break;	
   329 		case Parabel:	
   330 			for (int i=0; i<segment.size(); ++i)
   331 				segment.at(i)->setPen( pen);
   332 			break;
   333 		case PolyLine:
   334 			p->setBrush( QBrush(col));
   335 			p->setPen( pen);
   336 			break;
   337 		case PolyParabel:	
   338 			p->setBrush( QBrush(col));
   339 			p->setPen( pen);
   340 			break;
   341 		default:
   342 			break;
   343 	} // switch (style)	
   344 }
   345 
   346 QColor LinkableMapObj::getLinkColor()
   347 {
   348 	return linkcolor;
   349 }
   350 
   351 void LinkableMapObj::setVisibility (bool v)
   352 {
   353 	MapObj::setVisibility (v);
   354 	bool visnow=visible;
   355 
   356 	// We can hide the link, while object is not selected
   357 	if (hideLinkUnselected && !selected)
   358 		visnow=false;
   359 
   360 	if (visnow) 
   361 	{
   362 		bottomline->show();
   363 		switch (style)
   364 		{
   365 			case Line:
   366 				if (l) l->show();
   367 				break;
   368 			case Parabel:	
   369 				for (int i=0; i<segment.size(); ++i)
   370 					segment.at(i)->show();
   371 				break;	
   372 			case PolyLine:
   373 				if (p) p->show();
   374 				break;
   375 			case PolyParabel:	
   376 				if (p) p->show();
   377 				break;
   378 			default:
   379 				break;
   380 		}
   381 	} else 
   382 	{
   383 		bottomline->hide();
   384 		switch (style)
   385 		{
   386 			case Line:
   387 				if (l) l->hide();
   388 				break;
   389 			case Parabel:	
   390 				for (int i=0; i<segment.size(); ++i)
   391 					segment.at(i)->hide();
   392 				break;	
   393 			case PolyLine:
   394 				if (p) p->hide();
   395 				break;
   396 			case PolyParabel:	
   397 				if (p) p->hide();
   398 				break;
   399 			default:
   400 				break;
   401 		}
   402 	}	
   403 }
   404 
   405 void LinkableMapObj::setOrientation()
   406 {
   407 	Orientation orientOld=orientation;
   408 
   409 	if (!parObj) 
   410 	{
   411 		orientation=UndefinedOrientation;
   412 		return;
   413 	}
   414 		
   415     // Set orientation, first look for orientation of parent
   416     if (parObj->getOrientation() != UndefinedOrientation ) 
   417 		// use the orientation of the parent:
   418 		orientation=parObj->getOrientation();
   419     else
   420     {
   421 		// calc orientation depending on position rel to parent
   422 		if (absPos.x() < QPointF(parObj->getChildPos() ).x() )
   423 			orientation=LeftOfCenter; 
   424 		else
   425 			orientation=RightOfCenter;
   426     }
   427 	if (orientOld!=orientation) requestReposition();
   428 }
   429 
   430 void LinkableMapObj::updateLink()
   431 {
   432     // needs:
   433     //	childPos of parent
   434     //	orient   of parent
   435     //	style
   436     // 
   437     // sets:
   438     //	orientation
   439     //	childPos	(by calling setDockPos())
   440     //	parPos		(by calling setDockPos())
   441 	//  bottomlineY
   442     //	drawing of the link itself
   443 
   444 	// updateLink is called from move, but called from constructor we don't
   445 	// have parents yet...
   446 	if (style==UndefinedStyle) return;	
   447 
   448 	switch (linkpos)
   449 	{
   450 		case Middle:
   451 			bottomlineY=bbox.top() + bbox.height()/2;	// draw link to middle (of frame)
   452 			break;
   453 		case Bottom:
   454 			bottomlineY=bbox.bottom()-1;	// draw link to bottom of box
   455 			break;
   456 	}
   457 	
   458     double p2x,p2y;								// Set P2 Before setting
   459 	if (!link2ParPos)
   460 	{
   461 		p2x=QPointF( parObj->getChildPos() ).x();	// P1, we have to look at
   462 		p2y=QPointF( parObj->getChildPos() ).y();	// orientation
   463 	} else	
   464 	{
   465 		p2x=QPointF( parObj->getParPos() ).x();	
   466 		p2y=QPointF( parObj->getParPos() ).y();
   467 	} 
   468 
   469 	setDockPos(); // Call overloaded method
   470 	setOrientation();
   471 
   472 	double p1x=parPos.x();	// Link is drawn from P1 to P2
   473 	double p1y=parPos.y();
   474 
   475 	double vx=p2x - p1x;	// V=P2-P1
   476 	double vy=p2y - p1y;
   477 
   478 	// Draw the horizontal line below heading (from ChildPos to ParPos)
   479 	//bottomline->prepareGeometryChange();
   480 	bottomline->setLine (QLine (qRound(childPos.x()),
   481 		qRound(childPos.y()),
   482 		qRound(p1x),
   483 		qRound(p1y) ));
   484 
   485 	double a;	// angle
   486 	if (vx > -0.000001 && vx < 0.000001)
   487 		a=M_PI_2;
   488 	else
   489 		a=atan( vy / vx );
   490 	// "turning point" for drawing polygonal links
   491 	QPointF tp (-qRound(sin (a)*thickness_start), qRound(cos (a)*thickness_start));	
   492 	
   493     // Draw the link
   494 	switch (style)
   495 	{
   496 		case Line:
   497 			//l->prepareGeometryChange();
   498 			l->setLine( QLine(qRound (parPos.x()),
   499 				qRound(parPos.y()),
   500 				qRound(p2x),
   501 				qRound(p2y) ));
   502 			break;	
   503 		case Parabel:	
   504 			parabel (pa0, p1x,p1y,p2x,p2y);
   505 			for (int i=0; i<segment.size(); ++i)
   506 			{
   507 				//segment.at(i)->prepareGeometryChange();
   508 				segment.at(i)->setLine(QLineF( pa0.at(i).x(), pa0.at(i).y(),pa0.at(i+1).x(),pa0.at(i+1).y()));
   509 			}	
   510 			break;
   511 		case PolyLine:
   512 			pa0.clear();
   513 			pa0<<QPointF (qRound(p2x+tp.x()), qRound(p2y+tp.y()));
   514 			pa0<<QPointF (qRound(p2x-tp.x()), qRound(p2y-tp.y()));
   515 			pa0<<QPointF (qRound (parPos.x()), qRound(parPos.y()) );
   516 			//p->prepareGeometryChange();
   517 			p->setPolygon(QPolygonF (pa0));
   518 			break;
   519 		case PolyParabel:	
   520 			parabel (pa1, p1x,p1y,p2x+tp.x(),p2y+tp.y());
   521 			parabel (pa2, p1x,p1y,p2x-tp.x(),p2y-tp.y());
   522 			pa0.clear();
   523 			for (int i=0;i<=arcsegs;i++)
   524 				pa0 << QPointF (pa1.at(i));
   525 			for (int i=0;i<=arcsegs;i++)
   526 				pa0 << QPointF (pa2.at(arcsegs-i));
   527 			//p->prepareGeometryChange();
   528 			p->setPolygon(QPolygonF (pa0));
   529 			break;
   530 		default:
   531 			break;
   532 	} // switch (style)	
   533 }
   534 	
   535 LinkableMapObj* LinkableMapObj::getChildObj()
   536 {
   537     return childObj;
   538 }
   539 
   540 LinkableMapObj* LinkableMapObj::getParObj()
   541 {
   542     return parObj;
   543 }
   544 
   545 LinkableMapObj* LinkableMapObj::findObjBySelect (QString s)
   546 {
   547 	LinkableMapObj *lmo=this;
   548 	QString part;
   549 	QString typ;
   550 	QString num;
   551 	while (!s.isEmpty() )
   552 	{
   553 		part=s.section(",",0,0);
   554 		typ=part.left (3);
   555 		num=part.right(part.length() - 3);
   556 		if (typ=="mc:")
   557 		{
   558 			if (depth>0)
   559 				return false;	// in a subtree there is no center
   560 			else
   561 				break;
   562 		} else
   563 			if (typ=="bo:")
   564 				lmo=((BranchObj*)lmo)->getBranchNum (num.toInt());
   565 			else
   566 				if (typ=="fi:")
   567 					lmo=((BranchObj*)lmo)->getFloatImageNum (num.toUInt());
   568 		if (!lmo) break;
   569 		
   570 		if (s.contains(","))
   571 			s=s.right(s.length() - part.length() -1 );
   572 		else	
   573 			break;
   574 	}
   575 	return lmo;
   576 }
   577 
   578 QPointF LinkableMapObj::getChildPos()
   579 {
   580     return childPos;
   581 }
   582 
   583 QPointF LinkableMapObj::getParPos()
   584 {
   585     return parPos;
   586 }
   587 
   588 void LinkableMapObj::setUseOrientation (const bool &b)
   589 {	
   590 	if (useOrientation!=b)
   591 	{
   592 		useOrientation=b;
   593 		requestReposition();
   594 	}	
   595 }
   596 
   597 LinkableMapObj::Orientation LinkableMapObj::getOrientation()
   598 {
   599     return orientation;
   600 }
   601 
   602 int LinkableMapObj::getDepth()
   603 {
   604     return depth;
   605 }
   606 
   607 void LinkableMapObj::setMapEditor (MapEditor *me)
   608 {
   609 	mapEditor=me;
   610 }
   611 
   612 MapEditor* LinkableMapObj::getMapEditor ()
   613 {
   614 	return mapEditor;
   615 }
   616 
   617 QPointF LinkableMapObj::getRandPos()
   618 {
   619 	// Choose a random position with given distance to parent:
   620 	double a=rand()%360 * 2 * M_PI / 360;
   621     return QPointF ( (int)( + 150*cos (a)),
   622                     (int)( + 150*sin (a)));
   623 }
   624 
   625 void LinkableMapObj::reposition()
   626 {
   627 }
   628 
   629 void LinkableMapObj::requestReposition()
   630 {
   631 	if (!repositionRequest)
   632 	{
   633 		// Pass on the request to parental objects, if this hasn't
   634 		// been done yet
   635 		repositionRequest=true;
   636 		if (parObj) parObj->requestReposition();
   637 	}
   638 }
   639 
   640 void LinkableMapObj::forceReposition()
   641 {
   642 	// Sometimes a reposition has to be done immediatly: For example
   643 	// if the note editor flag changes, there is no user event in mapeditor
   644 	// which could collect requests for a reposition.
   645 	// Then we have to call forceReposition()
   646 	// But no rule without exception: While loading a map or undoing it,
   647 	// we want to block expensive repositioning, but just do it once at
   648 	// the end, thus check first:
   649 
   650 	if (mapEditor->isRepositionBlocked()) return;
   651 	
   652 	// Pass on the request to parental objects, if this hasn't been done yet
   653 	
   654 	if (parObj) 
   655 		parObj->forceReposition(); 
   656 	else 
   657 		reposition(); 
   658 }
   659 
   660 bool LinkableMapObj::repositionRequested()
   661 {
   662 	return repositionRequest;
   663 }
   664 
   665 
   666 void LinkableMapObj::select()
   667 {
   668 	// select and unselect are still needed to
   669 	// handle hiding of links
   670     selected=true;
   671 	setVisibility (visible);
   672 }
   673 
   674 
   675 void LinkableMapObj::unselect()
   676 {
   677     selected=false;
   678 	// Maybe we have to hide the link:
   679 	setVisibility (visible);
   680 }
   681 
   682 void LinkableMapObj::parabel (QPolygonF &ya, double p1x, double p1y, double p2x, double p2y)
   683 
   684 {
   685 	double vx=p2x - p1x;	// V=P2-P1
   686 	double vy=p2y - p1y;
   687 
   688 	double dx;				// delta x during calculation of parabel
   689 	
   690 	double pnx;				// next point
   691 	double pny;
   692 	double m;
   693 
   694 	if (vx > -0.0001 && vx < 0.0001)
   695 		m=0;
   696 	else	
   697 		m=(vy / (vx*vx));
   698 	dx=vx/(arcsegs);
   699 	ya.clear();
   700 	ya<<QPointF (p1x,p1y);
   701 	for (int i=1;i<=arcsegs;i++)
   702 	{	
   703 		pnx=p1x+dx;
   704 		pny=m*(pnx-parPos.x())*(pnx-parPos.x())+parPos.y();
   705 		ya<<QPointF (pnx,pny);
   706 		p1x=pnx;
   707 		p1y=pny;
   708 	}	
   709 }
   710 
   711 QString LinkableMapObj::getLinkAttr ()
   712 {
   713 	if (hideLinkUnselected)
   714 		return attribut ("hideLink","true");
   715 	else
   716 		return attribut ("hideLink","false");
   717 	
   718 }
   719