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