]> git.sesse.net Git - mlt/blobdiff - src/modules/qimage/kdenlivetitle_wrapper.cpp
Add support for Qt 5, drop support for Qt 3 and KDE 3.
[mlt] / src / modules / qimage / kdenlivetitle_wrapper.cpp
index e1202e3d5355dc57c9fdeb64b4b01ce22eee6350..2d5bc4d6bf0df243cebfbc52348a552213771f4a 100755 (executable)
 
 #include "kdenlivetitle_wrapper.h"
 
-#include <QtGui/QImage>
-#include <QtGui/QPainter>
-#include <QtCore/QDebug>
-#include <QtGui/QApplication>
-#include <QtCore/QMutex>
-#include <QtGui/QGraphicsScene>
-#include <QtGui/QGraphicsTextItem>
-#include <QtSvg/QGraphicsSvgItem>
-#include <QtGui/QTextCursor>
-#include <QtGui/QTextDocument>
-#include <QtGui/QStyleOptionGraphicsItem>
-
-#include <QtCore/QString>
-
-#include <QtXml/QDomElement>
-#include <QtCore/QRectF>
-#include <QtGui/QColor>
-#include <QtGui/QWidget>
+#include <QImage>
+#include <QPainter>
+#include <QDebug>
+#include <QApplication>
+#include <QMutex>
+#include <QGraphicsScene>
+#include <QGraphicsTextItem>
+#include <QGraphicsSvgItem>
+#include <QSvgRenderer>
+#include <QTextCursor>
+#include <QTextDocument>
+#include <QStyleOptionGraphicsItem>
+
+#include <QString>
+
+#include <QDomElement>
+#include <QRectF>
+#include <QColor>
+#include <QWidget>
 #include <framework/mlt_log.h>
 
 #if QT_VERSION >= 0x040600
-#include <QtGui/QGraphicsEffect>
-#include <QtGui/QGraphicsBlurEffect>
-#include <QtGui/QGraphicsDropShadowEffect>
+#include <QGraphicsEffect>
+#include <QGraphicsBlurEffect>
+#include <QGraphicsDropShadowEffect>
 #endif
 
 static QApplication *app = NULL;
+Q_DECLARE_METATYPE(QTextCursor);
 
 class ImageItem: public QGraphicsItem
 {
@@ -75,26 +77,6 @@ virtual void paint( QPainter *painter,
 };
 
 
-QString rectTransform( QString s, QTransform t )
-{
-       QStringList l = s.split( ',' );
-       return QString::number(l.at(0).toDouble() * t.m11()) + ',' + QString::number(l.at(1).toDouble() * t.m22()) + ',' + QString::number(l.at(2).toDouble() * t.m11()) + ',' + QString::number(l.at(3).toDouble() * t.m22());
-}
-
-QString colorToString( const QColor& c )
-{
-       QString ret = "%1,%2,%3,%4";
-       ret = ret.arg( c.red() ).arg( c.green() ).arg( c.blue() ).arg( c.alpha() );
-       return ret;
-}
-
-QString rectFToString( const QRectF& c )
-{
-       QString ret = "%1,%2,%3,%4";
-       ret = ret.arg( c.top() ).arg( c.left() ).arg( c.width() ).arg( c.height() );
-       return ret;
-}
-
 QRectF stringToRect( const QString & s )
 {
 
@@ -141,10 +123,16 @@ void loadFromXml( mlt_producer producer, QGraphicsScene *scene, const char *temp
        QString replacementText = QString::fromUtf8(templateText);
        doc.setContent(data);
        QDomElement title = doc.documentElement();
-       
+
        // Check for invalid title
        if ( title.isNull() || title.tagName() != "kdenlivetitle" ) return;
        
+       // Check title locale
+       if ( title.hasAttribute( "LC_NUMERIC" ) ) {
+           QString locale = title.attribute( "LC_NUMERIC" );
+           QLocale::setDefault( locale );
+       }
+       
         int originalWidth;
         int originalHeight;
        if ( title.hasAttribute("width") ) {
@@ -166,29 +154,32 @@ void loadFromXml( mlt_producer producer, QGraphicsScene *scene, const char *temp
        mlt_properties_set_int( producer_props, "_original_width", originalWidth );
        mlt_properties_set_int( producer_props, "_original_height", originalHeight );
 
+       QDomNode node;
        QDomNodeList items = title.elementsByTagName("item");
         for ( int i = 0; i < items.count(); i++ )
        {
                QGraphicsItem *gitem = NULL;
-               int zValue = items.item( i ).attributes().namedItem( "z-index" ).nodeValue().toInt();
+               node = items.item( i );
+               QDomNamedNodeMap nodeAttributes = node.attributes();
+               int zValue = nodeAttributes.namedItem( "z-index" ).nodeValue().toInt();
                if ( zValue > -1000 )
                {
-                       if ( items.item( i ).attributes().namedItem( "type" ).nodeValue() == "QGraphicsTextItem" )
+                       if ( nodeAttributes.namedItem( "type" ).nodeValue() == "QGraphicsTextItem" )
                        {
-                               QDomNamedNodeMap txtProperties = items.item( i ).namedItem( "content" ).attributes();
+                               QDomNamedNodeMap txtProperties = node.namedItem( "content" ).attributes();
                                QFont font( txtProperties.namedItem( "font" ).nodeValue() );
-                                       QDomNode node = txtProperties.namedItem( "font-bold" );
-                               if ( !node.isNull() )
+                               QDomNode propsNode = txtProperties.namedItem( "font-bold" );
+                               if ( !propsNode.isNull() )
                                {
-                               // Old: Bold/Not bold.
-                                       font.setBold( node.nodeValue().toInt() );
+                                       // Old: Bold/Not bold.
+                                       font.setBold( propsNode.nodeValue().toInt() );
                                }
                                else
                                {
                                        // New: Font weight (QFont::)
                                        font.setWeight( txtProperties.namedItem( "font-weight" ).nodeValue().toInt() );
                                }
-                                       font.setItalic( txtProperties.namedItem( "font-italic" ).nodeValue().toInt() );
+                               font.setItalic( txtProperties.namedItem( "font-italic" ).nodeValue().toInt() );
                                font.setUnderline( txtProperties.namedItem( "font-underline" ).nodeValue().toInt() );
                                // Older Kdenlive version did not store pixel size but point size
                                if ( txtProperties.namedItem( "font-pixel-size" ).isNull() )
@@ -200,14 +191,17 @@ void loadFromXml( mlt_producer producer, QGraphicsScene *scene, const char *temp
                                else
                                        font.setPixelSize( txtProperties.namedItem( "font-pixel-size" ).nodeValue().toInt() );
                                QColor col( stringToColor( txtProperties.namedItem( "font-color" ).nodeValue() ) );
-                               QString text = items.item( i ).namedItem( "content" ).firstChild().nodeValue();
+                               QString text = node.namedItem( "content" ).firstChild().nodeValue();
                                if ( !replacementText.isEmpty() )
                                {
                                        text = text.replace( "%s", replacementText );
                                }
                                QGraphicsTextItem *txt = scene->addText(text, font);
                                if (txtProperties.namedItem("font-outline").nodeValue().toDouble()>0.0){
-                                       QTextCursor cursor(txt->document());
+                                       QTextDocument *doc = txt->document();
+                                       // Make sure some that the text item does not request refresh by itself
+                                       doc->blockSignals(true);
+                                       QTextCursor cursor(doc);
                                        cursor.select(QTextCursor::Document);
                                        QTextCharFormat format;
                                        format.setTextOutline(
@@ -228,6 +222,8 @@ void loadFromXml( mlt_producer producer, QGraphicsScene *scene, const char *temp
                                        mlt_properties_set_int( producer_props, "_animated", 1 );
                                        QStringList effetData = QStringList() << "typewriter" << text << txtProperties.namedItem( "typewriter" ).nodeValue();
                                        txt->setData(0, effetData);
+                                       if ( !txtProperties.namedItem( "textwidth" ).isNull() )
+                                               txt->setData( 1, txtProperties.namedItem( "textwidth" ).nodeValue() );
                                }
                                
                                if ( txtProperties.namedItem( "alignment" ).isNull() == false )
@@ -247,39 +243,55 @@ void loadFromXml( mlt_producer producer, QGraphicsScene *scene, const char *temp
                                }
                                        gitem = txt;
                        }
-                       else if ( items.item( i ).attributes().namedItem( "type" ).nodeValue() == "QGraphicsRectItem" )
+                       else if ( nodeAttributes.namedItem( "type" ).nodeValue() == "QGraphicsRectItem" )
                        {
-                               QString rect = items.item( i ).namedItem( "content" ).attributes().namedItem( "rect" ).nodeValue();
-                               QString br_str = items.item( i ).namedItem( "content" ).attributes().namedItem( "brushcolor" ).nodeValue();
-                               QString pen_str = items.item( i ).namedItem( "content" ).attributes().namedItem( "pencolor" ).nodeValue();
-                               double penwidth = items.item( i ).namedItem( "content" ).attributes().namedItem( "penwidth") .nodeValue().toDouble();
+                               QString rect = node.namedItem( "content" ).attributes().namedItem( "rect" ).nodeValue();
+                               QString br_str = node.namedItem( "content" ).attributes().namedItem( "brushcolor" ).nodeValue();
+                               QString pen_str = node.namedItem( "content" ).attributes().namedItem( "pencolor" ).nodeValue();
+                               double penwidth = node.namedItem( "content" ).attributes().namedItem( "penwidth") .nodeValue().toDouble();
                                QGraphicsRectItem *rec = scene->addRect( stringToRect( rect ), QPen( QBrush( stringToColor( pen_str ) ), penwidth, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin ), QBrush( stringToColor( br_str ) ) );
                                gitem = rec;
                        }
-                       else if ( items.item( i ).attributes().namedItem( "type" ).nodeValue() == "QGraphicsPixmapItem" )
+                       else if ( nodeAttributes.namedItem( "type" ).nodeValue() == "QGraphicsPixmapItem" )
                        {
-                               const QString url = items.item( i ).namedItem( "content" ).attributes().namedItem( "url" ).nodeValue();
-                               QImage img( url );
+                               const QString url = node.namedItem( "content" ).attributes().namedItem( "url" ).nodeValue();
+                               const QString base64 = items.item(i).namedItem("content").attributes().namedItem("base64").nodeValue();
+                               QImage img;
+                               if (base64.isEmpty()){
+                                       img.load(url);
+                               }else{
+                                       img.loadFromData(QByteArray::fromBase64(base64.toLatin1()));
+                               }
                                ImageItem *rec = new ImageItem(img);
                                scene->addItem( rec );
                                gitem = rec;
                        }
-                       else if ( items.item( i ).attributes().namedItem( "type" ).nodeValue() == "QGraphicsSvgItem" )
+                       else if ( nodeAttributes.namedItem( "type" ).nodeValue() == "QGraphicsSvgItem" )
                        {
-                               const QString url = items.item( i ).namedItem( "content" ).attributes().namedItem( "url" ).nodeValue();
-                               QGraphicsSvgItem *rec = new QGraphicsSvgItem(url);
-                               scene->addItem(rec);
-                               gitem = rec;
+                               QString url = items.item(i).namedItem("content").attributes().namedItem("url").nodeValue();
+                               QString base64 = items.item(i).namedItem("content").attributes().namedItem("base64").nodeValue();
+                               QGraphicsSvgItem *rec = NULL;
+                               if (base64.isEmpty()){
+                                       rec = new QGraphicsSvgItem(url);
+                               }else{
+                                       rec = new QGraphicsSvgItem();
+                                       QSvgRenderer *renderer= new QSvgRenderer(QByteArray::fromBase64(base64.toLatin1()), rec );
+                                       rec->setSharedRenderer(renderer);
+                               }
+                               if (rec){
+                                       scene->addItem(rec);
+                                       gitem = rec;
+                               }
                        }
                }
                //pos and transform
                if ( gitem )
                {
-                       QPointF p( items.item( i ).namedItem( "position" ).attributes().namedItem( "x" ).nodeValue().toDouble(),
-                                  items.item( i ).namedItem( "position" ).attributes().namedItem( "y" ).nodeValue().toDouble() );
+                       QPointF p( node.namedItem( "position" ).attributes().namedItem( "x" ).nodeValue().toDouble(),
+                                  node.namedItem( "position" ).attributes().namedItem( "y" ).nodeValue().toDouble() );
                        gitem->setPos( p );
-                       gitem->setTransform( stringToTransform( items.item( i ).namedItem( "position" ).firstChild().firstChild().nodeValue() ) );
-                       int zValue = items.item( i ).attributes().namedItem( "z-index" ).nodeValue().toInt();
+                       gitem->setTransform( stringToTransform( node.namedItem( "position" ).firstChild().firstChild().nodeValue() ) );
+                       int zValue = nodeAttributes.namedItem( "z-index" ).nodeValue().toInt();
                        gitem->setZValue( zValue );
 
 #if QT_VERSION >= 0x040600
@@ -385,19 +397,30 @@ void drawKdenliveTitle( producer_ktitle self, mlt_frame frame, int width, int he
                                        {
                                                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 );
-                                               exit(1);
                                                return;
                                        }
 #endif
-                                       app = new QApplication( argc, argv );
-                                       //fix to let the decimal point for every locale be: "."
-                                       setlocale(LC_NUMERIC,"POSIX");
+                                       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" ));
-                       loadFromXml( producer, scene, mlt_properties_get( producer_props, "xmldata" ), mlt_properties_get( producer_props, "templatetext" ) );
+                       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 );
                }
                 
@@ -423,11 +446,21 @@ void drawKdenliveTitle( producer_ktitle self, mlt_frame frame, int width, int he
                                    // 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() );
-                                   QTextDocument *td = new QTextDocument( params.at( 1 ).left( interval ) );
-                                   td->setDefaultFont( titem->font() );
-                                   td->setDefaultTextOption( titem->document()->defaultTextOption() );
-                                   td->setTextWidth( titem->document()->textWidth() );
-                                   titem->setDocument( td );
+                                   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() );
                            }
                    }
                }
@@ -449,7 +482,9 @@ void drawKdenliveTitle( producer_ktitle self, mlt_frame frame, int width, int he
                         scene->render( &p1, source, end, Qt::IgnoreAspectRatio );
                 }
                else {
-                        double percentage = position / anim_out;
+                        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 );