Exemple #1
0
QLineF Robot::intersectDistance(QGraphicsLineItem *item, const double &baseAngle) const
{
	QGraphicsScene *scene = item->scene();
	if(!scene) return QLineF(0, 0, 0, 0);
	
	const double rad = (m_robot->rotation() + baseAngle) / 180.0 * M_PI;
	QLineF line(m_robot->pos(), m_robot->pos() + m_rangeLength *
		QPointF(cos(rad), sin(rad)));
	
	const QLineF unit = line.unitVector();
	// qDebug() << unit.dx();
	double xs = unit.dx();
	double ys = unit.dy();
	if(xs == 0.0) xs = 0.0001;
	if(ys == 0.0) ys = 0.0001;
	for(double i = 0; i < m_rangeLength; i += 1.0) {
		QRectF r(m_robot->x() + i * xs, m_robot->y() + i * ys, xs, ys);
		QList<QGraphicsItem *> items = scene->items(r, Qt::IntersectsItemBoundingRect, Qt::AscendingOrder);
		foreach(QGraphicsItem *t, items) {
			if(t->data(0) == BoardFile::Real) {
				line.setLength(i);
				return line;
			}
		}
	}
	
	return line;
}
Exemple #2
0
QPointF EdgeSnapper::snap(const QPointF& pos) {
    QGraphicsScene* scene = theView->scene();

    // TODO: probably should use the view to get the items so that
    // the same visible area is always used for item selection, independent
    // of view transformation
    QList<QGraphicsItem *> items =
            scene->items (QRectF(pos.x() - 4, pos.y() - 4, 8, 8),
                          Qt::IntersectsItemShape);

    qreal minDist = 4.0; // minimum distance
    QPointF result = pos;
    bool found = false;
    //qDebug() << "Items: " << items.size() - 1;
    foreach(QGraphicsItem* item, items) {
        InteractableItem* iItem =  dynamic_cast<InteractableItem*>(item);
        if (iItem && iItem != theView->getFocusItem()) {  // TODO: Better approach to filter out current item?
            QPointF edge = iItem->getNearestEdge(theView, pos);
            qreal dist =  sqrt(pow(pos.x() - edge.x(), 2) + pow(pos.y() - edge.y(), 2));

            if (dist < minDist) {
                found = true;
                minDist = dist;
                result = edge;
            }
        }
    }
Exemple #3
0
double Robot::reflectanceReading(double sensorX, double sensorY)
{
	double result = 0.0;
	double weight = 1.0 / num_pts;
	double spiral_scale = 2.0;

	QGraphicsScene *scene = m_leftRange->scene();

	for (int i = 0; i < num_pts; i++){
		double spiralX = spiral_xs[i]*spiral_scale + sensorX;
		double spiralY = spiral_ys[i]*spiral_scale + sensorY;

		QRectF r(QPoint(spiralX, spiralY), QSize(1,1));

		QList<QGraphicsItem *> items = scene->items(r, Qt::IntersectsItemBoundingRect, Qt::AscendingOrder);
		foreach(QGraphicsItem *t, items) {
			if(t->data(0) == BoardFile::Tape) {
				result += weight;
				continue;
			}
		}
	}

	return result;
}
Exemple #4
0
void GraphWidget::draw(ITree<GuiNode>* tree)
{
    //Reset properties (only usefull when drawing more than one tree)
    resetCachedContent();
    resetMatrix();
    resetTransform();

    //Set Properties
    setCacheMode(CacheBackground);
    setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    setDragMode(QGraphicsView::ScrollHandDrag);
    rotate(qreal(-90));


    //Create scene
    QGraphicsScene* scene;
    if (this->scene() != NULL)
    {
        scene = this->scene();
        QListIterator<QGraphicsItem*> items(scene->items());
        while (items.hasNext())
        {
            scene->removeItem(items.next());
        }
        delete scene;
    }
    scene = new QGraphicsScene(this);
    this->setScene(scene);
    this->tree = tree;
    drawTree(this->scene(), tree->getRoot());

    //Ensure visibility of the tree
    this->fitInView(this->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
}
Exemple #5
0
void PartsEditorSketchWidget::clearScene() {
	QGraphicsScene * scene = this->scene();
	//QList<QGraphicsItem*> items;
	for(int i=0; i < scene->items().size(); i++){
		ItemBase * itemBase = ItemBase::extractTopLevelItemBase(scene->items()[i]);
		if (itemBase == NULL) {
			//items << scene->items()[i];
			continue;
		}

		this->deleteItem(itemBase, true, true);
	}

	/*for(int i=0; i < items.size(); i++) {
		scene->removeItem(items[i]);
	}*/
}
Exemple #6
0
SEXP qt_qitemsInRect_QGraphicsScene(SEXP rself, SEXP rrect) {
  QGraphicsScene *self = unwrapQObject(rself, QGraphicsScene);
  SEXP ans;
  QList<QGraphicsItem *> items = self->items(asQRectF(rrect));
  ans = allocVector(VECSXP, items.size());
  for (int i = 0; i < length(ans); i++)
    SET_VECTOR_ELT(ans, i, wrapQGraphicsItem(items[i]));
  return ans;
}
Exemple #7
0
bool
QGModifyInteractor::normalStateFilter(QObject * obj, QEvent * evt)
{
  // Flag indicating if the received event must be trapped by the
  // method (ie. not passed to other filters).
  bool trap = false;

  if (evt->type() == QEvent::MouseButtonPress) {

    QMouseEvent * me = dynamic_cast<QMouseEvent *>(evt);

    if (me->button() == Qt::LeftButton) {

      // --------------------------
      // Left-Click: Item selection
      // --------------------------  
    
      //-- Look up for collisions.

      // Compute cursors 'real position'
      QPoint realPos = _view->toRealCoords( me->pos() );
      
      // Access to the current document canvas.
      QGraphicsScene * canvas = _layer->canvas();

      // Retrieve all objects intersecting with a square of 5 pixels edge.
      QRect selRect(realPos - QPoint(2, 2), realPos + QPoint(2, 2));

      QList<QGraphicsItem*> itemList = canvas->items(selRect);

      if (!itemList.empty()) {

	//-- Set the selected item. 
	// The item selected is the first item of the collision list
	// The item is informed that it is selected thus it can modify
	// its appearence.
	setSelectedItem(itemList.front());

	//-- Change state to 'selectedItem' state

	// Remove current filter and install 'selectedItem' filter.
	_view->viewport()->removeEventFilter(_normalFilter);
	_view->viewport()->installEventFilter(_selectedItemFilter);

	// Enable keyboard event on the viewport.
	_view->viewport()->setFocus();
	
	//-- Prevent the click event to be forwarded.

	trap = true;
      }// if empty()
    }// if leftButton
  }// if MouseButtonPress
  
  return trap;
}
Exemple #8
0
SEXP qt_qupdate_QGraphicsScene(SEXP rself) {
  QGraphicsScene *scene = unwrapQObject(rself, QGraphicsScene);
  QList<QGraphicsItem *> items = scene->items();
  for (int i = 0; i < items.size(); i++) {
    QGraphicsItem *item = items[i];
    QGraphicsItem::CacheMode mode = item->cacheMode();
    item->setCacheMode(QGraphicsItem::NoCache);
    item->setCacheMode(mode);
  }
  scene->update();
  return rself;
}
Exemple #9
0
GraphWidget::~GraphWidget()
{
    QGraphicsScene* scene;
    if (this->scene() != NULL)
    {
        scene = this->scene();
        QListIterator<QGraphicsItem*> items(scene->items());
        while (items.hasNext())
        {
            scene->removeItem(items.next());
        }
    }
}
SCgObject* IncidencePointGraphicsItem::objectAtPoint() const
{
    QGraphicsScene* s = scene();
    Q_ASSERT(s);

    QList<QGraphicsItem*> itemList = s->items(scenePos(), Qt::IntersectsItemShape, Qt::DescendingOrder);

    foreach(QGraphicsItem* it, itemList)
        if (it != this && it != mParent && SCgObject::isSCgObjectType(it->type()))
            return static_cast<SCgObject*>(it);

    return 0;
}
Exemple #11
0
void core::Connector::updateConectorLine(const QPointF &begin, const QPointF &end)
{

	const double MIN_LENGHT = 10;

//	QLineF line(begin, end);

	QList<QGraphicsItem*>
			collidingItemsEndOfLine,
			collidingItemsMiddleLine,
			fullList;

//	QGraphicsItem *closerItem;
//	QRectF closerItemRect;

//	QPointF
//			correctedEnd = end,
//			midPoint,
//			mappedMidPoint;

	if(composedLine.isEmpty()){

		Port p = beginObject->getCurrentPort(mapToItem(beginObject, begin));

		RestrictedLineF *firstLine = new RestrictedLineF(begin, end);

		switch(p){
			case GraphicObject::portBottom:
				firstLine->setConstrain(RestrictedLineF::VerticalDown);
				break;
			case GraphicObject::portTop:
				firstLine->setConstrain(RestrictedLineF::VerticalUp);
				break;
			case GraphicObject::portLeft:
				firstLine->setConstrain(RestrictedLineF::HorizontalLeft);
				break;
			case GraphicObject::portRight:
				firstLine->setConstrain(RestrictedLineF::HorizontalRight);
				break;
				
			case GraphicObject::portNone:
			default:
				firstLine->setConstrain(RestrictedLineF::None);
				break;
		}
		composedLine.push_back(firstLine);

		shapeForm.push_back(firstLine->p1());
		shapeForm.push_back(firstLine->p2());
	}

	QGraphicsScene *env = scene();

	QList<CollidingResult> colItems = collidingObjects(composedLine);

//	for(int i = 0; i < colItems.size(); i++){
//		colItems[i].line->setConstrain(RestrictedLineF::Both);
//	}

	RestrictedLineF
			temptativeLine,
			*curLine;
	for(auto i = composedLine.size()-1; i >= 0; i--){
		curLine = composedLine[i];
		temptativeLine = *curLine;
		if(i == composedLine.size() - 1){

			if(env){
				fullList = env->items(mapToScene(end));
				collidingItemsEndOfLine = removeIgnoredObjects(fullList);

				if(composedLine.size() > 1){
					fullList = env->items(mapToScene(composedLine[i - 1]->getCorrectedP2(end)));
					collidingItemsMiddleLine = removeIgnoredObjects(fullList);
				}

				if(collidingItemsEndOfLine.isEmpty() && collidingItemsMiddleLine.isEmpty()){
					if(composedLine.size() > 1){
						composedLine[i - 1]->setP2(end);
						curLine->setP1(composedLine[i - 1]->p2());
						shapeForm[i] = composedLine[i - 1]->p2();
					}


					//Set the point p2 to curLine (it will be corrected against restrictions)
					curLine->setP2(end);
					shapeForm[i + 1] = curLine->p2();

					//calculates the distance between corrected p2 of curLine and current end point
					if(math::distance(curLine->p2(), end) >= MIN_LENGHT &&
							!curLine->isNull() &&
							!(i = 1 && composedLine[0]->isNull())){

						RestrictedLineF::Constrain restriction;

						switch (curLine->getConstrain()) {
							case RestrictedLineF::HorizontalRight:
							case RestrictedLineF::HorizontalLeft:
							case RestrictedLineF::Horizontal:
								restriction = RestrictedLineF::Vertical;
								break;

							case RestrictedLineF::VerticalUp:
							case RestrictedLineF::VerticalDown:
							case RestrictedLineF::Vertical:
								restriction = RestrictedLineF::Horizontal;
								break;
							case RestrictedLineF::Both:
								if(fabs(curLine->p2().x() - end.x()) >= fabs(curLine->p2().y() - end.y())){
									restriction = RestrictedLineF::Horizontal;
								}else{
									restriction = RestrictedLineF::Vertical;
								}
								break;
							case RestrictedLineF::None:
							default:
								restriction = RestrictedLineF::None;
								break;
						}

						RestrictedLineF *newLine = new RestrictedLineF(curLine->p2(), end, restriction);

						composedLine.push_back(newLine);
						//use in case shapeForm be QPainterPath
//						shapeForm.lineTo(newLine->p2());

						//use in case shapeForm be QPolygonF
//						shapeForm[i + 1]
						shapeForm.push_back(newLine->p2());
					}
				}
			}
		}else if(i == composedLine.size() - 2){

		}

		if(curLine->length() < MIN_LENGHT && i != 0){
			composedLine.remove(i);
			shapeForm.remove(i+1);
		}else if(i == 1){
			if(composedLine[i - 1]->isNull()){
				composedLine.remove(i);
				shapeForm.remove(i+1);
			}
		}
	}

//	shapeForm = QPainterPath(begin);

////	shapeForm
//	for(auto i = 0; i < composedLine.size(); i++){
//		shapeForm.lineTo(composedLine[i]->p2());
//	}
//	//Only for debug process. Can be simplified
//	midPoint = QPointF(end.x(), 0);
//	mappedMidPoint = mapToScene(midPoint);

//	fullList = collidingItems(Qt::IntersectsItemShape);
//	itemListAt = removeIgnoredObjects(fullList);

//	if(fabs(line.dx()) >= fabs(line.dy())){
//		if(itemListAt.size() > 0){
//			if(midPoint.x() >= 0){
//				closerItem = closerItemPerif(midPoint, portLeft, itemListAt);

//				closerItemRect = mapFromItem(closerItem, closerItem->boundingRect()).boundingRect();

//				midPoint.setX(closerItemRect.left()/* - clearance*/);
//				correctedEnd.setX(closerItemRect.left());
//			}else{
//				closerItem = closerItemPerif(midPoint, portRight, itemListAt);

//				closerItemRect = mapFromItem(closerItem, closerItem->boundingRect()).boundingRect();

//				midPoint.setX(closerItemRect.right()/* + clearance*/);
//				correctedEnd.setX(closerItemRect.right());
//			}
//		}
////		composedLine.push_back(QLineF(begin, midPoint));
////		composedLine.push_back(QLineF(midPoint, correctedEnd));
//	}else{
//		if(itemListAt.size() > 0){
//			if(midPoint.y() >= 0){
//				closerItem = closerItemPerif(midPoint, portTop, itemListAt);

//				closerItemRect = mapFromItem(closerItem, closerItem->boundingRect()).boundingRect();

//				midPoint.setY(closerItemRect.top()/* - clearance*/);
//				correctedEnd.setY(closerItemRect.top());
//			}else{
//				closerItem = closerItemPerif(midPoint, portBottom, itemListAt);

//				closerItemRect = mapFromItem(closerItem, closerItem->boundingRect()).boundingRect();

//				midPoint.setY(closerItemRect.bottom()/* + clearance*/);
//				correctedEnd.setY(closerItemRect.bottom());
//			}
//		}
//	}

//	composedLine.clear();
//	composedLine.push_back(QLineF(begin, midPoint));
//	composedLine.push_back(QLineF(midPoint, correctedEnd));
}
Exemple #12
0
bool QtPrinterTableView::print()
{
    Q_D(QtPrinterTableView);
    if (! d->printer->isValid()) {
        qWarning() << "QtPrinterTableView::print: printer not valid, please setup the printer before calling print";
        return false;
    }

    // next use a view just for the filling of the options...
    QGraphicsScene scene;
    QtGraphicsTableView view;
    scene.addItem(&view);
    view.setModel(d->model);


    class QTableHeaderDataProvider2 : public QtGraphicsHeaderDataProvider
    {
    public:
        QTableHeaderDataProvider2(QtTableModelInterface *model_) : model(model_) {}
        QHash<int,QVariant> data(int logicalIndex, const QList<int> &roles) const
        {
            // ### call the model - temporary implementation
            QHash<int,QVariant> hash;
            for (int i = 0; i < roles.count(); ++i)
                if (roles.at(i) == Qt::DisplayRole)
                    hash.insert(Qt::DisplayRole, logicalIndex + 1);
            return hash;
        }
        QtTableModelInterface *model;
    };

    if (d->horizontalHeader) {
        QtGraphicsHeader *header = new QtGraphicsHeader(Qt::Horizontal, &view);
        header->setDataProvider(new QTableHeaderDataProvider2(d->model));
        header->copySections(*d->horizontalHeader);
        view.setHorizontalHeader(header);
    }
    if (d->verticalHeader) {
        QtGraphicsHeader *header = new QtGraphicsHeader(Qt::Vertical, &view);
        header->setDataProvider(new QTableHeaderDataProvider2(d->model));
        header->copySections(*d->verticalHeader);
        view.setVerticalHeader(header);
    }

    QPainter painter;
    if (!painter.begin(d->printer)) {
        qWarning() << "QtPrinterTableView::print: printer fails to begin(), sorry can't print";
        return false;
    }

    // re-layout the header footer to the current page size.
    if (d->header) {
        d->header->documentLayout()->setPaintDevice(d->printer);
        d->header->setPageSize(d->printer->pageRect().size());
    }
    if (d->footer) {
        d->footer->documentLayout()->setPaintDevice(d->printer);
        d->footer->setPageSize(d->printer->pageRect().size());
    }

    const qreal headerSize = d->printHeader(painter);
    const qreal footerSize = d->printFooter(painter);
    const bool vertical = d->orientation == Qt::Vertical;
    const qreal scaleX = d->printer->logicalDpiX() / (qreal) qt_defaultDpiX();
    const qreal scaleY = d->printer->logicalDpiY() / (qreal) qt_defaultDpiY();
    painter.scale(scaleX, scaleY);

    const QRect rect = d->printer->pageRect();
    QSizeF visibleSize(rect.width() / scaleX, rect.height() / scaleY);
    if (vertical)
        visibleSize = QSizeF(visibleSize.width(), visibleSize.height() - headerSize - footerSize);
    else // then rotate it.
        visibleSize = QSizeF(visibleSize.height() - headerSize - footerSize, visibleSize.width());

    view.setGeometry(0, 0, visibleSize.width(), visibleSize.height());
    view.setHorizontalOffset(0);

    int row = 0;
    int column;
    bool first = true;
    qreal offsetInColumn = 0; // for those columns too wide and thus split over more than one page
    while (row < d->model->rowCount()) {
        column = 0;
        view.setFirstRow(row);
        qreal height = visibleSize.height();
        while (true) {
            const qreal rowHeight = view.rowHeight(row);
            if (height - rowHeight < 0)
                break;
            if (row >= d->model->rowCount())
                break;
            ++row;
            height -= rowHeight;
        }
        while (column < d->model->columnCount()) {
            if (!first) {
                d->printer->newPage();
                d->printHeader(painter);
                d->printFooter(painter);
            }
            first = false;
            view.setFirstColumn(column);
            view.setHorizontalOffset(offsetInColumn);

            qreal width = visibleSize.width();
            while (true) {
                const qreal columnWidth = view.columnWidth(column);
                if (width == visibleSize.width() && columnWidth - offsetInColumn > visibleSize.width()) {
                    // the column doesn't fit on a page. Lets split it.
                    offsetInColumn += visibleSize.width();
                    width = 0;
                    break;
                } else if (offsetInColumn > 0) { // we still have a part of a split column to print!
                    width -= columnWidth - offsetInColumn;
                    offsetInColumn = 0;
                    ++column;
                    continue;
                }

                if (width - columnWidth + offsetInColumn < 0)
                    break;
                if (column >= d->model->columnCount())
                    break;
                ++column;
                width -= columnWidth;
            }
            view.doLayout();

            painter.save(); // for each page
            painter.translate(0, headerSize);
            if (!vertical) {
                painter.translate(0, visibleSize.width());
                painter.rotate(-90);
            }
#ifdef DEBUG_TABLES
            painter.setPen(QPen(QColor(Qt::green)));
            painter.drawRect(QRectF(0, 0, visibleSize.width() - width, visibleSize.height() - height));
#endif
            painter.setClipRect(QRectF(0, 0, visibleSize.width() - width, visibleSize.height() - height));
            // find and paint children which are the cells
            QList<QGraphicsItem*> items = scene.items(view.rect());
            QList<QGraphicsItem*>::Iterator iter = items.begin();
            for (;iter != items.end(); ++iter) {
                QGraphicsItem *parent = *iter;
                while (parent != &view && parent != 0) // only draw children of our view
                    parent = parent->parentItem();
                if (parent == 0)
                    continue;
                if (!(*iter)->isVisible())
                    continue;
                painter.save();
                painter.translate((*iter)->mapToItem(&view, QPointF()));
#ifdef DEBUG_TABLES
                QGraphicsWidget *w = dynamic_cast<QGraphicsWidget*>(*iter);
                if (w) {
                    painter.save();
                    painter.setPen(QPen(QColor(Qt::red)));
                    painter.drawRect(QRectF(QPointF(), w->size()));
                    painter.restore();
                }
#endif
                (*iter)->paint(&painter, 0);
                painter.restore();
            }
            painter.restore(); // for each page
        }
    }
    return true;
}
Exemple #13
0
//virtual
void VirtualCamera::setup(const QGraphicsItem * farBoundItem,const QList<QPointer<ThingPaintable> >& exclusionList,
							const QRectF& sceneViewport)
{
	m_triggerAble = false;
	//grab the scene pointer, or bail if not available
	QGraphicsScene * pScene = DimensionsGlobal::globalGraphicsScene();
	if (!pScene)
	{
		qDebug() << __FUNCTION__ << ": global graphics scene not available";
		return;
	}

	QList<QGraphicsItem *> rawItems;
	QSize rectSize;
	//if the sceneViewport isn't empty, then just get the items that are w/in it
	// use Qt::IntersectsItemBoundingRect to speed things up; this doesn't have to be exact, since the actual render by
	// trigger() will have to deal with source regions anyways
	if (!sceneViewport.isEmpty())
	{
		rectSize = sceneViewport.size().toSize();
		if ((rectSize.width() == 0) || (rectSize.height() == 0))
		{
			//would cause problems later
			m_viewport = QRectF();
			return;
		}
		m_viewport = sceneViewport;
		rawItems = pScene->items(sceneViewport,Qt::IntersectsItemBoundingRect,Qt::AscendingOrder);
		//SHOULD be ok to convert toSize(), w.r.t. trunc-ing off decimal bits and getting a smaller whole size
		// painter will have to do a similar thing so it SHOULD be compatible.
		// if things crash, look here first!
	}
	else //else get everything
	{
		rectSize = pScene->sceneRect().size().toSize();
		if ((rectSize.width() == 0) || (rectSize.height() == 0))
		{
			m_viewport = QRectF();
			return;
		}
		m_viewport = pScene->sceneRect();
		rawItems = pScene->items(pScene->sceneRect(),Qt::IntersectsItemBoundingRect,Qt::AscendingOrder);
	}

	//re-init the excludes
	m_excludes = QSet<QPointer<ThingPaintable> >::fromList(exclusionList);
	//clear the subjects
	m_subjects.clear();

	//the list is in ascending stack order. Toss out anything:
	// 1. below the farBoundItem
	// 2. not a ThingPaintable
	// 3. in the exclusion list

	//can't directly use "visible" as a determinant; the scene *can* provide an indicator of whether or not an item is occluded.
	// However, tossing out items by 1,2,3, above may actually reveal an item that was previously occluded, so more complicated logic
	// would be needed. It's ok though. The likelihood of it giving a significant reduction is minimal against the expense to
	// determine it.

	bool farItemReached = (farBoundItem == 0 ? true : false);		//if no far item was specified then set as already reached
	for (QList<QGraphicsItem *>::iterator it = rawItems.begin();
			it != rawItems.end();++it)
	{
		QGraphicsItem * pItem = *it;
		if ((!pItem) || (!farItemReached))
		{
			continue;
		}
		if (pItem == farBoundItem)
		{
			farItemReached = true;
		}
		ThingPaintable * pThingPaintable = ThingPaintable::thingpaintable_cast(pItem);
		if (!pThingPaintable)
		{
			continue;
		}
		if (m_excludes.contains(QPointer<ThingPaintable>(pThingPaintable)))
		{
			qDebug() << __FUNCTION__ << ": excluding thingpaintable [" << pThingPaintable->objectName() << "]";
			continue;
		}
		//ok it made it through the gauntlet...append to subjects list
		m_subjects << QPointer<ThingPaintable>(pThingPaintable);
	}

	//if the subjects list contains anything, then set up a pixmapobject...
	if (m_subjects.isEmpty())
	{
		//nada...bail
		m_viewport = QRectF();
		return;
	}

	setupBackingFb(pScene->sceneRect().size().toSize());
	m_triggerAble = true;
}
void drawKdenliveTitle( producer_ktitle self, mlt_frame frame, int width, int height, double position, int force_refresh )
{
  	// Obtain the producer 
	mlt_producer producer = &self->parent;
	mlt_profile profile = mlt_service_profile ( MLT_PRODUCER_SERVICE( producer ) ) ;
	mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer );

	// Obtain properties of frame
	mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
        
        pthread_mutex_lock( &self->mutex );
	
	// Check if user wants us to reload the image
	if ( mlt_properties_get( producer_props, "_animated" ) != NULL || force_refresh == 1 || width != self->current_width || height != self->current_height || mlt_properties_get( producer_props, "_endrect" ) != NULL )
	{
		//mlt_cache_item_close( self->image_cache );
		self->current_image = NULL;
		mlt_properties_set_data( producer_props, "cached_image", NULL, 0, NULL, NULL );
		mlt_properties_set_int( producer_props, "force_reload", 0 );
	}
	
	if (self->current_image == NULL) {
		// restore QGraphicsScene
		QGraphicsScene *scene = static_cast<QGraphicsScene *> (mlt_properties_get_data( producer_props, "qscene", NULL ));

		if ( force_refresh == 1 && scene )
		{
			scene = NULL;
			mlt_properties_set_data( producer_props, "qscene", NULL, 0, NULL, NULL );
		}

		if ( scene == NULL )
		{
			int argc = 1;
			char* argv[1];
			argv[0] = (char*) "xxx";
			
			// Warning: all Qt graphic objects (QRect, ...) must be initialized AFTER 
			// the QApplication is created, otherwise their will be NULL
			
			if ( app == NULL ) {
				if ( qApp ) {
					app = qApp;
				}
				else {
#ifdef linux
					if ( getenv("DISPLAY") == 0 )
					{
						mlt_log_panic( MLT_PRODUCER_SERVICE( producer ), "Error, cannot render titles without an X11 environment.\nPlease either run melt from an X session or use a fake X server like xvfb:\nxvfb-run -a melt (...)\n" );
						pthread_mutex_unlock( &self->mutex );
						return;
					}
#endif
					app = new QApplication( argc, argv );				
					const char *localename = mlt_properties_get_lcnumeric( MLT_SERVICE_PROPERTIES( MLT_PRODUCER_SERVICE( producer ) ) );
					QLocale::setDefault( QLocale( localename ) );
				}
				qRegisterMetaType<QTextCursor>( "QTextCursor" );
			}
			scene = new QGraphicsScene();
			scene->setItemIndexMethod( QGraphicsScene::NoIndex );
                        scene->setSceneRect(0, 0, mlt_properties_get_int( properties, "width" ), mlt_properties_get_int( properties, "height" ));
			if ( mlt_properties_get( producer_props, "resource" ) && mlt_properties_get( producer_props, "resource" )[0] != '\0' )
			{
				// The title has a resource property, so we read all properties from the resource.
				// Do not serialize the xmldata
				loadFromXml( producer, scene, mlt_properties_get( producer_props, "_xmldata" ), mlt_properties_get( producer_props, "templatetext" ) );
			}
			else
			{
				// The title has no resource, all data should be serialized
				loadFromXml( producer, scene, mlt_properties_get( producer_props, "xmldata" ), mlt_properties_get( producer_props, "templatetext" ) );
			  
			}
			mlt_properties_set_data( producer_props, "qscene", scene, 0, ( mlt_destructor )qscene_delete, NULL );
		}
                
                QRectF start = stringToRect( QString( mlt_properties_get( producer_props, "_startrect" ) ) );
                QRectF end = stringToRect( QString( mlt_properties_get( producer_props, "_endrect" ) ) );
	
		int originalWidth = mlt_properties_get_int( producer_props, "_original_width" );
		int originalHeight= mlt_properties_get_int( producer_props, "_original_height" );
		const QRectF source( 0, 0, width, height );
		if (start.isNull()) {
		    start = QRectF( 0, 0, originalWidth, originalHeight );
		}

		// Effects
		QList <QGraphicsItem *> items = scene->items();
		QGraphicsTextItem *titem = NULL;
		for (int i = 0; i < items.count(); i++) {
		    titem = static_cast <QGraphicsTextItem*> ( items.at( i ) );
		    if (titem && !titem->data( 0 ).isNull()) {
			    QStringList params = titem->data( 0 ).toStringList();
			    if (params.at( 0 ) == "typewriter" ) {
				    // typewriter effect has 2 param values:
				    // the keystroke delay and a start offset, both in frames
				    QStringList values = params.at( 2 ).split( ";" );
				    int interval = qMax( 0, ( ( int ) position - values.at( 1 ).toInt()) / values.at( 0 ).toInt() );
				    QTextCursor cursor = titem->textCursor();
				    cursor.movePosition(QTextCursor::EndOfBlock);
				    // get the font format
				    QTextCharFormat format = cursor.charFormat();
				    cursor.select(QTextCursor::Document);
				    QString txt = params.at( 1 ).left( interval );
				    // If the string to insert is empty, insert a space / linebreak so that we don't loose
				    // formatting infos for the next iterations
				    int lines = params.at( 1 ).count( '\n' );
				    QString empty = " ";
				    for (int i = 0; i < lines; i++)
					    empty.append( "\n " );
				    cursor.insertText( txt.isEmpty() ? empty : txt, format );
				    if ( !titem->data( 1 ).isNull() )
					  titem->setTextWidth( titem->data( 1 ).toDouble() );
			    }
		    }
		}

		//must be extracted from kdenlive title
		QImage img( width, height, QImage::Format_ARGB32 );
		img.fill( 0 );
		QPainter p1;
		p1.begin( &img );
		p1.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing );
		//| QPainter::SmoothPixmapTransform );
                mlt_position anim_out = mlt_properties_get_position( producer_props, "_animation_out" );

		if (end.isNull())
		{
			scene->render( &p1, source, start, Qt::IgnoreAspectRatio );
		}
		else if ( position > anim_out ) {
                        scene->render( &p1, source, end, Qt::IgnoreAspectRatio );
                }
		else {
                        double percentage = 0;
			if ( position && anim_out )
				percentage = position / anim_out;
			QPointF topleft = start.topLeft() + ( end.topLeft() - start.topLeft() ) * percentage;
			QPointF bottomRight = start.bottomRight() + ( end.bottomRight() - start.bottomRight() ) * percentage;
			const QRectF r1( topleft, bottomRight );
			scene->render( &p1, source, r1, Qt::IgnoreAspectRatio );
			if ( profile && !profile->progressive ){
				int line=0;
				double percentage_next_filed	= ( position + 0.5 ) / anim_out;
				QPointF topleft_next_field = start.topLeft() + ( end.topLeft() - start.topLeft() ) * percentage_next_filed;
				QPointF bottomRight_next_field = start.bottomRight() + ( end.bottomRight() - start.bottomRight() ) * percentage_next_filed;
				const QRectF r2( topleft_next_field, bottomRight_next_field );
				QImage img1( width, height, QImage::Format_ARGB32 );
				img1.fill( 0 );
				QPainter p2;
				p2.begin(&img1);
				p2.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing );
				scene->render(&p2,source,r2,  Qt::IgnoreAspectRatio );
				p2.end();
				int next_field_line = (  mlt_properties_get_int( producer_props, "top_field_first" ) ? 1 : 0 );
				for (line = next_field_line ;line<height;line+=2){
						memcpy(img.scanLine(line),img1.scanLine(line),img.bytesPerLine());
				}

			}
		}
		p1.end();

		int size = width * height * 4;
		uint8_t *pointer=img.bits();
		QRgb* src = ( QRgb* ) pointer;
		self->current_image = ( uint8_t * )mlt_pool_alloc( size );
		uint8_t *dst = self->current_image;
	
		for ( int i = 0; i < width * height * 4; i += 4 )
		{
			*dst++=qRed( *src );
			*dst++=qGreen( *src );
			*dst++=qBlue( *src );
			*dst++=qAlpha( *src );
			src++;
		}

		mlt_properties_set_data( producer_props, "cached_image", self->current_image, size, mlt_pool_release, NULL );
		self->current_width = width;
		self->current_height = height;
	}

	pthread_mutex_unlock( &self->mutex );
	mlt_properties_set_int( properties, "width", self->current_width );
	mlt_properties_set_int( properties, "height", self->current_height );
}