linkablemapobj.cpp
author insilmaril
Fri, 09 Apr 2010 14:24:04 +0000
changeset 846 f0fe7c36ec5c
parent 836 62d621e3e550
child 847 43268373032d
permissions -rw-r--r--
Version 1.13.3 and added treeeditor.png
     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\n";
    36     delete (bottomline);
    37 	delLink();
    38 }
    39 
    40 void LinkableMapObj::delLink()
    41 {
    42 	//bottomline->hide();
    43 	switch (style)
    44 	{
    45 		case Line:
    46 			delete (l);
    47 			break;
    48 		case Parabel:
    49 			while (!segment.isEmpty()) delete segment.takeFirst();
    50 			break;
    51 		case PolyLine:
    52 			delete (p);
    53 			break;
    54 		case PolyParabel:
    55 			delete (p);
    56 			break;
    57 		default:
    58 			break;
    59 	}		
    60 }
    61 
    62 void LinkableMapObj::init ()
    63 {
    64     parObj=NULL;
    65     parObjTmpBuf=NULL;
    66 	tmpParent=false;
    67     parPos=QPointF(0,0);
    68     childPos=QPointF(0,0);
    69 	link2ParPos=false;
    70     l=NULL;
    71 	p=NULL;
    72     orientation=UndefinedOrientation;
    73     linkwidth=20;		
    74 	thickness_start=8;
    75     style=UndefinedStyle;
    76 	linkpos=Bottom;
    77     arcsegs=13;
    78     
    79 // TODO instead of linkcolor pen.color() could be used	all around
    80 	pen.setWidth (1);
    81 	pen.setColor (linkcolor);
    82 	pen.setCapStyle ( Qt::RoundCap );
    83 
    84 	useBottomline=true;
    85 	bottomline=scene->addLine(QLineF(1,1,1,1),pen);
    86     bottomline->setZValue(Z_LINK);
    87     bottomline->show();
    88 
    89 	topPad=botPad=leftPad=rightPad=0;
    90 
    91 	repositionRequest=false;
    92 
    93 	// Rel Positions
    94 	relPos=QPointF(0,0);
    95 	useRelPos=false;
    96 }
    97 
    98 void LinkableMapObj::copy (LinkableMapObj* other)
    99 {
   100     MapObj::copy(other);
   101 	bboxTotal=other->bboxTotal;
   102     setLinkStyle(other->style);
   103     setLinkColor (other->linkcolor);
   104 	relPos=other->relPos;
   105 	treeItem=other->treeItem;
   106 }
   107 
   108 void LinkableMapObj::setParObj(LinkableMapObj* o)
   109 {
   110     parObj=o;
   111 }
   112 
   113 void LinkableMapObj::setParObjTmp(LinkableMapObj*,QPointF,int)	// FIXME-3 make pure virtual
   114 {
   115 }
   116 
   117 void LinkableMapObj::unsetParObjTmp()	// FIXME-3 make pure virtual
   118 {
   119 }
   120 
   121 bool LinkableMapObj::hasParObjTmp()
   122 {
   123 	return tmpParent;
   124 }
   125 
   126 void LinkableMapObj::setUseRelPos (const bool &b)
   127 {
   128 	useRelPos=b;
   129 }
   130 
   131 bool LinkableMapObj::getUseRelPos ()
   132 {
   133 	return useRelPos;
   134 }
   135 
   136 void LinkableMapObj::setRelPos()
   137 {
   138 	if (parObj)
   139 	{	
   140 		setRelPos (absPos - parObj->getChildPos() );
   141 	}	else
   142 		qWarning ("LMO::setRelPos() parObj==0");
   143 }
   144 
   145 void LinkableMapObj::setRelPos(const QPointF &p)
   146 {
   147 	if (parObj)
   148 	{		
   149 		relPos=p;
   150 		useRelPos=true;
   151 		parObj->calcBBoxSize();
   152 		requestReposition();
   153 	}	else
   154 		qWarning ("LMO::setRelPos (p) parObj==0");
   155 }
   156 
   157 QPointF LinkableMapObj::getRelPos()
   158 {
   159 	if (!parObj) 
   160 	{
   161 		qWarning("LMO::getRelPos parObj==0");
   162 		return QPointF();
   163 	}
   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 (TreeItem *parent)
   183 {
   184 	VymModel *model=treeItem->getModel();
   185 	if (!model)
   186 	{
   187 		qWarning ("LMO::getDefLinkStyle   model=NULL");
   188 		//return UndefinedStyle;
   189 	}
   190 	Style ls=model->getMapLinkStyle();
   191 	int depth=1+parent->depth();
   192 	if (depth==0) return UndefinedStyle;
   193 	switch (ls)
   194 	{
   195 		case Line: 
   196 			return ls;
   197 			break;
   198 		case Parabel:
   199 			return ls;
   200 			break;
   201 		case PolyLine:	
   202 			if (depth>1)
   203 				return Line;
   204 			else	
   205 				return ls;
   206 			break;
   207 		case PolyParabel:	
   208 			if (depth>1)
   209 				return Parabel;
   210 			else	
   211 				return ls;
   212 			break;
   213 		default: 
   214 			break;	
   215 	}	
   216 	return UndefinedStyle;
   217 }
   218 
   219 void LinkableMapObj::setLinkStyle(Style newstyle)
   220 {
   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::setLinkPos(Position lp)
   286 {
   287 	linkpos=lp;
   288 }
   289 
   290 LinkableMapObj::Position LinkableMapObj::getLinkPos()
   291 {
   292 	return linkpos;
   293 }
   294 
   295 void LinkableMapObj::setLinkColor()
   296 {
   297 	// Overloaded in BranchObj and children
   298 	// here only set default color
   299 	VymModel *model=treeItem->getModel();
   300 	if (model)
   301 		setLinkColor (model->getMapDefLinkColor());
   302 }
   303 
   304 void LinkableMapObj::setLinkColor(QColor col)
   305 {
   306 	linkcolor=col;
   307 	pen.setColor(col);
   308     bottomline->setPen( pen );
   309 	switch (style)
   310 	{
   311 		case Line:
   312 			l->setPen( pen);
   313 			break;	
   314 		case Parabel:	
   315 			for (int i=0; i<segment.size(); ++i)
   316 				segment.at(i)->setPen( pen);
   317 			break;
   318 		case PolyLine:
   319 			p->setBrush( QBrush(col));
   320 			p->setPen( pen);
   321 			break;
   322 		case PolyParabel:	
   323 			p->setBrush( QBrush(col));
   324 			p->setPen( pen);
   325 			break;
   326 		default:
   327 			break;
   328 	} 
   329 }
   330 
   331 QColor LinkableMapObj::getLinkColor()
   332 {
   333 	return linkcolor;
   334 }
   335 
   336 void LinkableMapObj::setVisibility (bool v)
   337 {
   338 	MapObj::setVisibility (v);
   339 	updateVisibility();
   340 }
   341 
   342 void LinkableMapObj::setOrientation()
   343 {
   344 	Orientation orientOld=orientation;
   345 
   346 	if (!parObj) 
   347 	{
   348 		orientation=UndefinedOrientation;
   349 		return;
   350 	}
   351 		
   352     // Set orientation, first look for orientation of parent
   353     if (parObj->getOrientation() != UndefinedOrientation ) 
   354 		// use the orientation of the parent:
   355 		orientation=parObj->getOrientation();
   356     else
   357     {
   358 		// calc orientation depending on position rel to parent
   359 		if (absPos.x() < QPointF(parObj->getChildPos() ).x() )
   360 			orientation=LeftOfCenter; 
   361 		else
   362 			orientation=RightOfCenter;
   363     }
   364 	if (orientOld!=orientation) requestReposition();
   365 }
   366 
   367 void LinkableMapObj::updateVisibility()
   368 {
   369 	bool visnow=visible;
   370 
   371 	if (((MapItem*)treeItem)->getHideLinkUnselected()
   372 		&& treeItem->getModel()->getSelectedLMO() !=this)
   373 		visnow=false;
   374 
   375 	if (visnow) 
   376 	{
   377 		if (useBottomline)
   378 			bottomline->show();
   379 		else	
   380 			bottomline->hide();
   381 
   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 	//cout <<"LMO::updateLinkGeometry: "<<treeItem->getHeadingStd()<<"  "<<parObj<<endl;
   444 	if (!parObj)	
   445 	{
   446 		// If I am a mapcenter, set childPos to middle of MapCenterObj
   447 		childPos.setX( clickBox.topLeft().x() + clickBox.width()/2 );
   448 		childPos.setY( clickBox.topLeft().y() + clickBox.height()/2 );
   449 		parPos=childPos;		
   450 		// Redraw links to children
   451 		for (int i=0; i<treeItem->branchCount(); ++i)
   452 			treeItem->getBranchObjNum(i)->updateLinkGeometry();
   453 		return;	
   454 	}
   455 
   456 	if (style==UndefinedStyle) return;	
   457 
   458 	switch (linkpos)
   459 	{
   460 		case Middle:
   461 			bottomlineY=bbox.top() + bbox.height()/2;	// draw link to middle (of frame)
   462 			break;
   463 		case Bottom:
   464 			//bottomlineY=bbox.bottom()-1;	// draw link to bottom of box
   465 			bottomlineY=bbox.bottom()-botPad;
   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->setLine (QLine (qRound(childPos.x()),
   491 		qRound(childPos.y()),
   492 		qRound(p1x),
   493 		qRound(p1y) ));
   494 
   495 	double a;	// angle
   496 	if (vx > -0.000001 && vx < 0.000001)
   497 		a=M_PI_2;
   498 	else
   499 		a=atan( vy / vx );
   500 	// "turning point" for drawing polygonal links
   501 	QPointF tp (-qRound(sin (a)*thickness_start), qRound(cos (a)*thickness_start));	
   502 	
   503     // Draw the link
   504 	switch (style)
   505 	{
   506 		case Line:
   507 			l->setLine( QLine(qRound (parPos.x()),
   508 				qRound(parPos.y()),
   509 				qRound(p2x),
   510 				qRound(p2y) ));
   511 			break;	
   512 		case Parabel:	
   513 			parabel (pa0, p1x,p1y,p2x,p2y);
   514 			for (int i=0; i<segment.size(); ++i)
   515 				segment.at(i)->setLine(QLineF( pa0.at(i).x(), pa0.at(i).y(),pa0.at(i+1).x(),pa0.at(i+1).y()));
   516 			break;
   517 		case PolyLine:
   518 			pa0.clear();
   519 			pa0<<QPointF (qRound(p2x+tp.x()), qRound(p2y+tp.y()));
   520 			pa0<<QPointF (qRound(p2x-tp.x()), qRound(p2y-tp.y()));
   521 			pa0<<QPointF (qRound (parPos.x()), qRound(parPos.y()) );
   522 			p->setPolygon(QPolygonF (pa0));
   523 			break;
   524 		case PolyParabel:	
   525 			parabel (pa1, p1x,p1y,p2x+tp.x(),p2y+tp.y());
   526 			parabel (pa2, p1x,p1y,p2x-tp.x(),p2y-tp.y());
   527 			pa0.clear();
   528 			for (int i=0;i<=arcsegs;i++)
   529 				pa0 << QPointF (pa1.at(i));
   530 			for (int i=0;i<=arcsegs;i++)
   531 				pa0 << QPointF (pa2.at(arcsegs-i));
   532 			p->setPolygon(QPolygonF (pa0));
   533 			break;
   534 		default:
   535 			break;
   536 	} 
   537 }
   538 	
   539 LinkableMapObj* LinkableMapObj::getParObj()
   540 {
   541     return parObj;
   542 }
   543 
   544 QPointF LinkableMapObj::getChildPos()
   545 {
   546     return childPos;
   547 }
   548 
   549 QPointF LinkableMapObj::getParPos()
   550 {
   551     return parPos;
   552 }
   553 
   554 LinkableMapObj::Orientation LinkableMapObj::getOrientation()
   555 {
   556     return orientation;
   557 }
   558 
   559 QPointF LinkableMapObj::getRandPos()
   560 {
   561 	// Choose a random position with given distance to parent:
   562 	double a=rand()%360 * 2 * M_PI / 360;
   563     return QPointF ( (int)( + 150*cos (a)),
   564                     (int)( + 150*sin (a)));
   565 }
   566 
   567 void LinkableMapObj::reposition()
   568 {
   569 }
   570 
   571 void LinkableMapObj::requestReposition()	//FIXME-3 needed?
   572 {
   573 	if (!repositionRequest)
   574 	{
   575 		// Pass on the request to parental objects, if this hasn't
   576 		// been done yet
   577 		repositionRequest=true;
   578 		if (parObj) parObj->requestReposition();
   579 	}
   580 }
   581 
   582 void LinkableMapObj::forceReposition()
   583 {
   584 	// Sometimes a reposition has to be done immediatly: For example
   585 	// if the note editor flag changes, there is no user event in mapeditor
   586 	// which could collect requests for a reposition.
   587 	// Then we have to call forceReposition()
   588 	// But no rule without exception: While loading a map or undoing it,
   589 	// we want to block expensive repositioning, but just do it once at
   590 	// the end, thus check first:
   591 
   592 	VymModel *model=treeItem->getModel();
   593 	if (model->isRepositionBlocked()) return;	
   594 	
   595 	// Pass on the request to parent objects, if this hasn't been done yet
   596 	if (parObj) 
   597 		parObj->forceReposition(); 
   598 	else 
   599 		reposition(); 
   600 }
   601 
   602 bool LinkableMapObj::repositionRequested()
   603 {
   604 	return repositionRequest;
   605 }
   606 
   607 void LinkableMapObj::parabel (QPolygonF &ya, double p1x, double p1y, double p2x, double p2y)
   608 
   609 {
   610 	double vx=p2x - p1x;	// V=P2-P1
   611 	double vy=p2y - p1y;
   612 
   613 	double dx;				// delta x during calculation of parabel
   614 	
   615 	double pnx;				// next point
   616 	double pny;
   617 	double m;
   618 
   619 	if (vx > -0.0001 && vx < 0.0001)
   620 		m=0;
   621 	else	
   622 		m=(vy / (vx*vx));
   623 	dx=vx/(arcsegs);
   624 	ya.clear();
   625 	ya<<QPointF (p1x,p1y);
   626 	for (int i=1;i<=arcsegs;i++)
   627 	{	
   628 		pnx=p1x+dx;
   629 		pny=m*(pnx-parPos.x())*(pnx-parPos.x())+parPos.y();
   630 		ya<<QPointF (pnx,pny);
   631 		p1x=pnx;
   632 		p1y=pny;
   633 	}	
   634 }
   635