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