linkablemapobj.cpp
author insilmaril
Mon, 14 Jun 2010 13:59:17 +0000
changeset 848 e265f07f2173
parent 847 43268373032d
permissions -rw-r--r--
Fixed tmp relink, colored headings in TreeView
     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 /* FIXME-3
    15 LinkableMapObj::LinkableMapObj():MapObj()
    16 {
    17   //  cout << "Const LinkableMapObj ()\n";
    18     init ();
    19 }
    20 */
    21 
    22 LinkableMapObj::LinkableMapObj(QGraphicsScene* s, TreeItem *ti) :MapObj(s,ti)
    23 {
    24 //    cout << "Const LinkableMapObj s="<<s<<"  ti="<<ti<<"  treeItem="<<treeItem<<endl;
    25     init ();
    26 }
    27 
    28 LinkableMapObj::LinkableMapObj (LinkableMapObj* lmo) : MapObj (lmo->scene)
    29 {
    30     copy (lmo);
    31 }
    32 
    33 LinkableMapObj::~LinkableMapObj()
    34 {
    35 	//cout<< "Destructor LMO style="<<style<<" l="<<l<<"  p="<<p<<"  segment="<<segment.count()<<endl;
    36     if (bottomline)
    37 	{
    38 		delete (bottomline);
    39 		bottomline=NULL;
    40 	}	
    41 	delLink();
    42 }
    43 
    44 void LinkableMapObj::delLink()
    45 {
    46 	//bottomline->hide();
    47 	switch (style)
    48 	{
    49 		case Line:
    50 			delete (l);
    51 			break;
    52 		case Parabel:
    53 			while (!segment.isEmpty()) delete segment.takeFirst();
    54 			break;
    55 		case PolyLine:
    56 			delete (p);
    57 			break;
    58 		case PolyParabel:
    59 			delete (p);
    60 			break;
    61 		default:
    62 			break;
    63 	}		
    64 }
    65 
    66 void LinkableMapObj::init ()
    67 {
    68     parObj=NULL;
    69     parObjTmpBuf=NULL;
    70 	tmpParent=false;
    71     parPos=QPointF(0,0);
    72     childPos=QPointF(0,0);
    73 	link2ParPos=false;
    74     l=NULL;
    75 	p=NULL;
    76     orientation=UndefinedOrientation;
    77     linkwidth=20;		
    78 	thickness_start=8;
    79     style=UndefinedStyle;
    80 	linkpos=Bottom;
    81     arcsegs=13;
    82     
    83 // TODO instead of linkcolor pen.color() could be used	all around
    84 	pen.setWidth (1);
    85 	pen.setColor (linkcolor);
    86 	pen.setCapStyle ( Qt::RoundCap );
    87 
    88 	useBottomline=true;
    89 	bottomline=scene->addLine(QLineF(1,1,1,1),pen);
    90     bottomline->setZValue(Z_LINK);
    91     bottomline->show();
    92 
    93 	topPad=botPad=leftPad=rightPad=0;
    94 
    95 	repositionRequest=false;
    96 
    97 	// Rel Positions
    98 	relPos=QPointF(0,0);
    99 	useRelPos=false;
   100 }
   101 
   102 void LinkableMapObj::copy (LinkableMapObj* other)
   103 {
   104     MapObj::copy(other);
   105 	bboxTotal=other->bboxTotal;
   106     setLinkStyle(other->style);
   107     setLinkColor (other->linkcolor);
   108 	relPos=other->relPos;
   109 	treeItem=other->treeItem;
   110 }
   111 
   112 void LinkableMapObj::setParObj(LinkableMapObj* o)
   113 {
   114     parObj=o;
   115 }
   116 
   117 void LinkableMapObj::setParObjTmp(LinkableMapObj*,QPointF,int)	// FIXME-3 make pure virtual
   118 {
   119 }
   120 
   121 void LinkableMapObj::unsetParObjTmp()	// FIXME-3 make pure virtual
   122 {
   123 }
   124 
   125 bool LinkableMapObj::hasParObjTmp()
   126 {
   127 	return tmpParent;
   128 }
   129 
   130 void LinkableMapObj::setUseRelPos (const bool &b)
   131 {
   132 	useRelPos=b;
   133 }
   134 
   135 bool LinkableMapObj::getUseRelPos ()
   136 {
   137 	return useRelPos;
   138 }
   139 
   140 void LinkableMapObj::setRelPos()
   141 {
   142 	if (parObj)
   143 	{	
   144 		setRelPos (absPos - parObj->getChildPos() );
   145 	}	else
   146 		qWarning ("LMO::setRelPos() parObj==0");
   147 }
   148 
   149 void LinkableMapObj::setRelPos(const QPointF &p)
   150 {
   151 	if (parObj)
   152 	{		
   153 		relPos=p;
   154 		useRelPos=true;
   155 		parObj->calcBBoxSize();
   156 		requestReposition();
   157 	}	else
   158 		qWarning ("LMO::setRelPos (p) parObj==0");
   159 }
   160 
   161 QPointF LinkableMapObj::getRelPos()
   162 {
   163 	if (!parObj) 
   164 	{
   165 		qWarning("LMO::getRelPos parObj==0");
   166 		return QPointF();
   167 	}
   168 	return relPos;
   169 }
   170 
   171 qreal LinkableMapObj::getTopPad()
   172 {
   173 	return topPad;
   174 }
   175 
   176 qreal LinkableMapObj::getLeftPad()
   177 {
   178 	return leftPad;
   179 }
   180 
   181 qreal LinkableMapObj::getRightPad()
   182 {
   183 	return rightPad;
   184 }
   185 
   186 LinkableMapObj::Style LinkableMapObj::getDefLinkStyle (TreeItem *parent)
   187 {
   188 	VymModel *model=treeItem->getModel();
   189 	if (!model)
   190 	{
   191 		qWarning ("LMO::getDefLinkStyle   model=NULL");
   192 		//return UndefinedStyle;
   193 	}
   194 	Style ls=model->getMapLinkStyle();
   195 	int depth=1+parent->depth();
   196 	if (depth==0) return UndefinedStyle;
   197 	switch (ls)
   198 	{
   199 		case Line: 
   200 			return ls;
   201 			break;
   202 		case Parabel:
   203 			return ls;
   204 			break;
   205 		case PolyLine:	
   206 			if (depth>1)
   207 				return Line;
   208 			else	
   209 				return ls;
   210 			break;
   211 		case PolyParabel:	
   212 			if (depth>1)
   213 				return Parabel;
   214 			else	
   215 				return ls;
   216 			break;
   217 		default: 
   218 			break;	
   219 	}	
   220 	return UndefinedStyle;
   221 }
   222 
   223 void LinkableMapObj::setLinkStyle(Style newstyle)
   224 {
   225 	delLink();
   226 		
   227 	style=newstyle;
   228 
   229     if (parObj != NULL)
   230     {
   231 		QGraphicsLineItem *cl;
   232 		switch (style)
   233 		{
   234 			case UndefinedStyle:
   235 				bottomline->hide();
   236 				break;
   237 			case Line: 
   238 				l = scene->addLine(QLineF(1,1,1,1),pen);
   239 				l->setZValue(Z_LINK);
   240 				if (visible)
   241 					l->show();
   242 				else
   243 					l->hide();
   244 				break;
   245 			case Parabel:
   246 				for (int i=0;i<arcsegs;i++)
   247 				{
   248 					cl = scene->addLine(QLineF(i*5,0,i*10,100),pen);
   249 					cl->setZValue(Z_LINK);
   250 					if (visible)
   251 						cl->show();
   252 					else
   253 						cl->hide();
   254 					segment.append(cl);
   255 				}
   256 				pa0.resize (arcsegs+1);
   257 				break;
   258 			case PolyLine:	
   259 				p =scene->addPolygon(QPolygonF(),pen,linkcolor);
   260 				p->setZValue(Z_LINK);
   261 				if (visible)
   262 					p->show();
   263 				else
   264 					p->hide();
   265 				pa0.resize (3);
   266 				break;
   267 			case PolyParabel:	
   268 				p = scene->addPolygon(QPolygonF(),pen,linkcolor);
   269 				p->setZValue(Z_LINK);
   270 				if (visible)
   271 					p->show();
   272 				else
   273 					p->hide();
   274 				pa0.resize (arcsegs*2+2);
   275 				pa1.resize (arcsegs+1);
   276 				pa2.resize (arcsegs+1);
   277 				break;
   278 			default: 
   279 				break;	
   280 		}	
   281 	} 
   282 }
   283 
   284 LinkableMapObj::Style LinkableMapObj::getLinkStyle()
   285 {
   286 	return style;
   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 		if (useBottomline)
   382 			bottomline->show();
   383 		else	
   384 			bottomline->hide();
   385 
   386 		switch (style)
   387 		{
   388 			case Line:
   389 				if (l) l->show();
   390 				break;
   391 			case Parabel:	
   392 				for (int i=0; i<segment.size(); ++i)
   393 					segment.at(i)->show();
   394 				break;	
   395 			case PolyLine:
   396 				if (!p) cout << "LMO::updateVis p==0 (PolyLine)\n"; //FIXME-3
   397 				if (p) p->show();
   398 				break;
   399 			case PolyParabel:	
   400 				if (!p) cout << "LMO::updateVis p==0 (PolyParabel) "<<treeItem->getHeading().toStdString()<<endl; //FIXME-3
   401 				if (p) p->show();
   402 				break;
   403 			default:
   404 				break;
   405 		}
   406 	} else 
   407 	{
   408 		bottomline->hide();
   409 		switch (style)
   410 		{
   411 			case Line:
   412 				if (l) l->hide();
   413 				break;
   414 			case Parabel:	
   415 				for (int i=0; i<segment.size(); ++i)
   416 					segment.at(i)->hide();
   417 				break;	
   418 			case PolyLine:
   419 				if (p) p->hide();
   420 				break;
   421 			case PolyParabel:	
   422 				if (p) p->hide();
   423 				break;
   424 			default:
   425 				break;
   426 		}
   427 	}	
   428 }
   429 
   430 void LinkableMapObj::updateLinkGeometry()
   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 	// updateLinkGeometry is called from move, but called from constructor we don't
   445 	// have parents yet...
   446 
   447 	//cout <<"LMO::updateLinkGeometry: "<<treeItem->getHeadingStd()<<"  "<<parObj<<endl;
   448 	if (!parObj)	
   449 	{
   450 		// If I am a mapcenter, set childPos to middle of MapCenterObj
   451 		childPos.setX( clickBox.topLeft().x() + clickBox.width()/2 );
   452 		childPos.setY( clickBox.topLeft().y() + clickBox.height()/2 );
   453 		parPos=childPos;		
   454 		// Redraw links to children
   455 		for (int i=0; i<treeItem->branchCount(); ++i)
   456 			treeItem->getBranchObjNum(i)->updateLinkGeometry();
   457 		return;	
   458 	}
   459 
   460 	if (style==UndefinedStyle) return;	
   461 
   462 	switch (linkpos)
   463 	{
   464 		case Middle:
   465 			bottomlineY=bbox.top() + bbox.height()/2;	// draw link to middle (of frame)
   466 			break;
   467 		case Bottom:
   468 			//bottomlineY=bbox.bottom()-1;	// draw link to bottom of box
   469 			bottomlineY=bbox.bottom()-botPad;
   470 			break;
   471 	}
   472 	
   473     double p2x,p2y;								// Set P2 Before setting
   474 	if (!link2ParPos)
   475 	{
   476 		p2x=QPointF( parObj->getChildPos() ).x();	// P1, we have to look at
   477 		p2y=QPointF( parObj->getChildPos() ).y();	// orientation
   478 	} else	
   479 	{
   480 		p2x=QPointF( parObj->getParPos() ).x();	
   481 		p2y=QPointF( parObj->getParPos() ).y();
   482 	} 
   483 
   484 	setDockPos(); // Call overloaded method
   485 	setOrientation();
   486 
   487 	double p1x=parPos.x();	// Link is drawn from P1 to P2
   488 	double p1y=parPos.y();
   489 
   490 	double vx=p2x - p1x;	// V=P2-P1
   491 	double vy=p2y - p1y;
   492 
   493 	// Draw the horizontal line below heading (from ChildPos to ParPos)
   494 	bottomline->setLine (QLine (qRound(childPos.x()),
   495 		qRound(childPos.y()),
   496 		qRound(p1x),
   497 		qRound(p1y) ));
   498 
   499 	double a;	// angle
   500 	if (vx > -0.000001 && vx < 0.000001)
   501 		a=M_PI_2;
   502 	else
   503 		a=atan( vy / vx );
   504 	// "turning point" for drawing polygonal links
   505 	QPointF tp (-qRound(sin (a)*thickness_start), qRound(cos (a)*thickness_start));	
   506 	
   507     // Draw the link
   508 	switch (style)
   509 	{
   510 		case Line:
   511 			l->setLine( QLine(qRound (parPos.x()),
   512 				qRound(parPos.y()),
   513 				qRound(p2x),
   514 				qRound(p2y) ));
   515 			break;	
   516 		case Parabel:	
   517 			parabel (pa0, p1x,p1y,p2x,p2y);
   518 			for (int i=0; i<segment.size(); ++i)
   519 				segment.at(i)->setLine(QLineF( pa0.at(i).x(), pa0.at(i).y(),pa0.at(i+1).x(),pa0.at(i+1).y()));
   520 			break;
   521 		case PolyLine:
   522 			pa0.clear();
   523 			pa0<<QPointF (qRound(p2x+tp.x()), qRound(p2y+tp.y()));
   524 			pa0<<QPointF (qRound(p2x-tp.x()), qRound(p2y-tp.y()));
   525 			pa0<<QPointF (qRound (parPos.x()), qRound(parPos.y()) );
   526 			p->setPolygon(QPolygonF (pa0));
   527 			break;
   528 		case PolyParabel:	
   529 			parabel (pa1, p1x,p1y,p2x+tp.x(),p2y+tp.y());
   530 			parabel (pa2, p1x,p1y,p2x-tp.x(),p2y-tp.y());
   531 			pa0.clear();
   532 			for (int i=0;i<=arcsegs;i++)
   533 				pa0 << QPointF (pa1.at(i));
   534 			for (int i=0;i<=arcsegs;i++)
   535 				pa0 << QPointF (pa2.at(arcsegs-i));
   536 			p->setPolygon(QPolygonF (pa0));
   537 			break;
   538 		default:
   539 			break;
   540 	} 
   541 }
   542 	
   543 LinkableMapObj* LinkableMapObj::getParObj()
   544 {
   545     return parObj;
   546 }
   547 
   548 QPointF LinkableMapObj::getChildPos()
   549 {
   550     return childPos;
   551 }
   552 
   553 QPointF LinkableMapObj::getParPos()
   554 {
   555     return parPos;
   556 }
   557 
   558 LinkableMapObj::Orientation LinkableMapObj::getOrientation()
   559 {
   560     return orientation;
   561 }
   562 
   563 QPointF LinkableMapObj::getRandPos()
   564 {
   565 	// Choose a random position with given distance to parent:
   566 	double a=rand()%360 * 2 * M_PI / 360;
   567     return QPointF ( (int)( + 150*cos (a)),
   568                     (int)( + 150*sin (a)));
   569 }
   570 
   571 void LinkableMapObj::reposition()
   572 {
   573 }
   574 
   575 void LinkableMapObj::requestReposition()	//FIXME-3 needed?
   576 {
   577 	if (!repositionRequest)
   578 	{
   579 		// Pass on the request to parental objects, if this hasn't
   580 		// been done yet
   581 		repositionRequest=true;
   582 		if (parObj) parObj->requestReposition();
   583 	}
   584 }
   585 
   586 void LinkableMapObj::forceReposition()
   587 {
   588 	// Sometimes a reposition has to be done immediatly: For example
   589 	// if the note editor flag changes, there is no user event in mapeditor
   590 	// which could collect requests for a reposition.
   591 	// Then we have to call forceReposition()
   592 	// But no rule without exception: While loading a map or undoing it,
   593 	// we want to block expensive repositioning, but just do it once at
   594 	// the end, thus check first:
   595 
   596 	VymModel *model=treeItem->getModel();
   597 	if (model->isRepositionBlocked()) return;	
   598 	
   599 	// Pass on the request to parent objects, if this hasn't been done yet
   600 	if (parObj) 
   601 		parObj->forceReposition(); 
   602 	else 
   603 		reposition(); 
   604 }
   605 
   606 bool LinkableMapObj::repositionRequested()
   607 {
   608 	return repositionRequest;
   609 }
   610 
   611 void LinkableMapObj::parabel (QPolygonF &ya, double p1x, double p1y, double p2x, double p2y)
   612 
   613 {
   614 	double vx=p2x - p1x;	// V=P2-P1
   615 	double vy=p2y - p1y;
   616 
   617 	double dx;				// delta x during calculation of parabel
   618 	
   619 	double pnx;				// next point
   620 	double pny;
   621 	double m;
   622 
   623 	if (vx > -0.0001 && vx < 0.0001)
   624 		m=0;
   625 	else	
   626 		m=(vy / (vx*vx));
   627 	dx=vx/(arcsegs);
   628 	ya.clear();
   629 	ya<<QPointF (p1x,p1y);
   630 	for (int i=1;i<=arcsegs;i++)
   631 	{	
   632 		pnx=p1x+dx;
   633 		pny=m*(pnx-parPos.x())*(pnx-parPos.x())+parPos.y();
   634 		ya<<QPointF (pnx,pny);
   635 		p1x=pnx;
   636 		p1y=pny;
   637 	}	
   638 }
   639