Exemple #1
0
void cc2DLabel::drawMeOnly2D(CC_DRAW_CONTEXT& context)
{
	if (!m_dispIn2D)
		return;

	assert(!m_points.empty());

	//get the set of OpenGL functions (version 2.1)
	QOpenGLFunctions_2_1 *glFunc = context.glFunctions<QOpenGLFunctions_2_1>();
	assert( glFunc != nullptr );
	
	if ( glFunc == nullptr )
		return;

	//standard case: list names pushing
	bool pushName = MACRO_DrawEntityNames(context);
	if (pushName)
	{
		glFunc->glPushName(getUniqueID());
	}

	//we should already be in orthoprojective & centered omde
	//glFunc->glOrtho(-halfW,halfW,-halfH,halfH,-maxS,maxS);

	//label title
	const int precision = context.dispNumberPrecision;
	QString title = getTitle(precision);

#define DRAW_CONTENT_AS_TAB
#ifdef DRAW_CONTENT_AS_TAB
	//draw contents as an array
	Tab tab(4);
	int rowHeight = 0;
#else
//simply display the content as text
	QStringList body;
#endif

	//render zoom
	int margin        = static_cast<int>(c_margin        * context.renderZoom);
	int tabMarginX    = static_cast<int>(c_tabMarginX    * context.renderZoom);
	int tabMarginY    = static_cast<int>(c_tabMarginY    * context.renderZoom);
	int arrowBaseSize = static_cast<int>(c_arrowBaseSize * context.renderZoom);
	
	int titleHeight = 0;
	GLdouble arrowDestX = -1.0, arrowDestY = -1.0;
	QFont bodyFont,titleFont;
	if (!pushName)
	{
		/*** line from 2D point to label ***/

		//compute arrow head position
		CCVector3 arrowDest;
		m_points[0].cloud->getPoint(m_points[0].index,arrowDest);
		for (unsigned i = 1; i < m_points.size(); ++i)
		{
			arrowDest += *m_points[i].cloud->getPointPersistentPtr(m_points[i].index);
		}
		arrowDest /= static_cast<PointCoordinateType>(m_points.size());

		//project it in 2D screen coordinates
		{
			ccGLCameraParameters camera;
			context.display->getGLCameraParameters(camera);

			CCVector3d Q2D;
			camera.project(arrowDest, Q2D);
			arrowDestX = Q2D.x;
			arrowDestY = Q2D.y;
		}

		/*** label border ***/
		bodyFont = context.display->getLabelDisplayFont(); //takes rendering zoom into account!
		titleFont = bodyFont; //takes rendering zoom into account!
		//titleFont.setBold(true);

		QFontMetrics titleFontMetrics(titleFont);
		titleHeight = titleFontMetrics.height();

		QFontMetrics bodyFontMetrics(bodyFont);
		rowHeight = bodyFontMetrics.height();

		//get label box dimension
		int dx = 100;
		int dy = 0;
		//int buttonSize    = static_cast<int>(c_buttonSize * context.renderZoom);
		{
			//base box dimension
			dx = std::max(dx,titleFontMetrics.width(title));
			dy += margin;		//top vertical margin
			dy += titleHeight;	//title

			if (m_showFullBody)
			{
#ifdef DRAW_CONTENT_AS_TAB
				try
				{
					size_t labelCount = m_points.size();
					if (labelCount == 1)
					{
						LabelInfo1 info;
						getLabelInfo1(info);

						bool isShifted = info.cloud->isShifted();
						//1st block: X, Y, Z (local)
						{
							int c = tab.add2x3Block();
							QChar suffix;
							if (isShifted)
								suffix = 'l'; //'l' for local
							const CCVector3* P = info.cloud->getPoint(info.pointIndex);
							tab.colContent[c] << QString("X") + suffix; tab.colContent[c+1] << QString::number(P->x,'f',precision);
							tab.colContent[c] << QString("Y") + suffix; tab.colContent[c+1] << QString::number(P->y,'f',precision);
							tab.colContent[c] << QString("Z") + suffix; tab.colContent[c+1] << QString::number(P->z,'f',precision);
						}
						//next block:  X, Y, Z (global)
						if (isShifted)
						{
							int c = tab.add2x3Block();
							CCVector3d P = info.cloud->toGlobal3d(*info.cloud->getPoint(info.pointIndex));
							tab.colContent[c] << "Xg"; tab.colContent[c+1] << QString::number(P.x,'f',precision);
							tab.colContent[c] << "Yg"; tab.colContent[c+1] << QString::number(P.y,'f',precision);
							tab.colContent[c] << "Zg"; tab.colContent[c+1] << QString::number(P.z,'f',precision);
						}
						//next block: normal
						if (info.hasNormal)
						{
							int c = tab.add2x3Block();
							tab.colContent[c] << "Nx"; tab.colContent[c+1] << QString::number(info.normal.x,'f',precision);
							tab.colContent[c] << "Ny"; tab.colContent[c+1] << QString::number(info.normal.y,'f',precision);
							tab.colContent[c] << "Nz"; tab.colContent[c+1] << QString::number(info.normal.z,'f',precision);
						}

						//next block: RGB color
						if (info.hasRGB)
						{
							int c = tab.add2x3Block();
							tab.colContent[c] <<"R"; tab.colContent[c+1] << QString::number(info.rgb.x);
							tab.colContent[c] <<"G"; tab.colContent[c+1] << QString::number(info.rgb.y);
							tab.colContent[c] <<"B"; tab.colContent[c+1] << QString::number(info.rgb.z);
						}
					}
					else if (labelCount == 2)
					{
						LabelInfo2 info;
						getLabelInfo2(info);

						//1st block: dX, dY, dZ
						{
							int c = tab.add2x3Block();
							tab.colContent[c] << MathSymbolDelta + QString("X"); tab.colContent[c+1] << QString::number(info.diff.x,'f',precision);
							tab.colContent[c] << MathSymbolDelta + QString("Y"); tab.colContent[c+1] << QString::number(info.diff.y,'f',precision);
							tab.colContent[c] << MathSymbolDelta + QString("Z"); tab.colContent[c+1] << QString::number(info.diff.z,'f',precision);
						}
						//2nd block: dXY, dXZ, dZY
						{
							int c = tab.add2x3Block();
							PointCoordinateType dXY = sqrt(info.diff.x*info.diff.x + info.diff.y*info.diff.y);
							PointCoordinateType dXZ = sqrt(info.diff.x*info.diff.x + info.diff.z*info.diff.z);
							PointCoordinateType dZY = sqrt(info.diff.z*info.diff.z + info.diff.y*info.diff.y);
							tab.colContent[c] << MathSymbolDelta + QString("XY"); tab.colContent[c+1] << QString::number(dXY,'f',precision);
							tab.colContent[c] << MathSymbolDelta + QString("XZ"); tab.colContent[c+1] << QString::number(dXZ,'f',precision);
							tab.colContent[c] << MathSymbolDelta + QString("ZY"); tab.colContent[c+1] << QString::number(dZY,'f',precision);
						}
					}
					else if (labelCount == 3)
					{
						LabelInfo3 info;
						getLabelInfo3(info);
						tab.setMaxBlockPerRow(2); //square tab (2x2 blocks)

						//next block: indexes
						{
							int c = tab.add2x3Block();
							tab.colContent[c] << "index.A"; tab.colContent[c+1] << QString::number(info.point1Index);
							tab.colContent[c] << "index.B"; tab.colContent[c+1] << QString::number(info.point2Index);
							tab.colContent[c] << "index.C"; tab.colContent[c+1] << QString::number(info.point3Index);
						}
						//next block: edges length
						{
							int c = tab.add2x3Block();
							tab.colContent[c] << "AB"; tab.colContent[c+1] << QString::number(info.edges.u[0],'f',precision);
							tab.colContent[c] << "BC"; tab.colContent[c+1] << QString::number(info.edges.u[1],'f',precision);
							tab.colContent[c] << "CA"; tab.colContent[c+1] << QString::number(info.edges.u[2],'f',precision);
						}
						//next block: angles
						{
							int c = tab.add2x3Block();
							tab.colContent[c] << "angle.A"; tab.colContent[c+1] << QString::number(info.angles.u[0],'f',precision);
							tab.colContent[c] << "angle.B"; tab.colContent[c+1] << QString::number(info.angles.u[1],'f',precision);
							tab.colContent[c] << "angle.C"; tab.colContent[c+1] << QString::number(info.angles.u[2],'f',precision);
						}
						//next block: normal
						{
							int c = tab.add2x3Block();
							tab.colContent[c] << "Nx"; tab.colContent[c+1] << QString::number(info.normal.x,'f',precision);
							tab.colContent[c] << "Ny"; tab.colContent[c+1] << QString::number(info.normal.y,'f',precision);
							tab.colContent[c] << "Nz"; tab.colContent[c+1] << QString::number(info.normal.z,'f',precision);
						}
					}
				}
				catch (const std::bad_alloc&)
				{
					//not enough memory
					return;
				}

				//compute min width of each column
				int totalWidth = tab.updateColumnsWidthTable(bodyFontMetrics);

				int tabWidth = totalWidth + tab.colCount * (2*tabMarginX); //add inner margins
				dx = std::max(dx,tabWidth);
				dy += tab.rowCount * (rowHeight + 2*tabMarginY); //add inner margins
				//we also add a margin every 3 rows
				dy += std::max(0,(tab.rowCount/3)-1) * margin;
				dy += margin;		//bottom vertical margin
#else
				body = getLabelContent(precision);
				if (!body.empty())
				{
					dy += margin;	//vertical margin above separator
					for (int j=0; j<body.size(); ++j)
					{
						dx = std::max(dx,bodyFontMetrics.width(body[j]));
						dy += rowHeight; //body line height
					}
					dy += margin;	//vertical margin below text
				}
#endif //DRAW_CONTENT_AS_TAB
			}

			dx += margin*2;	// horizontal margins
		}

		//main rectangle
		m_labelROI = QRect(0,0,dx,dy);

		//close button
		//m_closeButtonROI.right()   = dx-margin;
		//m_closeButtonROI.left()    = m_closeButtonROI.right()-buttonSize;
		//m_closeButtonROI.bottom()  = margin;
		//m_closeButtonROI.top()     = m_closeButtonROI.bottom()+buttonSize;

		//automatically elide the title
		//title = titleFontMetrics.elidedText(title,Qt::ElideRight,m_closeButtonROI[0]-2*margin);
	}

	int halfW = (context.glW >> 1);
	int halfH = (context.glH >> 1);

	//draw label rectangle
	int xStart = static_cast<int>(context.glW * m_screenPos[0]);
	int yStart = static_cast<int>(context.glH * (1.0f - m_screenPos[1]));

	m_lastScreenPos[0] = xStart;
	m_lastScreenPos[1] = yStart - m_labelROI.height();

	//colors
	bool highlighted = (!pushName && isSelected());
	//default background color
	unsigned char alpha = static_cast<unsigned char>((context.labelOpacity/100.0) * 255);
	ccColor::Rgbaub defaultBkgColor(context.labelDefaultBkgCol,alpha);
	//default border color (mustn't be totally transparent!)
	ccColor::Rgbaub defaultBorderColor(ccColor::red);
	if (!highlighted)
	{
		//apply only half of the transparency
		unsigned char halfAlpha = static_cast<unsigned char>((50.0 + context.labelOpacity/200.0) * 255);
		defaultBorderColor = ccColor::Rgbaub(context.labelDefaultBkgCol,halfAlpha);
	}

	glFunc->glPushAttrib(GL_COLOR_BUFFER_BIT);
	glFunc->glEnable(GL_BLEND);

	glFunc->glMatrixMode(GL_MODELVIEW);
	glFunc->glPushMatrix();
	glFunc->glTranslatef(static_cast<GLfloat>(-halfW + xStart), static_cast<GLfloat>(-halfH + yStart), 0);

	if (!pushName)
	{
		//compute arrow base position relatively to the label rectangle (for 0 to 8)
		int arrowBaseConfig = 0;
		int iArrowDestX = static_cast<int>(arrowDestX)-xStart;
		int iArrowDestY = static_cast<int>(arrowDestY)-yStart;
		{
			if (iArrowDestX < m_labelROI.left()) //left
				arrowBaseConfig += 0;
			else if (iArrowDestX > m_labelROI.right()) //Right
				arrowBaseConfig += 2;
			else  //Middle
				arrowBaseConfig += 1;

			if (iArrowDestY > -m_labelROI.top()) //Top
				arrowBaseConfig += 0;
			else if (iArrowDestY < -m_labelROI.bottom()) //Bottom
				arrowBaseConfig += 6;
			else  //Middle
				arrowBaseConfig += 3;
		}

		//we make the arrow base start from the nearest corner
		if (arrowBaseConfig != 4) //4 = label above point!
		{
			glFunc->glColor4ubv(defaultBorderColor.rgba);
			glFunc->glBegin(GL_TRIANGLE_FAN);
			glFunc->glVertex2d(arrowDestX - xStart, arrowDestY - yStart);
			switch(arrowBaseConfig)
			{
			case 0: //top-left corner
				glFunc->glVertex2i(m_labelROI.left(), -m_labelROI.top()-2*arrowBaseSize);
				glFunc->glVertex2i(m_labelROI.left(), -m_labelROI.top());
				glFunc->glVertex2i(m_labelROI.left()+2*arrowBaseSize, -m_labelROI.top());
				break;
			case 1: //top-middle edge
				glFunc->glVertex2i(std::max(m_labelROI.left(),iArrowDestX-arrowBaseSize), -m_labelROI.top());
				glFunc->glVertex2i(std::min(m_labelROI.right(),iArrowDestX+arrowBaseSize), -m_labelROI.top());
				break;
			case 2: //top-right corner
				glFunc->glVertex2i(m_labelROI.right(), -m_labelROI.top()-2*arrowBaseSize);
				glFunc->glVertex2i(m_labelROI.right(), -m_labelROI.top());
				glFunc->glVertex2i(m_labelROI.right()-2*arrowBaseSize, -m_labelROI.top());
				break;
			case 3: //middle-left edge
				glFunc->glVertex2i(m_labelROI.left(), std::min(-m_labelROI.top(),iArrowDestY+arrowBaseSize));
				glFunc->glVertex2i(m_labelROI.left(), std::max(-m_labelROI.bottom(),iArrowDestY-arrowBaseSize));
				break;
			case 4: //middle of rectangle!
				break;
			case 5: //middle-right edge
				glFunc->glVertex2i(m_labelROI.right(), std::min(-m_labelROI.top(),iArrowDestY+arrowBaseSize));
				glFunc->glVertex2i(m_labelROI.right(), std::max(-m_labelROI.bottom(),iArrowDestY-arrowBaseSize));
				break;
			case 6: //bottom-left corner
				glFunc->glVertex2i(m_labelROI.left(), -m_labelROI.bottom()+2*arrowBaseSize);
				glFunc->glVertex2i(m_labelROI.left(), -m_labelROI.bottom());
				glFunc->glVertex2i(m_labelROI.left()+2*arrowBaseSize, -m_labelROI.bottom());
				break;
			case 7: //bottom-middle edge
				glFunc->glVertex2i(std::max(m_labelROI.left(),iArrowDestX-arrowBaseSize), -m_labelROI.bottom());
				glFunc->glVertex2i(std::min(m_labelROI.right(),iArrowDestX+arrowBaseSize), -m_labelROI.bottom());
				break;
			case 8: //bottom-right corner
				glFunc->glVertex2i(m_labelROI.right(), -m_labelROI.bottom()+2*arrowBaseSize);
				glFunc->glVertex2i(m_labelROI.right(), -m_labelROI.bottom());
				glFunc->glVertex2i(m_labelROI.right()-2*arrowBaseSize, -m_labelROI.bottom());
				break;
			}
			glFunc->glEnd();
		}
	}

	//main rectangle
	glFunc->glColor4ubv(defaultBkgColor.rgba);
	glFunc->glBegin(GL_QUADS);
	glFunc->glVertex2i(m_labelROI.left(),  -m_labelROI.top());
	glFunc->glVertex2i(m_labelROI.left(),  -m_labelROI.bottom());
	glFunc->glVertex2i(m_labelROI.right(), -m_labelROI.bottom());
	glFunc->glVertex2i(m_labelROI.right(), -m_labelROI.top());
	glFunc->glEnd();

	//if (highlighted)
	{
		glFunc->glPushAttrib(GL_LINE_BIT);
		glFunc->glLineWidth(3.0f * context.renderZoom);
		glFunc->glColor4ubv(defaultBorderColor.rgba);
		glFunc->glBegin(GL_LINE_LOOP);
		glFunc->glVertex2i(m_labelROI.left(),  -m_labelROI.top());
		glFunc->glVertex2i(m_labelROI.left(),  -m_labelROI.bottom());
		glFunc->glVertex2i(m_labelROI.right(), -m_labelROI.bottom());
		glFunc->glVertex2i(m_labelROI.right(), -m_labelROI.top());
		glFunc->glEnd();
		glFunc->glPopAttrib();
	}

	//draw close button
	//glFunc->glColor3ubv(ccColor::black);
	//glFunc->glBegin(GL_LINE_LOOP);
	//glFunc->glVertex2i(m_closeButtonROI.left(),-m_closeButtonROI.top());
	//glFunc->glVertex2i(m_closeButtonROI.left(),-m_closeButtonROI.bottom());
	//glFunc->glVertex2i(m_closeButtonROI.right(),-m_closeButtonROI.bottom());
	//glFunc->glVertex2i(m_closeButtonROI.right(),-m_closeButtonROI.top());
	//glFunc->glEnd();
	//glFunc->glBegin(GL_LINES);
	//glFunc->glVertex2i(m_closeButtonROI.left()+2,-m_closeButtonROI.top()+2);
	//glFunc->glVertex2i(m_closeButtonROI.right()-2,-m_closeButtonROI.bottom()-2);
	//glFunc->glVertex2i(m_closeButtonROI.right()-2,-m_closeButtonROI.top()+2);
	//glFunc->glVertex2i(m_closeButtonROI.left()+2,-m_closeButtonROI.bottom()-2);
	//glFunc->glEnd();

	//display text
	if (!pushName)
	{
		int xStartRel = margin;
		int yStartRel = 0;
		yStartRel -= titleHeight;

		ccColor::Rgbub defaultTextColor;
		if (context.labelOpacity < 40)
		{
			//under a given opacity level, we use the default text color instead!
			defaultTextColor = context.textDefaultCol;
		}
		else
		{
			defaultTextColor = ccColor::Rgbub(	255 - context.labelDefaultBkgCol.r,
												255 - context.labelDefaultBkgCol.g,
												255 - context.labelDefaultBkgCol.b);
		}

		//label title
		context.display->displayText(	title,
										xStart+xStartRel,
										yStart+yStartRel,
										ccGenericGLDisplay::ALIGN_DEFAULT,
										0,
										defaultTextColor.rgb,
										&titleFont);
		yStartRel -= margin;
		
		if (m_showFullBody)
		{
#ifdef DRAW_CONTENT_AS_TAB
			int xCol = xStartRel;
			for (int c=0; c<tab.colCount; ++c)
			{
				int width = tab.colWidth[c] + 2*tabMarginX;
				int height = rowHeight + 2*tabMarginY;

				int yRow = yStartRel;
				int actualRowCount = std::min(tab.rowCount,tab.colContent[c].size());

				bool labelCol = ((c & 1) == 0);
				const unsigned char* textColor = labelCol ? ccColor::white.rgba : defaultTextColor.rgb;
				
				for (int r=0; r<actualRowCount; ++r)
				{
					if (r && (r % 3) == 0)
						yRow -= margin;

					if (labelCol)
					{
						//draw background
						int rgbIndex = (r % 3);
						if (rgbIndex == 0)
							glFunc->glColor3ubv(ccColor::red.rgba);
						else if (rgbIndex == 1)
							glFunc->glColor3ubv(c_darkGreen.rgba);
						else if (rgbIndex == 2)
							glFunc->glColor3ubv(ccColor::blue.rgba);

						glFunc->glBegin(GL_QUADS);
						glFunc->glVertex2i(m_labelROI.left() + xCol, -m_labelROI.top() + yRow);
						glFunc->glVertex2i(m_labelROI.left() + xCol, -m_labelROI.top() + yRow - height);
						glFunc->glVertex2i(m_labelROI.left() + xCol + width, -m_labelROI.top() + yRow - height);
						glFunc->glVertex2i(m_labelROI.left() + xCol + width, -m_labelROI.top() + yRow);
						glFunc->glEnd();
					}

					const QString& str = tab.colContent[c][r];

					int xShift = 0;
					if (labelCol)
					{
						//align characters in the middle
						xShift = (tab.colWidth[c] - QFontMetrics(bodyFont).width(str)) / 2;
					}
					else
					{
						//align digits on the right
						xShift = tab.colWidth[c] - QFontMetrics(bodyFont).width(str);
					}

					context.display->displayText(	str,
													xStart + xCol + tabMarginX + xShift,
													yStart + yRow - rowHeight, ccGenericGLDisplay::ALIGN_DEFAULT, 0, textColor, &bodyFont);

					yRow -= height;
				}

				xCol += width;
			}
#else
			if (!body.empty())
			{
				//display body
				yStartRel -= margin;
				for (int i=0; i<body.size(); ++i)
				{
					yStartRel -= rowHeight;
					context.display->displayText(body[i],xStart+xStartRel,yStart+yStartRel,ccGenericGLDisplay::ALIGN_DEFAULT,0,defaultTextColor.rgb,&bodyFont);
				}
			}
#endif //DRAW_CONTENT_AS_TAB
		}
	}

	glFunc->glPopAttrib();

	glFunc->glPopMatrix();

	if (pushName)
	{
		glFunc->glPopName();
	}
}
Exemple #2
0
void cc2DLabel::drawMeOnly2D(CC_DRAW_CONTEXT& context)
{
	if (!m_dispIn2D)
		return;

	assert(!m_points.empty());

	//standard case: list names pushing
	bool pushName = MACRO_DrawEntityNames(context);
	if (pushName)
		glPushName(getUniqueID());

	//we should already be in orthoprojective & centered omde
	//glOrtho(-halfW,halfW,-halfH,halfH,-maxS,maxS);

	int strHeight = 0;
	int titleHeight = 0;
	QString title(getName());
	QStringList body;
	GLdouble arrowDestX=-1.0,arrowDestY=-1.0;
	QFont bodyFont,titleFont;
	if (!pushName)
	{
		/*** line from 2D point to label ***/

		//compute arrow head position
		CCVector3 arrowDest;
		m_points[0].cloud->getPoint(m_points[0].index,arrowDest);
		for (unsigned i=1;i<m_points.size();++i)
			arrowDest += *m_points[i].cloud->getPointPersistentPtr(m_points[i].index);
		arrowDest /= (PointCoordinateType)m_points.size();

		//project it in 2D screen coordinates
		int VP[4];
		context._win->getViewportArray(VP);
		const double* MM = context._win->getModelViewMatd(); //viewMat
		const double* MP = context._win->getProjectionMatd(); //projMat
		GLdouble zp;
		gluProject(arrowDest.x,arrowDest.y,arrowDest.z,MM,MP,VP,&arrowDestX,&arrowDestY,&zp);

		/*** label border ***/
		bodyFont = context._win->getTextDisplayFont(); //takes rendering zoom into account!
		titleFont = QFont(context._win->getTextDisplayFont()); //takes rendering zoom into account!
		titleFont.setBold(true);
		QFontMetrics titleFontMetrics(titleFont);
		QFontMetrics bodyFontMetrics(bodyFont);

		strHeight = bodyFontMetrics.height();
		titleHeight = titleFontMetrics.height();

		if (m_showFullBody)
			body = getLabelContent(context.dispNumberPrecision);

		//base box dimension
		int dx = 150;
		dx = std::max(dx,titleFontMetrics.width(title));

		int dy = c_margin;	//top vertical margin
		dy += titleHeight;	//title
		if (!body.empty())
		{
			dy += c_margin;	//vertical margin above separator
			for (int j=0;j<body.size();++j)
			{
				dx = std::max(dx,bodyFontMetrics.width(body[j]));
				dy += (c_margin+strHeight); //margin + body line height
			}
		}
		else
		{
			dy += c_margin;	// vertical margin (purely for aesthetics)
		}
		dy += c_margin;		// bottom vertical margin
		dx += c_margin*2;	// horizontal margins

		//main rectangle
		m_labelROI[0]=0;
		m_labelROI[1]=0;
		m_labelROI[2]=dx;
		m_labelROI[3]=dy;

		//close button
		/*m_closeButtonROI[2]=dx-c_margin;
		m_closeButtonROI[0]=m_closeButtonROI[2]-c_buttonSize;
		m_closeButtonROI[3]=c_margin;
		m_closeButtonROI[1]=m_closeButtonROI[3]+c_buttonSize;
		//*/

		//automatically elide the title
		//title = titleFontMetrics.elidedText(title,Qt::ElideRight,m_closeButtonROI[0]-2*c_margin);
	}

	int halfW = (context.glW>>1);
	int halfH = (context.glH>>1);

	//draw label rectangle
	int xStart = m_lastScreenPos[0] = (int)((float)context.glW * m_screenPos[0]);
	int yStart = m_lastScreenPos[1] = (int)((float)context.glH * (1.0f-m_screenPos[1]));

	//colors
	bool highlighted = (!pushName && isSelected());
	//default background color
	colorType defaultBkgColor[4];
	memcpy(defaultBkgColor,context.labelDefaultCol,sizeof(colorType)*3);
	defaultBkgColor[3] = (colorType)((float)context.labelsTransparency*(float)MAX_COLOR_COMP/100.0f);
	//default border color (mustn't be totally transparent!)
	colorType defaultBorderColor[4];
	if (highlighted)
		memcpy(defaultBorderColor,ccColor::red,sizeof(colorType)*3);
	else
		memcpy(defaultBorderColor,context.labelDefaultCol,sizeof(colorType)*3);
	defaultBorderColor[3] = (colorType)((float)(50+context.labelsTransparency/2)*(float)MAX_COLOR_COMP/100.0f);

	glPushAttrib(GL_COLOR_BUFFER_BIT);
	glEnable(GL_BLEND);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glTranslatef(static_cast<GLfloat>(-halfW+xStart),static_cast<GLfloat>(-halfH+yStart),0);

	if (!pushName)
	{
		//compute arrow base position relatively to the label rectangle (for 0 to 8)
		int arrowBaseConfig = 0;
		int iArrowDestX = (int)arrowDestX-xStart;
		int iArrowDestY = (int)arrowDestY-yStart;
		{
			if (iArrowDestX < m_labelROI[0]) //left
				arrowBaseConfig += 0;
			else if (iArrowDestX > m_labelROI[2]) //Right
				arrowBaseConfig += 2;
			else  //Middle
				arrowBaseConfig += 1;

			if (iArrowDestY > -m_labelROI[1]) //Top
				arrowBaseConfig += 0;
			else if (iArrowDestY < -m_labelROI[3]) //Bottom
				arrowBaseConfig += 6;
			else  //Middle
				arrowBaseConfig += 3;
		}

		//we make the arrow base start from the nearest corner
		if (arrowBaseConfig != 4) //4 = label above point!
		{
			glColor4ubv(defaultBorderColor);
			glBegin(GL_TRIANGLE_FAN);
			glVertex2d(arrowDestX-xStart,arrowDestY-yStart);
			switch(arrowBaseConfig)
			{
			case 0: //top-left corner
				glVertex2i(m_labelROI[0], -m_labelROI[1]-2*c_arrowBaseSize);
				glVertex2i(m_labelROI[0], -m_labelROI[1]);
				glVertex2i(m_labelROI[0]+2*c_arrowBaseSize, -m_labelROI[1]);
				break;
			case 1: //top-middle edge
				glVertex2i(std::max(m_labelROI[0],iArrowDestX-c_arrowBaseSize), -m_labelROI[1]);
				glVertex2i(std::min(m_labelROI[2],iArrowDestX+c_arrowBaseSize), -m_labelROI[1]);
				break;
			case 2: //top-right corner
				glVertex2i(m_labelROI[2], -m_labelROI[1]-2*c_arrowBaseSize);
				glVertex2i(m_labelROI[2], -m_labelROI[1]);
				glVertex2i(m_labelROI[2]-2*c_arrowBaseSize, -m_labelROI[1]);
				break;
			case 3: //middle-left edge
				glVertex2i(m_labelROI[0], std::min(-m_labelROI[1],iArrowDestY+c_arrowBaseSize));
				glVertex2i(m_labelROI[0], std::max(-m_labelROI[3],iArrowDestY-c_arrowBaseSize));
				break;
			case 4: //middle of rectangle!
				break;
			case 5: //middle-right edge
				glVertex2i(m_labelROI[2], std::min(-m_labelROI[1],iArrowDestY+c_arrowBaseSize));
				glVertex2i(m_labelROI[2], std::max(-m_labelROI[3],iArrowDestY-c_arrowBaseSize));
				break;
			case 6: //bottom-left corner
				glVertex2i(m_labelROI[0], -m_labelROI[3]+2*c_arrowBaseSize);
				glVertex2i(m_labelROI[0], -m_labelROI[3]);
				glVertex2i(m_labelROI[0]+2*c_arrowBaseSize, -m_labelROI[3]);
				break;
			case 7: //bottom-middle edge
				glVertex2i(std::max(m_labelROI[0],iArrowDestX-c_arrowBaseSize), -m_labelROI[3]);
				glVertex2i(std::min(m_labelROI[2],iArrowDestX+c_arrowBaseSize), -m_labelROI[3]);
				break;
			case 8: //bottom-right corner
				glVertex2i(m_labelROI[2], -m_labelROI[3]+2*c_arrowBaseSize);
				glVertex2i(m_labelROI[2], -m_labelROI[3]);
				glVertex2i(m_labelROI[2]-2*c_arrowBaseSize, -m_labelROI[3]);
				break;
			}
			glEnd();
		}
	}

	//main rectangle
	glColor4ubv(defaultBkgColor);
    glBegin(GL_QUADS);
    glVertex2i(m_labelROI[0], -m_labelROI[1]);
    glVertex2i(m_labelROI[0], -m_labelROI[3]);
    glVertex2i(m_labelROI[2], -m_labelROI[3]);
    glVertex2i(m_labelROI[2], -m_labelROI[1]);
    glEnd();

	//if (highlighted)
	{
		glPushAttrib(GL_LINE_BIT);
		glLineWidth(3.0f);
		glColor4ubv(defaultBorderColor);
		glBegin(GL_LINE_LOOP);
		glVertex2i(m_labelROI[0], -m_labelROI[1]);
		glVertex2i(m_labelROI[0], -m_labelROI[3]);
		glVertex2i(m_labelROI[2], -m_labelROI[3]);
		glVertex2i(m_labelROI[2], -m_labelROI[1]);
		glEnd();
		glPopAttrib();
	}

	//draw close button
	/*glColor3ubv(ccColor::black);
    glBegin(GL_LINE_LOOP);
    glVertex2i(m_closeButtonROI[0],-m_closeButtonROI[1]);
    glVertex2i(m_closeButtonROI[0],-m_closeButtonROI[3]);
    glVertex2i(m_closeButtonROI[2],-m_closeButtonROI[3]);
    glVertex2i(m_closeButtonROI[2],-m_closeButtonROI[1]);
    glEnd();
    glBegin(GL_LINES);
    glVertex2i(m_closeButtonROI[0]+2,-m_closeButtonROI[1]+2);
    glVertex2i(m_closeButtonROI[2]-2,-m_closeButtonROI[3]-2);
    glVertex2i(m_closeButtonROI[2]-2,-m_closeButtonROI[1]+2);
    glVertex2i(m_closeButtonROI[0]+2,-m_closeButtonROI[3]-2);
    glEnd();
	//*/

	//display text
	if (!pushName)
	{
		int xStartRel = c_margin;
		int yStartRel = -c_margin;
		yStartRel -= titleHeight;

		const colorType* defaultTextColor = (context.labelsTransparency<40 ? context.textDefaultCol : ccColor::darkBlue);

		context._win->displayText(title,xStart+xStartRel,yStart+yStartRel,ccGenericGLDisplay::ALIGN_DEFAULT,0,defaultTextColor,&titleFont);
		yStartRel -= c_margin;

		if (!body.empty())
		{
			//line separation
			glColor4ubv(defaultBorderColor);
			glBegin(GL_LINES);
			glVertex2i(xStartRel,yStartRel);
			glVertex2i(xStartRel+m_labelROI[2]-m_labelROI[0]-2*c_margin,yStartRel);
			glEnd();

			//display body
			yStartRel -= c_margin;
			for (int i=0;i<body.size();++i)
			{
				yStartRel -= strHeight;
				context._win->displayText(body[i],xStart+xStartRel,yStart+yStartRel,ccGenericGLDisplay::ALIGN_DEFAULT,0,defaultTextColor,&bodyFont);
			}
		}
	}

	glPopAttrib();

	glPopMatrix();

	if (pushName)
		glPopName();
}