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