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