void DArrowRectangle::setContent(QWidget *content)
{
    if (!content)
        return;

    m_content = content;
    m_content->setParent(this);
    m_content->show();

    qreal delta = shadowBlurRadius() + shadowDistance() + margin();

    resizeWithContent();

    switch(m_arrowDirection)
    {
    case ArrowLeft:
        m_content->move(m_arrowHeight + delta, delta);
        break;
    case ArrowRight:
        m_content->move(delta, delta);
        break;
    case ArrowTop:
        m_content->move(delta, delta + m_arrowHeight);
        break;
    case ArrowBottom:
        m_content->move(delta, delta);
        break;
    }

    update();
}
void DArrowRectangle::horizontalMove(int x, int y)
{
    QRect dRect = QApplication::desktop()->geometry();
    qreal delta = shadowBlurRadius() - shadowDistance();

    int lRelativeX = x - dRect.x() - (width() - delta) / 2;
    int rRelativeX = x - dRect.x() + (width() - delta) / 2 - dRect.width();
    int absoluteX = 0;

    if (lRelativeX < 0)//out of screen in left side
    {
        //arrowX use relative coordinates
        setArrowX(width() / 2 - delta + lRelativeX);
        absoluteX = dRect.x() - delta;
    }
    else if(rRelativeX > 0)//out of screen in right side
    {
        setArrowX(width() / 2 - delta * 2 + rRelativeX);
        absoluteX = dRect.x() + dRect.width() - width() + delta;
    }
    else
        absoluteX = x - width() / 2;

    switch (m_arrowDirection)
    {
    case ArrowTop:
        QWidget::move(absoluteX, y);
        break;
    case ArrowBottom:
        QWidget::move(absoluteX, y - height());
        break;
    default:
        break;
    }
}
QPainterPath DArrowRectangle::getBottomCornerPath()
{
    qreal delta = shadowBlurRadius() + shadowDistance();

    QRect rect = this->rect().marginsRemoved(QMargins(delta, delta, delta, delta));

    QPoint cornerPoint(rect.x() + (m_arrowX > 0 ? m_arrowX : rect.width() / 2), rect.y()  + rect.height());
    QPoint topLeft(rect.x(), rect.y());
    QPoint topRight(rect.x() + rect.width(), rect.y());
    QPoint bottomRight(rect.x() + rect.width(), rect.y() + rect.height() - m_arrowHeight);
    QPoint bottomLeft(rect.x(), rect.y() + rect.height() - m_arrowHeight);
    int radius = this->m_radius > (rect.height() / 2 - m_arrowHeight) ? rect.height() / 2 -m_arrowHeight : this->m_radius;

    QPainterPath border;
    border.moveTo(topLeft.x() + radius, topLeft.y());
    border.lineTo(topRight.x() - radius, topRight.y());
    border.arcTo(topRight.x() - 2 * radius, topRight.y(), 2 * radius, 2 * radius, 90, -90);
    border.lineTo(bottomRight.x(), bottomRight.y() - radius);
    border.arcTo(bottomRight.x() - 2 * radius, bottomRight.y() - 2 * radius, 2 * radius, 2 * radius, 0, -90);
    border.lineTo(cornerPoint.x() + m_arrowWidth / 2, cornerPoint.y() - m_arrowHeight);
    border.lineTo(cornerPoint);
    border.lineTo(cornerPoint.x() - m_arrowWidth / 2, cornerPoint.y() - m_arrowHeight);
    border.lineTo(bottomLeft.x() + radius, bottomLeft.y());
    border.arcTo(bottomLeft.x(), bottomLeft.y() - 2 * radius, 2 * radius, 2 * radius, -90, -90);
    border.lineTo(topLeft.x(), topLeft.y() + radius);
    border.arcTo(topLeft.x(), topLeft.y(), 2 * radius, 2 * radius, 180, -90);

    return border;
}
void DArrowRectangle::verticalMove(int x, int y)
{
    QRect dRect = QApplication::desktop()->geometry();
    qreal delta = shadowBlurRadius() - shadowDistance();

    int lRelativeY = y - dRect.y() - (height() - delta) / 2;
    int rRelativeY = y - dRect.y() + (height() - delta) / 2 - dRect.height();
    int absoluteY = 0;

    if (lRelativeY < 0)//out of screen in top side
    {
        //arrowY use relative coordinates
        setArrowY(height() / 2 - delta + lRelativeY);
        absoluteY = dRect.y() - delta;
    }
    else if(rRelativeY > 0)//out of screen in bottom side
    {
        setArrowY(height() / 2 - delta * 2 + rRelativeY);
        absoluteY = dRect.y() + dRect.height() - height() + delta;
    }
    else
        absoluteY = y - height() / 2;

    switch (m_arrowDirection)
    {
    case ArrowLeft:
        QWidget::move(x, absoluteY);
        break;
    case ArrowBottom:
        QWidget::move(x - width(), absoluteY);
        break;
    default:
        break;
    }
}
DWIDGET_USE_NAMESPACE

DArrowRectangle::DArrowRectangle(ArrowDirection direction, QWidget * parent) :
    QWidget(parent),m_arrowDirection(direction)
{
    DGraphicsGlowEffect *glowEffect = new DGraphicsGlowEffect(this);
    glowEffect->setBlurRadius(shadowBlurRadius());
    glowEffect->setDistance(shadowDistance());
    glowEffect->setXOffset(shadowXOffset());
    glowEffect->setYOffset(shadowYOffset());
    setGraphicsEffect(glowEffect);
}
DUI_USE_NAMESPACE

DArrowRectangle::DArrowRectangle(ArrowDirection direction, QWidget * parent) :
    QWidget(parent),m_arrowDirection(direction)
{
    D_THEME_INIT_WIDGET(DArrowRectangle);

    setWindowFlags(Qt::SplashScreen);
    setAttribute(Qt::WA_TranslucentBackground);

    DGraphicsGlowEffect *glowEffect = new DGraphicsGlowEffect(this);
    glowEffect->setBlurRadius(shadowBlurRadius());
    glowEffect->setDistance(shadowDistance());
    glowEffect->setXOffset(shadowXOffset());
    glowEffect->setYOffset(shadowYOffset());
    setGraphicsEffect(glowEffect);
}
QSize DArrowRectangle::getFixedSize()
{
    if (m_content)
    {        
        qreal delta = shadowBlurRadius() + shadowDistance() + margin();

        switch(m_arrowDirection)
        {
        case ArrowLeft:
        case ArrowRight:
            return QSize(m_content->width() + delta * 2 + m_arrowHeight, m_content->height() + delta * 2);
        case ArrowTop:
        case ArrowBottom:
            return QSize(m_content->width() + delta * 2, m_content->height() + delta * 2 + m_arrowHeight);
        }
    }

    return QSize(0, 0);
}
void DArrowRectangle::resizeWithContent()
{
    setFixedSize(getFixedSize());

    repaint();

    //Shadow Transparent For MouseEvents
    qreal delta = shadowBlurRadius() + shadowDistance();
    Q_UNUSED(delta);
//    XRectangle m_contentXRect;
//    m_contentXRect.x = 0;
//    m_contentXRect.y = 0;
//    m_contentXRect.width = width() - delta * 2;
//    m_contentXRect.height = height() - delta * 2;
//    XShapeCombineRectangles(QX11Info::display(), winId(), ShapeInput,
//                            delta + shadowXOffset(),
//                            delta + shadowYOffset(),
//                            &m_contentXRect, 1, ShapeSet, YXBanded);
}
void DArrowRectangle::resizeWithContent()
{
    setFixedSize(getFixedSize());

    update();

#ifdef Q_OS_UNIX
    //Shadow Transparent For MouseEvents
    qreal delta = shadowBlurRadius() + shadowDistance();

    XRectangle m_contentXRect;
    m_contentXRect.x = 0;
    m_contentXRect.y = 0;
    m_contentXRect.width = width() - delta * 2;
    m_contentXRect.height = height() - delta * 2;
    XShapeCombineRectangles(QX11Info::display(), winId(), ShapeInput,
                            delta + shadowXOffset(),
                            delta + shadowYOffset(),
                            &m_contentXRect, 1, ShapeSet, YXBanded);
#endif
}
QImage RichTextRenderer::renderText()
{
// 	qDebug()<<itemName()<<"TextBoxWarmingThread::run(): htmlCode:"<<htmlCode;
	//qDebug() << "RichTextRenderer::renderText(): HTML:"<<html();
	//qDebug() << "RichTextRenderer::update(): Update Start...";
 	//qDebug() << "RichTextRenderer::renderText(): \t in thread:"<<QThread::currentThreadId();
	if(m_updateTimer.isActive())
		m_updateTimer.stop();
		
	QTime renderTime;
	renderTime.start();
	
	QTextDocument doc;
	QTextDocument shadowDoc;
	
	if (Qt::mightBeRichText(html()))
	{
		doc.setHtml(html());
		shadowDoc.setHtml(html());
	}
	else
	{
		doc.setPlainText(html());
		shadowDoc.setPlainText(html());
	}
	
	int textWidth = m_textWidth;

	doc.setTextWidth(textWidth);
	shadowDoc.setTextWidth(textWidth);
	
	// Apply outline pen to the html
	QTextCursor cursor(&doc);
	cursor.select(QTextCursor::Document);

	QTextCharFormat format;

	QPen p(Qt::NoPen);
	if(outlineEnabled())
	{
		p = outlinePen();
		p.setJoinStyle(Qt::MiterJoin);
	}

	format.setTextOutline(p);
	//format.setForeground(fillEnabled() ? fillBrush() : Qt::NoBrush); //Qt::white);

	cursor.mergeCharFormat(format);
	
	// Setup the shadow text formatting if enabled
	if(shadowEnabled())
	{
		if(shadowBlurRadius() <= 0.05)
		{
			QTextCursor cursor(&shadowDoc);
			cursor.select(QTextCursor::Document);
	
			QTextCharFormat format;
			format.setTextOutline(Qt::NoPen);
			format.setForeground(shadowBrush());
	
			cursor.mergeCharFormat(format);
		}
	}
	
			
	QSizeF shadowSize = shadowEnabled() ? QSizeF(shadowOffsetX(),shadowOffsetY()) : QSizeF(0,0);
	QSizeF docSize = doc.size();
	QSizeF padSize(12.,12.);
	QSizeF sumSize = (docSize + shadowSize + padSize);//.toSize();
	
	QSizeF scaledSize = QSizeF(sumSize.width() * m_scaling.x(), sumSize.height() * m_scaling.y());
	if(m_scaling.x() != 1. || m_scaling.y() != 1.)
	{
		//qDebug() << "RichTextRenderer::renderText(): Orig size:"<<sumSize<<", scaled size:"<<scaledSize<<", scaling:"<<m_scaling;
		m_rawSize = sumSize;
	}
	//qDebug() << "RichTextRenderer::update(): textWidth: "<<textWidth<<", shadowSize:"<<shadowSize<<", docSize:"<<docSize<<", sumSize:"<<sumSize;
	QImage cache(scaledSize.toSize(),QImage::Format_ARGB32); //_Premultiplied);
	memset(cache.scanLine(0),0,cache.byteCount());
	
	double padSizeHalfX = padSize.width() / 2;
	double padSizeHalfY = padSize.height() / 2;
			
	
	QPainter textPainter(&cache);
	textPainter.scale(m_scaling.x(), m_scaling.y());
	//textPainter.fillRect(cache.rect(),Qt::transparent);
	
	QAbstractTextDocumentLayout::PaintContext pCtx;

	//qDebug() << "RichTextRenderer::renderText(): shadowEnabled():"<<shadowEnabled()<<", shadowBlurRadius():"<<shadowBlurRadius(); 
	if(shadowEnabled())
	{
		if(shadowBlurRadius() <= 0.05)
		{
			// render a "cheap" version of the shadow using the shadow text document
			textPainter.save();

			textPainter.translate(shadowOffsetX(),shadowOffsetY());
			shadowDoc.documentLayout()->draw(&textPainter, pCtx);

			textPainter.restore();
		}
		else
		{
			double radius = shadowBlurRadius();
			
			// create temporary pixmap to hold a copy of the text
			QSizeF blurSize = ImageFilters::blurredSizeFor(doc.size(), (int)radius);
			
			QSizeF scaledBlurSize = QSize(blurSize.width() * m_scaling.x(), blurSize.height() * m_scaling.y());
			//QSize docSize = doc.size();
			//qDebug() << "RichTextRenderer::renderText(): [shadow] radius:"<<radius<<" blurSize:"<<blurSize<<", scaling:"<<m_scaling<<", scaledBlurSize:"<<scaledBlurSize;
			
			
			//qDebug() << "Blur size:"<<blurSize<<", doc:"<<doc.size()<<", radius:"<<radius;
			QImage tmpImage(scaledBlurSize.toSize(),QImage::Format_ARGB32_Premultiplied);
			memset(tmpImage.scanLine(0),0,tmpImage.byteCount());
			
			// render the text
			QPainter tmpPainter(&tmpImage);
			tmpPainter.scale(m_scaling.x(), m_scaling.y());
			
			tmpPainter.save();
			tmpPainter.translate(radius + padSizeHalfX, radius + padSizeHalfY);
			doc.documentLayout()->draw(&tmpPainter, pCtx);
			tmpPainter.restore();
			
			// blacken the text by applying a color to the copy using a QPainter::CompositionMode_DestinationIn operation. 
			// This produces a homogeneously-colored pixmap.
			QRect rect = tmpImage.rect();
			tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
			tmpPainter.fillRect(rect, shadowBrush().color());
			tmpPainter.end();

			// blur the colored text
			ImageFilters::blurImage(tmpImage, (int)radius);
			
			// render the blurred text at an offset into the cache
			textPainter.save();
			textPainter.translate(shadowOffsetX() - radius,
					      shadowOffsetY() - radius);
			textPainter.drawImage(0, 0, tmpImage);
			textPainter.restore();
		}
	}
	
	textPainter.translate(padSizeHalfX, padSizeHalfY);
	doc.documentLayout()->draw(&textPainter, pCtx);
	
	textPainter.end();
	
	m_image = cache.convertToFormat(QImage::Format_ARGB32);
	emit textRendered(m_image);
	
	//qDebug() << "RichTextRenderer::renderText(): Render finished, elapsed:"<<renderTime.elapsed()<<"ms";
	//m_image.save("debug-text.png");
	return m_image;
	
}