]> git.sesse.net Git - kdenlive/blobdiff - src/titlewidget.cpp
Position of z-index number field changed
[kdenlive] / src / titlewidget.cpp
index 9d7f3f4866aa6f2909bd63a3819afbc736f65211..a9560b75cc3a0c4f0bc9488ee3e83088bb2340b6 100644 (file)
@@ -26,6 +26,7 @@
 #include <KStandardDirs>
 #include <KMessageBox>
 #include <kio/netaccess.h>
+#include <kdeversion.h>
 
 #include <QDomDocument>
 #include <QGraphicsItem>
 #include <QTextBlockFormat>
 #include <QTextCursor>
 
+#if QT_VERSION >= 0x040600
+#include <QGraphicsEffect>
+#include <QGraphicsBlurEffect>
+#include <QGraphicsDropShadowEffect>
+#endif
+
 int settingUp = false;
 
 const int IMAGEITEM = 7;
 const int RECTITEM = 3;
 const int TEXTITEM = 8;
-static bool insertingValues = false;
+
+const int NOEFFECT = 0;
+const int BLUREFFECT = 1;
+const int SHADOWEFFECT = 2;
+const int TYPEWRITEREFFECT = 3;
 
 TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render *render, QWidget *parent) :
         QDialog(parent),
@@ -57,18 +68,13 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
 {
     setupUi(this);
     setFont(KGlobalSettings::toolBarFont());
-    //toolBox->setFont(KGlobalSettings::toolBarFont());
     frame_properties->setEnabled(false);
-    rect_properties->setFixedHeight(frame_properties->height() + 4);
-    no_properties->setFixedHeight(frame_properties->height() + 4);
-    image_properties->setFixedHeight(frame_properties->height() + 4);
-    text_properties->setFixedHeight(frame_properties->height() + 4);
     frame_properties->setFixedHeight(frame_toolbar->height());
 
     itemzoom->setSuffix(i18n("%"));
     m_frameWidth = render->renderWidth();
     m_frameHeight = render->renderHeight();
-    showToolbars(TITLE_NONE);
+    showToolbars(TITLE_SELECT);
 
     //TODO: get default title duration instead of hardcoded one
     title_duration->setText(m_tc.getTimecode(GenTime(5000 / 1000.0)));
@@ -82,6 +88,8 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     connect(textAlpha, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateText()));
     connect(font_weight_box, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateText()));
 
+    connect(font_family, SIGNAL(editTextChanged(const QString &)), this, SLOT(slotFontText(const QString&)));
+
     connect(rectFAlpha, SIGNAL(valueChanged(int)), this, SLOT(rectChanged()));
     connect(rectBAlpha, SIGNAL(valueChanged(int)), this, SLOT(rectChanged()));
     connect(rectFColor, SIGNAL(clicked()), this, SLOT(rectChanged()));
@@ -95,6 +103,12 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     connect(endViewportY, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));
     connect(endViewportSize, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));*/
 
+    // Fill effects
+    effect_list->addItem(i18n("None"), NOEFFECT);
+    effect_list->addItem(i18n("Typewriter"), TYPEWRITEREFFECT);
+    effect_list->addItem(i18n("Blur"), BLUREFFECT);
+
+
     connect(zValue, SIGNAL(valueChanged(int)), this, SLOT(zIndexChanged(int)));
     connect(itemzoom, SIGNAL(valueChanged(int)), this, SLOT(itemScaled(int)));
     connect(itemrotate, SIGNAL(valueChanged(int)), this, SLOT(itemRotate(int)));
@@ -104,6 +118,15 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     connect(itembottom, SIGNAL(clicked()), this, SLOT(itemBottom()));
     connect(itemleft, SIGNAL(clicked()), this, SLOT(itemLeft()));
     connect(itemright, SIGNAL(clicked()), this, SLOT(itemRight()));
+    connect(effect_list, SIGNAL(currentIndexChanged(int)), this, SLOT(slotAddEffect(int)));
+    connect(typewriter_delay, SIGNAL(valueChanged(int)), this, SLOT(slotEditTypewriter(int)));
+    connect(typewriter_start, SIGNAL(valueChanged(int)), this, SLOT(slotEditTypewriter(int)));
+    connect(blur_radius, SIGNAL(valueChanged(int)), this, SLOT(slotEditBlur(int)));
+    connect(shadow_radius, SIGNAL(valueChanged(int)), this, SLOT(slotEditShadow()));
+    connect(shadow_x, SIGNAL(valueChanged(int)), this, SLOT(slotEditShadow()));
+    connect(shadow_y, SIGNAL(valueChanged(int)), this, SLOT(slotEditShadow()));
+    effect_stack->setHidden(true);
+    effect_frame->setEnabled(false);
 
     connect(origin_x_left, SIGNAL(clicked()), this, SLOT(slotOriginXClicked()));
     connect(origin_y_top, SIGNAL(clicked()), this, SLOT(slotOriginYClicked()));
@@ -165,6 +188,37 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     connect(m_unicodeAction, SIGNAL(triggered()), this, SLOT(slotInsertUnicode()));
     buttonInsertUnicode->setDefaultAction(m_unicodeAction);
 
+    m_zUp = new QAction(KIcon("kdenlive-zindex-up"), QString(), this);
+    m_zUp->setShortcut(Qt::Key_PageUp);
+    m_zUp->setToolTip(i18n("Raise object"));
+    connect(m_zUp, SIGNAL(triggered()), this, SLOT(slotZIndexUp()));
+    zUp->setDefaultAction(m_zUp);
+
+    m_zDown = new QAction(KIcon("kdenlive-zindex-down"), QString(), this);
+    m_zDown->setShortcut(Qt::Key_PageDown);
+    m_zDown->setToolTip(i18n("Lower object"));
+    connect(m_zDown, SIGNAL(triggered()), this, SLOT(slotZIndexDown()));
+    zDown->setDefaultAction(m_zDown);
+
+    m_zTop = new QAction(KIcon("kdenlive-zindex-top"), QString(), this);
+    m_zTop->setShortcut(Qt::Key_Home);
+    m_zTop->setToolTip(i18n("Raise object to top"));
+    connect(m_zTop, SIGNAL(triggered()), this, SLOT(slotZIndexTop()));
+    zTop->setDefaultAction(m_zTop);
+
+    m_zBottom = new QAction(KIcon("kdenlive-zindex-bottom"), QString(), this);
+    m_zBottom->setShortcut(Qt::Key_End);
+    m_zBottom->setToolTip(i18n("Lower object to bottom"));
+    connect(m_zBottom, SIGNAL(triggered()), this, SLOT(slotZIndexBottom()));
+    zBottom->setDefaultAction(m_zBottom);
+
+    zDown->setIcon(KIcon("kdenlive-zindex-down"));
+    zTop->setIcon(KIcon("kdenlive-zindex-top"));
+    zBottom->setIcon(KIcon("kdenlive-zindex-bottom"));
+    connect(zDown, SIGNAL(clicked()), this, SLOT(slotZIndexDown()));
+    connect(zTop, SIGNAL(clicked()), this, SLOT(slotZIndexTop()));
+    connect(zBottom, SIGNAL(clicked()), this, SLOT(slotZIndexBottom()));
+
     origin_x_left->setToolTip(i18n("Invert x axis and change 0 point"));
     origin_y_top->setToolTip(i18n("Invert y axis and change 0 point"));
     rectBColor->setToolTip(i18n("Select fill color"));
@@ -193,8 +247,10 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
 
     QHBoxLayout *layout = new QHBoxLayout;
     frame_toolbar->setLayout(layout);
-    layout->setContentsMargins(2, 2, 2, 2);
+    layout->setContentsMargins(0, 0, 0, 0);
     QToolBar *m_toolbar = new QToolBar("titleToolBar", this);
+    int s = style()->pixelMetric(QStyle::PM_SmallIconSize);
+    m_toolbar->setIconSize(QSize(s, s));
 
     m_buttonCursor = m_toolbar->addAction(KIcon("transform-move"), QString());
     m_buttonCursor->setCheckable(true);
@@ -297,6 +353,8 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     initAnimation();
     connect(anim_start, SIGNAL(toggled(bool)), this, SLOT(slotAnimStart(bool)));
     connect(anim_end, SIGNAL(toggled(bool)), this, SLOT(slotAnimEnd(bool)));
+
+    buttonBox->button(QDialogButtonBox::Ok)->setEnabled(KdenliveSettings::hastitleproducer());
 }
 
 TitleWidget::~TitleWidget()
@@ -308,6 +366,10 @@ TitleWidget::~TitleWidget()
     delete m_buttonSave;
     delete m_buttonLoad;
     delete m_unicodeAction;
+    delete m_zUp;
+    delete m_zDown;
+    delete m_zTop;
+    delete m_zBottom;
 
     delete m_unicodeDialog;
     delete m_frameBorder;
@@ -336,6 +398,7 @@ QStringList TitleWidget::getFreeTitleInfo(const KUrl &projectUrl, bool isClone)
     return result;
 }
 
+// static
 QString TitleWidget::getTitleResourceFromName(const KUrl &projectUrl, const QString &titleName)
 {
     QStringList result;
@@ -344,6 +407,22 @@ QString TitleWidget::getTitleResourceFromName(const KUrl &projectUrl, const QStr
     return titlePath + titleName + ".png";
 }
 
+// static
+QStringList TitleWidget::extractImageList(QString xml)
+{
+    QStringList result;
+    if (xml.isEmpty()) return result;
+    QDomDocument doc;
+    doc.setContent(xml);
+    QDomNodeList images = doc.elementsByTagName("content");
+    for (int i = 0; i < images.count(); i++) {
+        if (images.at(i).toElement().hasAttribute("url"))
+            result.append(images.at(i).toElement().attribute("url"));
+    }
+    return result;
+}
+
+
 //virtual
 void TitleWidget::resizeEvent(QResizeEvent * /*event*/)
 {
@@ -388,7 +467,7 @@ void TitleWidget::slotSelectTool()
     enableToolbars(t);
     if (t == TITLE_RECTANGLE && (l.at(0) == m_endViewport || l.at(0) == m_startViewport)) {
         //graphicsView->centerOn(l.at(0));
-        t = TITLE_NONE;
+        t = TITLE_SELECT;
     }
     showToolbars(t);
 
@@ -403,7 +482,9 @@ void TitleWidget::slotSelectTool()
 
 void TitleWidget::slotImageTool()
 {
-    KUrl url = KFileDialog::getOpenUrl(KUrl(), "*.svg *.png *.jpg *.jpeg *.gif *.raw", this, i18n("Load Image"));
+    // TODO: find a way to get a list of all supported image types...
+    QString allExtensions = "image/gif image/jpeg image/png image/x-tga image/x-bmp image/svg+xml image/tiff image/x-xcf-gimp image/x-vnd.adobe.photoshop image/x-pcx image/x-exr";
+    KUrl url = KFileDialog::getOpenUrl(KUrl(), allExtensions, this, i18n("Load Image")); //"*.svg *.png *.jpg *.jpeg *.gif *.raw"
     if (!url.isEmpty()) {
         if (url.path().endsWith(".svg")) {
             QGraphicsSvgItem *svg = new QGraphicsSvgItem(url.toLocalFile());
@@ -423,77 +504,21 @@ void TitleWidget::slotImageTool()
     }
     m_scene->setTool(TITLE_SELECT);
     showToolbars(TITLE_SELECT);
-    checkButton(TITLE_NONE);
+    checkButton(TITLE_SELECT);
 }
 
 void TitleWidget::showToolbars(TITLETOOL toolType)
 {
-    switch (toolType) {
-    case TITLE_TEXT:
-        rect_properties->setHidden(true);
-        image_properties->setHidden(true);
-        no_properties->setHidden(true);
-        text_properties->setHidden(false);
-        break;
-    case TITLE_RECTANGLE:
-        image_properties->setHidden(true);
-        no_properties->setHidden(true);
-        text_properties->setHidden(true);
-        rect_properties->setHidden(false);
-        break;
-    case TITLE_IMAGE:
-        no_properties->setHidden(true);
-        text_properties->setHidden(true);
-        rect_properties->setHidden(true);
-        image_properties->setHidden(false);
-        break;
-    default:
-        text_properties->setHidden(true);
-        rect_properties->setHidden(true);
-        image_properties->setHidden(true);
-        no_properties->setHidden(false);
-        break;
-    }
+    toolbar_stack->setCurrentIndex((int) toolType);
 }
 
 void TitleWidget::enableToolbars(TITLETOOL toolType)
 {
     // TITLETOOL is defined in graphicsscenerectmove.h
-    bool bFrame = false;
-    bool bText = false;
-    bool bRect = false;
-    bool bImage = false;
-    bool bValue_w = false;
-    bool bValue_h = false;
-
-    switch (toolType) {
-    case TITLE_SELECT:
-        break;
-    case TITLE_TEXT:
-        bFrame = true;
-        bText = true;
-        break;
-    case TITLE_RECTANGLE:
-        bFrame = true;
-        bRect = true;
-        bValue_w = true;
-        bValue_h = true;
-        break;
-    case TITLE_IMAGE:
-        bFrame = true;
-        bValue_w = true;
-        bValue_h = true;
-        bImage = true;
-        break;
-    default:
-        break;
-    }
-    frame_properties->setEnabled(bFrame);
-    text_properties->setEnabled(bText);
-    rect_properties->setEnabled(bRect);
-    image_properties->setEnabled(bImage);
-    value_w->setEnabled(bValue_w);
-    value_h->setEnabled(bValue_h);
+    bool enable = false;
+    if (toolType == TITLE_RECTANGLE || toolType == TITLE_IMAGE) enable = true;
+    value_w->setEnabled(enable);
+    value_h->setEnabled(enable);
 }
 
 void TitleWidget::checkButton(TITLETOOL toolType)
@@ -516,7 +541,7 @@ void TitleWidget::checkButton(TITLETOOL toolType)
     case TITLE_IMAGE:
         bImage = true;
         break;
-    case TITLE_NONE:
+    default:
         break;
     }
 
@@ -678,6 +703,9 @@ void TitleWidget::selectionChanged()
     itemzoom->blockSignals(true);
     itemrotate->blockSignals(true);
     if (l.size() == 0) {
+        effect_stack->setHidden(true);
+        effect_frame->setEnabled(false);
+        effect_list->setCurrentIndex(0);
         bool blockX = !origin_x_left->signalsBlocked();
         bool blockY = !origin_y_top->signalsBlocked();
         if (blockX) origin_x_left->blockSignals(true);
@@ -686,22 +714,69 @@ void TitleWidget::selectionChanged()
         origin_y_top->setChecked(false);
         updateTextOriginX();
         updateTextOriginY();
-        enableToolbars(TITLE_NONE);
+        enableToolbars(TITLE_SELECT);
         if (blockX) origin_x_left->blockSignals(false);
         if (blockY) origin_y_top->blockSignals(false);
         itemzoom->setEnabled(false);
         itemrotate->setEnabled(false);
+        frame_properties->setEnabled(false);
     } else if (l.size() == 1) {
+        effect_frame->setEnabled(true);
+        frame_properties->setEnabled(true);
         if (l.at(0) != m_startViewport && l.at(0) != m_endViewport) {
             itemzoom->setEnabled(true);
             itemrotate->setEnabled(true);
         } else {
             itemzoom->setEnabled(false);
             itemrotate->setEnabled(false);
+            updateInfoText();
         }
         if (l.at(0)->type() == TEXTITEM) {
             showToolbars(TITLE_TEXT);
             QGraphicsTextItem* i = static_cast <QGraphicsTextItem *>(l.at(0));
+            if (!i->data(100).isNull()) {
+                // Item has an effect
+                QStringList effdata = i->data(100).toStringList();
+                QString effectName = effdata.takeFirst();
+                if (effectName == "typewriter") {
+                    QStringList params = effdata.at(0).split(';');
+                    typewriter_delay->setValue(params.at(0).toInt());
+                    typewriter_start->setValue(params.at(1).toInt());
+                    effect_list->setCurrentIndex(effect_list->findData((int) TYPEWRITEREFFECT));
+                    effect_stack->setHidden(false);
+                }
+            } else {
+#if QT_VERSION >= 0x040600
+                if (i->graphicsEffect()) {
+                    QGraphicsBlurEffect *blur = static_cast <QGraphicsBlurEffect *>(i->graphicsEffect());
+                    if (blur) {
+                        effect_list->setCurrentIndex(effect_list->findData((int) BLUREFFECT));
+                        int rad = (int) blur->blurRadius();
+                        blur_radius->setValue(rad);
+                        effect_stack->setHidden(false);
+                    } else {
+                        QGraphicsDropShadowEffect *shad = static_cast <QGraphicsDropShadowEffect *>(i->graphicsEffect());
+                        if (shad) {
+                            effect_list->setCurrentIndex(effect_list->findData((int) SHADOWEFFECT));
+                            shadow_radius->setValue(shad->blurRadius());
+                            shadow_x->setValue(shad->xOffset());
+                            shadow_y->setValue(shad->yOffset());
+                            effect_stack->setHidden(false);
+                        }
+                    }
+                } else {
+                    effect_list->blockSignals(true);
+                    effect_list->setCurrentIndex(effect_list->findData((int) NOEFFECT));
+                    effect_list->blockSignals(false);
+                    effect_stack->setHidden(true);
+                }
+#else
+                effect_list->blockSignals(true);
+                effect_list->setCurrentIndex(effect_list->findData((int) NOEFFECT));
+                effect_list->blockSignals(false);
+                effect_stack->setHidden(true);
+#endif
+            }
             //if (l[0]->hasFocus())
             //toolBox->setCurrentIndex(0);
             //toolBox->setItemEnabled(2, true);
@@ -760,7 +835,7 @@ void TitleWidget::selectionChanged()
                 /*toolBox->setCurrentIndex(3);
                 toolBox->widget(0)->setEnabled(false);
                 toolBox->widget(1)->setEnabled(false);*/
-                enableToolbars(TITLE_NONE);
+                enableToolbars(TITLE_SELECT);
             } else {
                 /*toolBox->widget(0)->setEnabled(true);
                 toolBox->widget(1)->setEnabled(true);
@@ -794,11 +869,9 @@ void TitleWidget::selectionChanged()
 
         } else {
             //toolBox->setCurrentIndex(0);
-            showToolbars(TITLE_NONE);
-            enableToolbars(TITLE_NONE);
-            /*frame_properties->setEnabled(false);
-            text_properties->setEnabled(false);
-            rect_properties->setEnabled(false);*/
+            showToolbars(TITLE_SELECT);
+            enableToolbars(TITLE_SELECT);
+            frame_properties->setEnabled(false);
         }
         zValue->setValue((int)l.at(0)->zValue());
         itemzoom->setValue((int)(m_transformations.value(l.at(0)).scalex * 100.0 + 0.5));
@@ -891,8 +964,9 @@ void TitleWidget::updateDimension(QGraphicsItem *i)
 {
     value_w->blockSignals(true);
     value_h->blockSignals(true);
+    zValue->blockSignals(true);
 
-
+    zValue->setValue((int) i->zValue());
     if (i->type() == IMAGEITEM) {
         // Get multipliers for rotation/scaling
 
@@ -915,6 +989,7 @@ void TitleWidget::updateDimension(QGraphicsItem *i)
         value_h->setValue((int) t->boundingRect().height());
     }
 
+    zValue->blockSignals(false);
     value_w->blockSignals(false);
     value_h->blockSignals(false);
 }
@@ -1447,10 +1522,12 @@ void TitleWidget::saveTitle(KUrl url)
     if (anim_start->isChecked()) slotAnimStart(false);
     if (anim_end->isChecked()) slotAnimEnd(false);
     if (url.isEmpty()) {
-        KFileDialog *fs = new KFileDialog(KUrl(m_projectTitlePath), "application/x-kdenlivetitle",this);
+        KFileDialog *fs = new KFileDialog(KUrl(m_projectTitlePath), "application/x-kdenlivetitle", this);
         fs->setOperationMode(KFileDialog::Saving);
         fs->setMode(KFile::File);
+#if KDE_IS_VERSION(4,2,0)
         fs->setConfirmOverwrite(true);
+#endif
         fs->setKeepLocation(true);
         fs->exec();
         url = fs->selectedUrl();
@@ -1612,7 +1689,7 @@ void TitleWidget::slotAnimStart(bool anim)
     itemzoom->setEnabled(!anim);
     itemrotate->setEnabled(!anim);
     frame_toolbar->setEnabled(!anim);
-    rect_properties->setEnabled(!anim);
+    toolbar_stack->setEnabled(!anim);
     if (anim) {
         keep_aspect->setChecked(!m_startViewport->data(0).isNull());
         m_startViewport->setZValue(1100);
@@ -1623,10 +1700,12 @@ void TitleWidget::slotAnimStart(bool anim)
         m_startViewport->setSelected(true);
         selectionChanged();
         slotSelectTool();
+        if (m_startViewport->childItems().isEmpty()) addAnimInfoText();
     } else {
         m_startViewport->setZValue(-1000);
         m_startViewport->setBrush(QBrush());
         m_startViewport->setFlags(0);
+        if (!anim_end->isChecked()) deleteAnimInfoText();
     }
 
 }
@@ -1650,7 +1729,7 @@ void TitleWidget::slotAnimEnd(bool anim)
     itemzoom->setEnabled(!anim);
     itemrotate->setEnabled(!anim);
     frame_toolbar->setEnabled(!anim);
-    rect_properties->setEnabled(!anim);
+    toolbar_stack->setEnabled(!anim);
     if (anim) {
         keep_aspect->setChecked(!m_endViewport->data(0).isNull());
         m_endViewport->setZValue(1100);
@@ -1661,13 +1740,70 @@ void TitleWidget::slotAnimEnd(bool anim)
         m_endViewport->setSelected(true);
         selectionChanged();
         slotSelectTool();
+        if (m_endViewport->childItems().isEmpty()) addAnimInfoText();
     } else {
         m_endViewport->setZValue(-1000);
         m_endViewport->setBrush(QBrush());
         m_endViewport->setFlags(0);
+        if (!anim_start->isChecked()) deleteAnimInfoText();
     }
 }
 
+void TitleWidget::addAnimInfoText()
+{
+    // add text to anim viewport
+    QGraphicsTextItem *t = new QGraphicsTextItem(i18n("Start"), m_startViewport);
+    QGraphicsTextItem *t2 = new QGraphicsTextItem(i18n("End"), m_endViewport);
+    QFont font = t->font();
+    font.setPixelSize(m_startViewport->rect().width() / 10);
+    QColor col = m_startViewport->pen().color();
+    col.setAlpha(255);
+    t->setDefaultTextColor(col);
+    t->setFont(font);
+    font.setPixelSize(m_endViewport->rect().width() / 10);
+    col = m_endViewport->pen().color();
+    col.setAlpha(255);
+    t2->setDefaultTextColor(col);
+    t2->setFont(font);
+}
+
+void TitleWidget::updateInfoText()
+{
+    // update info text font
+    if (!m_startViewport->childItems().isEmpty()) {
+        QGraphicsTextItem *item = static_cast <QGraphicsTextItem *>(m_startViewport->childItems().at(0));
+        if (item) {
+            QFont font = item->font();
+            font.setPixelSize(m_startViewport->rect().width() / 10);
+            item->setFont(font);
+        }
+    }
+    if (!m_endViewport->childItems().isEmpty()) {
+        QGraphicsTextItem *item = static_cast <QGraphicsTextItem *>(m_endViewport->childItems().at(0));
+        if (item) {
+            QFont font = item->font();
+            font.setPixelSize(m_endViewport->rect().width() / 10);
+            item->setFont(font);
+        }
+    }
+}
+
+void TitleWidget::deleteAnimInfoText()
+{
+    // end animation editing, remove info text
+    while (!m_startViewport->childItems().isEmpty()) {
+        QGraphicsItem *item = m_startViewport->childItems().at(0);
+        m_scene->removeItem(item);
+        delete item;
+    }
+    while (!m_endViewport->childItems().isEmpty()) {
+        QGraphicsItem *item = m_endViewport->childItems().at(0);
+        m_scene->removeItem(item);
+        delete item;
+    }
+}
+
+
 void TitleWidget::slotKeepAspect(bool keep)
 {
     if (m_endViewport->zValue() == 1100) {
@@ -1700,5 +1836,174 @@ void TitleWidget::slotResize200()
     } else m_startViewport->setRect(0, 0, m_frameWidth * 2, m_frameHeight * 2);
 }
 
+void TitleWidget::slotAddEffect(int ix)
+{
+    QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
+    int effect = effect_list->itemData(ix).toInt();
+    if (effect == NOEFFECT) {
+        if (l.size() == 1) l[0]->setData(100, QVariant());
+        effect_stack->setHidden(true);
+        return;
+    }
+    effect_stack->setCurrentIndex(effect - 1);
+    effect_stack->setHidden(false);
+    if (effect == TYPEWRITEREFFECT) {
+        if (l.size() == 1 && l.at(0)->type() == TEXTITEM) {
+            QStringList effdata = QStringList() << "typewriter" << QString::number(typewriter_delay->value()) + ";" + QString::number(typewriter_start->value());
+            l[0]->setData(100, effdata);
+        }
+    }
+#if QT_VERSION < 0x040600
+    return;
+#else
+    if (effect == BLUREFFECT) {
+        // Blur effect
+        if (l.size() == 1) {
+            QGraphicsEffect *eff = new QGraphicsBlurEffect();
+            l[0]->setGraphicsEffect(eff);
+        }
+    } else if (effect == SHADOWEFFECT) {
+        if (l.size() == 1) {
+            QGraphicsEffect *eff = new QGraphicsDropShadowEffect();
+            l[0]->setGraphicsEffect(eff);
+        }
+    }
+
+#endif
+}
+
 
+void TitleWidget::slotFontText(const QString& s)
+{
+    const QFont f(s);
+    if (f.exactMatch()) {
+        // Font really exists (could also just be a «d» if the user
+        // starts typing «dejavu» for example).
+        font_family->setCurrentFont(f);
+    }
+    // Note: Typing dejavu serif does not recognize the font (takes sans)
+    // in older Qt versions.
+}
+
+void TitleWidget::slotEditTypewriter(int ix)
+{
+    QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
+    if (l.size() == 1) {
+        QStringList effdata = QStringList() << "typewriter" << QString::number(typewriter_delay->value()) + ";" + QString::number(typewriter_start->value());
+        l[0]->setData(100, effdata);
+    }
+}
 
+void TitleWidget::slotEditBlur(int ix)
+{
+#if QT_VERSION < 0x040600
+    return;
+#else
+    QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
+    if (l.size() == 1) {
+        QGraphicsEffect *eff = l[0]->graphicsEffect();
+        QGraphicsBlurEffect *blur = static_cast <QGraphicsBlurEffect *>(eff);
+        if (blur) blur->setBlurRadius(ix);
+    }
+#endif
+}
+
+void TitleWidget::slotEditShadow()
+{
+#if QT_VERSION < 0x040600
+    return;
+#else
+    QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
+    if (l.size() == 1) {
+        QGraphicsEffect *eff = l[0]->graphicsEffect();
+        QGraphicsDropShadowEffect *shadow = static_cast <QGraphicsDropShadowEffect *>(eff);
+        if (shadow) {
+            shadow->setBlurRadius(shadow_radius->value());
+            shadow->setOffset(shadow_x->value(), shadow_y->value());
+        }
+    }
+#endif
+}
+
+qreal TitleWidget::zIndexBounds(bool maxBound)
+{
+    qreal bound = maxBound ? -99 : 99;
+    QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
+    if (l.size() > 0) {
+        QList<QGraphicsItem*> lItems = graphicsView->scene()->items(l[0]->sceneBoundingRect(), Qt::IntersectsItemShape);
+        if (lItems.size() > 0) {
+            int n = lItems.size();
+            qreal z;
+            if (maxBound) {
+                for (int i = 0; i < n; i++) {
+                    z = lItems[i]->zValue();
+                    if (z > bound && !lItems[i]->isSelected()) {
+                        bound = z;
+                    }
+                }
+            } else {
+                // Get minimum z index.
+                for (int i = 0; i < n; i++) {
+                    z = lItems[i]->zValue();
+                    if (z < bound && !lItems[i]->isSelected() && z > -999) {
+                        // There are items at the very bottom (background e.g.) with z-index < -1000.
+                        bound = z;
+                    }
+                }
+            }
+        }
+    }
+    return bound;
+}
+
+void TitleWidget::slotZIndexUp()
+{
+    QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
+    if (l.size() >= 1) {
+        qreal currentZ = l[0]->zValue();
+        qreal max = zIndexBounds(true);
+        if (currentZ <= max) {
+            l[0]->setZValue(currentZ + 1);
+            updateDimension(l[0]);
+        }
+    }
+}
+
+void TitleWidget::slotZIndexTop()
+{
+    QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
+    if (l.size() >= 1) {
+        qreal currentZ = l[0]->zValue();
+        qreal max = zIndexBounds(true);
+        if (currentZ <= max) {
+            l[0]->setZValue(max + 1);
+            updateDimension(l[0]);
+        }
+    }
+}
+
+void TitleWidget::slotZIndexDown()
+{
+    QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
+    if (l.size() >= 1) {
+        qreal currentZ = l[0]->zValue();
+        qreal min = zIndexBounds(false);
+        if (currentZ >= min) {
+            l[0]->setZValue(currentZ - 1);
+            updateDimension(l[0]);
+        }
+    }
+}
+
+void TitleWidget::slotZIndexBottom()
+{
+    QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
+    if (l.size() >= 1) {
+        qreal currentZ = l[0]->zValue();
+        qreal min = zIndexBounds(false);
+        if (currentZ >= min) {
+            l[0]->setZValue(min - 1);
+            updateDimension(l[0]);
+        }
+    }
+}