]> git.sesse.net Git - kdenlive/blobdiff - src/titlewidget.cpp
http://www.kdenlive.org/mantis/view.php?id=1414Disabling Home/End keys for z index...
[kdenlive] / src / titlewidget.cpp
index 9cf416fb52230353444429d24179b0816e6903d1..9c9b517514d12c4a1431c8918da6ad1d6a5f3dee 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "titlewidget.h"
 #include "kdenlivesettings.h"
+#include "KoSliderCombo.h"
 
 #include <cmath>
 
@@ -71,6 +72,67 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     frame_properties->setEnabled(false);
     frame_properties->setFixedHeight(frame_toolbar->height());
 
+    // Set combo sliders values
+    textAlpha->setMinimum(0);
+    textAlpha->setMaximum(255);
+    textAlpha->setDecimals(0);
+    textAlpha->setValue(255);
+    textAlpha->setToolTip(i18n("Font color opacity"));
+
+    textOutlineAlpha->setMinimum(0);
+    textOutlineAlpha->setMaximum(255);
+    textOutlineAlpha->setDecimals(0);
+    textOutlineAlpha->setValue(255);
+    textOutlineAlpha->setToolTip(i18n("Outline color opacity"));
+
+    textOutline->setMinimum(0);
+    textOutline->setMaximum(200);
+    textOutline->setDecimals(0);
+    textOutline->setValue(0);
+    textOutline->setToolTip(i18n("Outline width"));
+
+    backgroundAlpha->setMinimum(0);
+    backgroundAlpha->setMaximum(255);
+    backgroundAlpha->setDecimals(0);
+    backgroundAlpha->setValue(0);
+    backgroundAlpha->setToolTip(i18n("Background color opacity"));
+
+    itemrotatex->setMinimum(-360);
+    itemrotatex->setMaximum(360);
+    itemrotatex->setDecimals(0);
+    itemrotatex->setValue(0);
+    itemrotatex->setToolTip(i18n("Rotation around the X axis"));
+
+    itemrotatey->setMinimum(-360);
+    itemrotatey->setMaximum(360);
+    itemrotatey->setDecimals(0);
+    itemrotatey->setValue(0);
+    itemrotatey->setToolTip(i18n("Rotation around the Y axis"));
+
+    itemrotatez->setMinimum(-360);
+    itemrotatez->setMaximum(360);
+    itemrotatez->setDecimals(0);
+    itemrotatez->setValue(0);
+    itemrotatez->setToolTip(i18n("Rotation around the Z axis"));
+
+    rectBAlpha->setMinimum(0);
+    rectBAlpha->setMaximum(255);
+    rectBAlpha->setDecimals(0);
+    rectBAlpha->setValue(255);
+    rectBAlpha->setToolTip(i18n("Color opacity"));
+
+    rectFAlpha->setMinimum(0);
+    rectFAlpha->setMaximum(255);
+    rectFAlpha->setDecimals(0);
+    rectFAlpha->setValue(255);
+    rectFAlpha->setToolTip(i18n("Border opacity"));
+
+    rectLineWidth->setMinimum(0);
+    rectLineWidth->setMaximum(100);
+    rectLineWidth->setDecimals(0);
+    rectLineWidth->setValue(0);
+    rectLineWidth->setToolTip(i18n("Border width"));
+
     itemzoom->setSuffix(i18n("%"));
     m_frameWidth = render->renderWidth();
     m_frameHeight = render->renderHeight();
@@ -79,25 +141,25 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     //TODO: get default title duration instead of hardcoded one
     title_duration->setText(m_tc.getTimecode(GenTime(5000 / 1000.0)));
 
-    connect(kcolorbutton, SIGNAL(clicked()), this, SLOT(slotChangeBackground())) ;
-    connect(horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(slotChangeBackground())) ;
+    connect(backgroundColor, SIGNAL(clicked()), this, SLOT(slotChangeBackground())) ;
+    connect(backgroundAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotChangeBackground())) ;
 
     connect(fontColorButton, SIGNAL(clicked()), this, SLOT(slotUpdateText())) ;
     connect(textOutlineColor, SIGNAL(clicked()), this, SLOT(slotUpdateText())) ;
     connect(font_family, SIGNAL(currentFontChanged(const QFont &)), this, SLOT(slotUpdateText())) ;
     connect(font_size, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateText())) ;
-    connect(textAlpha, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateText()));
-    connect(textOutline, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateText()));
-    connect(textOutlineAlpha, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateText()));
+    connect(textAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotUpdateText()));
+    connect(textOutline, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotUpdateText()));
+    connect(textOutlineAlpha, SIGNAL(valueChanged(qreal, bool)), 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(rectFAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
+    connect(rectBAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
     connect(rectFColor, SIGNAL(clicked()), this, SLOT(rectChanged()));
     connect(rectBColor, SIGNAL(clicked()), this, SLOT(rectChanged()));
-    connect(rectLineWidth, SIGNAL(valueChanged(int)), this, SLOT(rectChanged()));
+    connect(rectLineWidth, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
 
     /*connect(startViewportX, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));
     connect(startViewportY, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));
@@ -114,7 +176,9 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
 
     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)));
+    connect(itemrotatex, SIGNAL(valueChanged(qreal, bool)), this, SLOT(itemRotateX(qreal)));
+    connect(itemrotatey, SIGNAL(valueChanged(qreal, bool)), this, SLOT(itemRotateY(qreal)));
+    connect(itemrotatez, SIGNAL(valueChanged(qreal, bool)), this, SLOT(itemRotateZ(qreal)));
     connect(itemhcenter, SIGNAL(clicked()), this, SLOT(itemHCenter()));
     connect(itemvcenter, SIGNAL(clicked()), this, SLOT(itemVCenter()));
     connect(itemtop, SIGNAL(clicked()), this, SLOT(itemTop()));
@@ -153,7 +217,6 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     connect(buttonAlignRight, SIGNAL(clicked()), this, SLOT(slotUpdateText()));
     connect(buttonAlignCenter, SIGNAL(clicked()), this, SLOT(slotUpdateText()));
     connect(buttonAlignNone, SIGNAL(clicked()), this, SLOT(slotUpdateText()));
-    //connect(buttonInsertUnicode, SIGNAL(clicked()), this, SLOT(slotInsertUnicode()));
     connect(displayBg, SIGNAL(stateChanged(int)), this, SLOT(displayBackgroundFrame()));
 
     connect(m_unicodeDialog, SIGNAL(charSelected(QString)), this, SLOT(slotInsertUnicodeString(QString)));
@@ -204,13 +267,16 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     zDown->setDefaultAction(m_zDown);
 
     m_zTop = new QAction(KIcon("kdenlive-zindex-top"), QString(), this);
-    m_zTop->setShortcut(Qt::Key_Home);
+    // TODO mbt 1414: Shortcut should change z index only if 
+    // cursor is NOT in a text field ...
+    //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);
+    // TODO mbt 1414
+    //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);
@@ -226,13 +292,13 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     origin_y_top->setToolTip(i18n("Invert y axis and change 0 point"));
     rectBColor->setToolTip(i18n("Select fill color"));
     rectFColor->setToolTip(i18n("Select border color"));
-    rectBAlpha->setToolTip(i18n("Fill transparency"));
-    rectFAlpha->setToolTip(i18n("Border transparency"));
+    rectBAlpha->setToolTip(i18n("Fill opacity"));
+    rectFAlpha->setToolTip(i18n("Border opacity"));
     zoom_slider->setToolTip(i18n("Zoom"));
     buttonRealSize->setToolTip(i18n("Original size (1:1)"));
     buttonFitZoom->setToolTip(i18n("Fit zoom"));
-    kcolorbutton->setToolTip(i18n("Select background color"));
-    horizontalSlider->setToolTip(i18n("Background Transparency"));
+    backgroundColor->setToolTip(i18n("Select background color"));
+    backgroundAlpha->setToolTip(i18n("Background opacity"));
 
     itemhcenter->setIcon(KIcon("kdenlive-align-hor"));
     itemhcenter->setToolTip(i18n("Align item horizontally"));
@@ -296,6 +362,7 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render
     // initialize graphic scene
     m_scene = new GraphicsSceneRectMove(this);
     graphicsView->setScene(m_scene);
+    graphicsView->setMouseTracking(true);
     m_titledocument.setScene(m_scene, m_frameWidth, m_frameHeight);
     connect(m_scene, SIGNAL(changed(QList<QRectF>)), this, SLOT(slotChanged()));
     connect(font_size, SIGNAL(valueChanged(int)), m_scene, SLOT(slotUpdateFontSize(int)));
@@ -426,6 +493,21 @@ QStringList TitleWidget::extractImageList(QString xml)
     return result;
 }
 
+// static
+QStringList TitleWidget::extractFontList(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("font"))
+            result.append(images.at(i).toElement().attribute("font"));
+    }
+    return result;
+}
+
 
 //virtual
 void TitleWidget::resizeEvent(QResizeEvent * /*event*/)
@@ -644,11 +726,13 @@ void TitleWidget::slotNewRect(QGraphicsRectItem * rect)
     f.setAlpha(rectFAlpha->value());
     QPen penf(f);
     penf.setWidth(rectLineWidth->value());
+    penf.setJoinStyle(Qt::RoundJoin);
     rect->setPen(penf);
     QColor b = rectBColor->color();
     b.setAlpha(rectBAlpha->value());
     rect->setBrush(QBrush(b));
     rect->setZValue(m_count++);
+    rect->setData(ZOOMFACTOR, 100);
     //setCurrentItem(rect);
     //graphicsView->setFocus();
 }
@@ -668,6 +752,23 @@ void TitleWidget::slotNewText(QGraphicsTextItem *tt)
     QColor color = fontColorButton->color();
     color.setAlpha(textAlpha->value());
     tt->setDefaultTextColor(color);
+
+    QTextCursor cur(tt->document());
+    cur.select(QTextCursor::Document);
+    QTextBlockFormat format = cur.blockFormat();
+    QTextCharFormat cformat = cur.charFormat();
+    QColor outlineColor = textOutlineColor->color();
+    outlineColor.setAlpha(textOutlineAlpha->value());
+    double outlineWidth = textOutline->value() / 10.0;
+
+    tt->setData(101, outlineWidth);
+    tt->setData(102, outlineColor);
+    if (outlineWidth > 0.0) cformat.setTextOutline(QPen(outlineColor, outlineWidth));
+
+    cformat.setForeground(QBrush(color));
+    cur.setCharFormat(cformat);
+    cur.setBlockFormat(format);
+    tt->setTextCursor(cur);
     tt->setZValue(m_count++);
     setCurrentItem(tt);
 }
@@ -705,7 +806,9 @@ void TitleWidget::selectionChanged()
     value_w->blockSignals(true);
     value_h->blockSignals(true);
     itemzoom->blockSignals(true);
-    itemrotate->blockSignals(true);
+    itemrotatex->blockSignals(true);
+    itemrotatey->blockSignals(true);
+    itemrotatez->blockSignals(true);
     if (l.size() == 0) {
         effect_stack->setHidden(true);
         effect_frame->setEnabled(false);
@@ -722,17 +825,23 @@ void TitleWidget::selectionChanged()
         if (blockX) origin_x_left->blockSignals(false);
         if (blockY) origin_y_top->blockSignals(false);
         itemzoom->setEnabled(false);
-        itemrotate->setEnabled(false);
+        itemrotatex->setEnabled(false);
+        itemrotatey->setEnabled(false);
+        itemrotatez->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);
+            itemrotatex->setEnabled(true);
+            itemrotatey->setEnabled(true);
+            itemrotatez->setEnabled(true);
         } else {
             itemzoom->setEnabled(false);
-            itemrotate->setEnabled(false);
+            itemrotatex->setEnabled(false);
+            itemrotatey->setEnabled(false);
+            itemrotatez->setEnabled(false);
             updateInfoText();
         }
         if (l.at(0)->type() == TEXTITEM) {
@@ -804,26 +913,28 @@ void TitleWidget::selectionChanged()
             buttonUnder->setChecked(font.underline());
             setFontBoxWeight(font.weight());
 
-            QColor color = i->defaultTextColor();
-           QTextCursor cursor(i->document());
-           cursor.select(QTextCursor::Document);
-           color=cursor.charFormat().foreground().color();
-            fontColorButton->setColor(color);
+            QTextCursor cursor(i->document());
+            cursor.select(QTextCursor::Document);
+            QColor color = cursor.charFormat().foreground().color();
             textAlpha->setValue(color.alpha());
+            color.setAlpha(255);
+            fontColorButton->setColor(color);
 
-           if (!i->data(101).isNull()){
-                       textOutline->blockSignals(true);
-               textOutline->setValue(i->data(101).toDouble()*10);
-                       textOutline->blockSignals(false);
-           }
-           if (!i->data(102).isNull()){
-                       textOutlineColor->blockSignals(true);
-                       textOutlineAlpha->blockSignals(true);
-               textOutlineColor->setColor(i->data(102).toString());
-               textOutlineAlpha->setValue(QColor(i->data(102).toString()).alpha());
-                       textOutlineColor->blockSignals(false);
-                       textOutlineAlpha->blockSignals(false);
-           }
+            if (!i->data(101).isNull()) {
+                textOutline->blockSignals(true);
+                textOutline->setValue(i->data(101).toDouble()*10);
+                textOutline->blockSignals(false);
+            }
+            if (!i->data(102).isNull()) {
+                textOutlineColor->blockSignals(true);
+                textOutlineAlpha->blockSignals(true);
+                color = QColor(i->data(102).toString());
+                textOutlineAlpha->setValue(color.alpha());
+                color.setAlpha(255);
+                textOutlineColor->setColor(color);
+                textOutlineColor->blockSignals(false);
+                textOutlineAlpha->blockSignals(false);
+            }
             QTextCursor cur = i->textCursor();
             QTextBlockFormat format = cur.blockFormat();
             if (i->textWidth() == -1) buttonAlignNone->setChecked(true);
@@ -895,14 +1006,19 @@ void TitleWidget::selectionChanged()
             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));
-        itemrotate->setValue((int)(m_transformations.value(l.at(0)).rotate));
+        if (!l.at(0)->data(ZOOMFACTOR).isNull()) itemzoom->setValue(l.at(0)->data(ZOOMFACTOR).toInt());
+        else itemzoom->setValue((int)(m_transformations.value(l.at(0)).scalex * 100.0 + 0.5));
+        itemrotatex->setValue((int)(m_transformations.value(l.at(0)).rotatex));
+        itemrotatey->setValue((int)(m_transformations.value(l.at(0)).rotatey));
+        itemrotatez->setValue((int)(m_transformations.value(l.at(0)).rotatez));
         value_x->blockSignals(false);
         value_y->blockSignals(false);
         value_w->blockSignals(false);
         value_h->blockSignals(false);
         itemzoom->blockSignals(false);
-        itemrotate->blockSignals(false);
+        itemrotatex->blockSignals(false);
+        itemrotatey->blockSignals(false);
+        itemrotatez->blockSignals(false);
     }
 }
 
@@ -926,7 +1042,8 @@ void TitleWidget::slotValueChanged(int type)
 
         // Ratio width:height
         double phi = (double) i->boundingRect().width() / i->boundingRect().height();
-        double alpha = (double) t.rotate / 180.0 * M_PI;
+        // TODO: proper calculation for rotation around 3 axes
+        double alpha = (double) t.rotatez / 180.0 * M_PI;
 
         // New length
         double length = val;
@@ -950,7 +1067,9 @@ void TitleWidget::slotValueChanged(int type)
         t.scaley = scale;
         QTransform qtrans;
         qtrans.scale(scale, scale);
-        qtrans.rotate(t.rotate);
+        qtrans.rotate(t.rotatex, Qt::XAxis);
+        qtrans.rotate(t.rotatey, Qt::YAxis);
+        qtrans.rotate(t.rotatez, Qt::ZAxis);
         i->setTransform(qtrans);
         m_transformations[i] = t;
 
@@ -1084,14 +1203,23 @@ void TitleWidget::updateCoordinates(QGraphicsItem *i)
 void TitleWidget::updateRotZoom(QGraphicsItem *i)
 {
     itemzoom->blockSignals(true);
-    itemrotate->blockSignals(false);
+    itemrotatex->blockSignals(true);
+    itemrotatey->blockSignals(true);
+    itemrotatez->blockSignals(true);
 
     Transform t = m_transformations.value(i);
-    itemzoom->setValue((int)(t.scalex * 100.0 + 0.5));
-    itemrotate->setValue((int)(t.rotate));
+
+    if (!i->data(ZOOMFACTOR).isNull()) itemzoom->setValue(i->data(ZOOMFACTOR).toInt());
+    else itemzoom->setValue((int)(t.scalex * 100.0 + 0.5));
+
+    itemrotatex->setValue((int)(t.rotatex));
+    itemrotatey->setValue((int)(t.rotatey));
+    itemrotatez->setValue((int)(t.rotatez));
 
     itemzoom->blockSignals(false);
-    itemrotate->blockSignals(false);
+    itemrotatex->blockSignals(false);
+    itemrotatey->blockSignals(false);
+    itemrotatez->blockSignals(false);
 }
 
 /** \brief Updates the position of an item by reading coordinates from the text fields */
@@ -1241,8 +1369,8 @@ void TitleWidget::updateAxisButtons(QGraphicsItem *i)
 
 void TitleWidget::slotChangeBackground()
 {
-    QColor color = kcolorbutton->color();
-    color.setAlpha(horizontalSlider->value());
+    QColor color = backgroundColor->color();
+    color.setAlpha(backgroundAlpha->value());
     m_frameBorder->setBrush(QBrush(color));
 }
 
@@ -1312,9 +1440,9 @@ void TitleWidget::slotUpdateText()
     QColor color = fontColorButton->color();
     color.setAlpha(textAlpha->value());
 
-    QColor outlineColor=textOutlineColor->color();
+    QColor outlineColor = textOutlineColor->color();
     outlineColor.setAlpha(textOutlineAlpha->value());
-    double outlineWidth=textOutline->value()/10.0;
+    double outlineWidth = textOutline->value() / 10.0;
     QGraphicsTextItem* item = NULL;
     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
     if (l.size() == 1 && l.at(0)->type() == TEXTITEM) {
@@ -1322,7 +1450,8 @@ void TitleWidget::slotUpdateText()
     }
     if (!item) return;
     //if (item->textCursor().selection ().isEmpty())
-    QTextCursor cur = item->textCursor();
+    QTextCursor cur(item->document());
+    cur.select(QTextCursor::Document);
     QTextBlockFormat format = cur.blockFormat();
     if (buttonAlignLeft->isChecked() || buttonAlignCenter->isChecked() || buttonAlignRight->isChecked()) {
         item->setTextWidth(item->boundingRect().width());
@@ -1334,27 +1463,19 @@ void TitleWidget::slotUpdateText()
         item->setTextWidth(-1);
     }
 
-    {
-        item->setFont(font);
-       if (outlineWidth>0.0){
-                                       item->setData(101,outlineWidth);
-                                       item->setData(102,outlineColor);
-                                       QTextCursor cursor(item->document());
-                                       cursor.select(QTextCursor::Document);
-                                       QTextCharFormat format;
-                                       format.setTextOutline( QPen(outlineColor,outlineWidth ));
-                                       format.setForeground(QBrush(color));
-                                       cursor.mergeCharFormat(format); 
-       }else{
-               item->setDefaultTextColor(color);
-       }
-        cur.select(QTextCursor::Document);
-        cur.setBlockFormat(format);
-        item->setTextCursor(cur);
-        cur.clearSelection();
-        item->setTextCursor(cur);
+    item->setFont(font);
+    QTextCharFormat cformat = cur.charFormat();
 
-    }
+    item->setData(101, outlineWidth);
+    item->setData(102, outlineColor);
+    if (outlineWidth > 0.0) cformat.setTextOutline(QPen(outlineColor, outlineWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+
+    cformat.setForeground(QBrush(color));
+    cur.setCharFormat(cformat);
+    cur.setBlockFormat(format);
+    item->setTextCursor(cur);
+    cur.clearSelection();
+    item->setTextCursor(cur);
 }
 
 void TitleWidget::rectChanged()
@@ -1366,6 +1487,7 @@ void TitleWidget::rectChanged()
         f.setAlpha(rectFAlpha->value());
         QPen penf(f);
         penf.setWidth(rectLineWidth->value());
+        penf.setJoinStyle(Qt::RoundJoin);
         rec->setPen(penf);
         QColor b = rectBColor->color();
         b.setAlpha(rectBAlpha->value());
@@ -1382,24 +1504,58 @@ void TitleWidget::itemScaled(int val)
         x.scaley = (double)val / 100.0;
         QTransform qtrans;
         qtrans.scale(x.scalex, x.scaley);
-        qtrans.rotate(x.rotate);
+        qtrans.rotate(x.rotatex, Qt::XAxis);
+        qtrans.rotate(x.rotatey, Qt::YAxis);
+        qtrans.rotate(x.rotatez, Qt::ZAxis);
         l[0]->setTransform(qtrans);
+        l[0]->setData(ZOOMFACTOR, val);
         m_transformations[l.at(0)] = x;
         updateDimension(l.at(0));
     }
 }
 
-void TitleWidget::itemRotate(int val)
+void TitleWidget::itemRotateX(qreal val)
+{
+    itemRotate(val, 0);
+}
+
+void TitleWidget::itemRotateY(qreal val)
+{
+    itemRotate(val, 1);
+}
+
+void TitleWidget::itemRotateZ(qreal val)
+{
+    itemRotate(val, 2);
+}
+
+void TitleWidget::itemRotate(qreal val, int axis)
 {
     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
     if (l.size() == 1) {
         Transform x = m_transformations[l.at(0)];
-        x.rotate = (double)val;
+        switch (axis) {
+        case 0:
+            x.rotatex = val;
+            break;
+        case 1:
+            x.rotatey = val;
+            break;
+        case 2:
+            x.rotatez = val;
+            break;
+        }
+
+        l[0]->setData(ROTATEFACTOR, QList<QVariant>() << QVariant(x.rotatex) << QVariant(x.rotatey) << QVariant(x.rotatez));
+
         QTransform qtrans;
         qtrans.scale(x.scalex, x.scaley);
-        qtrans.rotate(x.rotate);
+        qtrans.rotate(x.rotatex, Qt::XAxis);
+        qtrans.rotate(x.rotatey, Qt::YAxis);
+        qtrans.rotate(x.rotatez, Qt::ZAxis);
         l[0]->setTransform(qtrans);
         m_transformations[l.at(0)] = x;
+        if (l[0]->data(ZOOMFACTOR).isNull()) l[0]->setData(ZOOMFACTOR, 100);
         updateDimension(l.at(0));
     }
 }
@@ -1607,18 +1763,40 @@ void TitleWidget::setXml(QDomDocument doc)
         Transform x;
         x.scalex = t.m11();
         x.scaley = t.m22();
-        x.rotate = 180. / PI * atan2(-t.m21(), t.m11());
+        if (!items.at(i)->data(ROTATEFACTOR).isNull()) {
+            QList<QVariant> rotlist = items.at(i)->data(ROTATEFACTOR).toList();
+            if (rotlist.count() >= 3) {
+                x.rotatex = rotlist[0].toDouble();
+                x.rotatey = rotlist[1].toDouble();
+                x.rotatez = rotlist[2].toDouble();
+
+                // Try to adjust zoom
+                t.rotate(x.rotatex * (-1), Qt::XAxis);
+                t.rotate(x.rotatey * (-1), Qt::YAxis);
+                t.rotate(x.rotatez * (-1), Qt::ZAxis);
+                x.scalex = t.m11();
+                x.scaley = t.m22();
+            } else {
+                x.rotatex = 0;
+                x.rotatey = 0;
+                x.rotatez = 0;
+            }
+        } else {
+            x.rotatex = 0;
+            x.rotatey = 0;
+            x.rotatez = 180. / PI * atan2(-t.m21(), t.m11());
+        }
         m_transformations[items.at(i)] = x;
     }
     // mbd: Update the GUI color selectors to match the stuff from the loaded document
     QColor background_color = m_titledocument.getBackgroundColor();
-    horizontalSlider->blockSignals(true);
-    kcolorbutton->blockSignals(true);
-    horizontalSlider->setValue(background_color.alpha());
+    backgroundAlpha->blockSignals(true);
+    backgroundColor->blockSignals(true);
+    backgroundAlpha->setValue(background_color.alpha());
     background_color.setAlpha(255);
-    kcolorbutton->setColor(background_color);
-    horizontalSlider->blockSignals(false);
-    kcolorbutton->blockSignals(false);
+    backgroundColor->setColor(background_color);
+    backgroundAlpha->blockSignals(false);
+    backgroundColor->blockSignals(false);
 
     /*startViewportX->setValue(m_startViewport->data(0).toInt());
     startViewportY->setValue(m_startViewport->data(1).toInt());
@@ -1629,6 +1807,7 @@ void TitleWidget::setXml(QDomDocument doc)
 
     QTimer::singleShot(200, this, SLOT(slotAdjustZoom()));
     slotSelectTool();
+    selectionChanged();
 }
 
 /** \brief Connected to the accepted signal - calls writeChoices */
@@ -1651,6 +1830,9 @@ void TitleWidget::writeChoices()
     titleConfig.writeEntry("font_pixel_size", font_size->value());
     titleConfig.writeEntry("font_color", fontColorButton->color());
     titleConfig.writeEntry("font_alpha", textAlpha->value());
+    titleConfig.writeEntry("font_outline", textOutline->value());
+    titleConfig.writeEntry("font_outline_color", textOutlineColor->color());
+    titleConfig.writeEntry("font_outline_alpha", textOutlineAlpha->value());
     titleConfig.writeEntry("font_weight", font_weight_box->itemData(font_weight_box->currentIndex()).toInt());
     titleConfig.writeEntry("font_italic", buttonItalic->isChecked());
     titleConfig.writeEntry("font_underlined", buttonUnder->isChecked());
@@ -1661,8 +1843,8 @@ void TitleWidget::writeChoices()
     titleConfig.writeEntry("rect_background_alpha", rectBAlpha->value());
     titleConfig.writeEntry("rect_line_width", rectLineWidth->value());
 
-    titleConfig.writeEntry("background_color", kcolorbutton->color());
-    titleConfig.writeEntry("background_alpha", horizontalSlider->value());
+    titleConfig.writeEntry("background_color", backgroundColor->color());
+    titleConfig.writeEntry("background_alpha", backgroundAlpha->value());
 
     //! \todo Not sure if I should sync - it is probably safe to do it
     config->sync();
@@ -1681,6 +1863,11 @@ void TitleWidget::readChoices()
     m_scene->slotUpdateFontSize(font_size->value());
     fontColorButton->setColor(titleConfig.readEntry("font_color", fontColorButton->color()));
     textAlpha->setValue(titleConfig.readEntry("font_alpha", textAlpha->value()));
+
+    textOutlineColor->setColor(titleConfig.readEntry("font_outline_color", textOutlineColor->color()));
+    textOutlineAlpha->setValue(titleConfig.readEntry("font_outline_alpha", textOutlineAlpha->value()));
+    textOutline->setValue(titleConfig.readEntry("font_outline", textOutline->value()));
+
     int weight;
     if (titleConfig.readEntry("font_bold", false)) weight = QFont::Bold;
     else weight = titleConfig.readEntry("font_weight", font_weight_box->itemData(font_weight_box->currentIndex()).toInt());
@@ -1694,8 +1881,8 @@ void TitleWidget::readChoices()
     rectBAlpha->setValue(titleConfig.readEntry("rect_background_alpha", rectBAlpha->value()));
     rectLineWidth->setValue(titleConfig.readEntry("rect_line_width", rectLineWidth->value()));
 
-    kcolorbutton->setColor(titleConfig.readEntry("background_color", kcolorbutton->color()));
-    horizontalSlider->setValue(titleConfig.readEntry("background_alpha", horizontalSlider->value()));
+    backgroundColor->setColor(titleConfig.readEntry("background_color", backgroundColor->color()));
+    backgroundAlpha->setValue(titleConfig.readEntry("background_alpha", backgroundAlpha->value()));
 }
 
 void TitleWidget::adjustFrameSize()
@@ -1723,7 +1910,9 @@ void TitleWidget::slotAnimStart(bool anim)
     }
     align_box->setEnabled(anim);
     itemzoom->setEnabled(!anim);
-    itemrotate->setEnabled(!anim);
+    itemrotatex->setEnabled(!anim);
+    itemrotatey->setEnabled(!anim);
+    itemrotatez->setEnabled(!anim);
     frame_toolbar->setEnabled(!anim);
     toolbar_stack->setEnabled(!anim);
     if (anim) {
@@ -1763,7 +1952,9 @@ void TitleWidget::slotAnimEnd(bool anim)
     }
     align_box->setEnabled(anim);
     itemzoom->setEnabled(!anim);
-    itemrotate->setEnabled(!anim);
+    itemrotatex->setEnabled(!anim);
+    itemrotatey->setEnabled(!anim);
+    itemrotatez->setEnabled(!anim);
     frame_toolbar->setEnabled(!anim);
     toolbar_stack->setEnabled(!anim);
     if (anim) {
@@ -1961,12 +2152,18 @@ void TitleWidget::slotEditShadow()
 #endif
 }
 
-qreal TitleWidget::zIndexBounds(bool maxBound)
+qreal TitleWidget::zIndexBounds(bool maxBound, bool intersectingOnly)
 {
     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);
+        QList<QGraphicsItem*> lItems;
+        // Get items (all or intersecting only)
+        if (intersectingOnly) {
+            lItems = graphicsView->scene()->items(l[0]->sceneBoundingRect(), Qt::IntersectsItemShape);
+        } else {
+            lItems = graphicsView->scene()->items();
+        }
         if (lItems.size() > 0) {
             int n = lItems.size();
             qreal z;
@@ -1997,7 +2194,7 @@ void TitleWidget::slotZIndexUp()
     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
     if (l.size() >= 1) {
         qreal currentZ = l[0]->zValue();
-        qreal max = zIndexBounds(true);
+        qreal max = zIndexBounds(true, true);
         if (currentZ <= max) {
             l[0]->setZValue(currentZ + 1);
             updateDimension(l[0]);
@@ -2010,7 +2207,7 @@ void TitleWidget::slotZIndexTop()
     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
     if (l.size() >= 1) {
         qreal currentZ = l[0]->zValue();
-        qreal max = zIndexBounds(true);
+        qreal max = zIndexBounds(true, false);
         if (currentZ <= max) {
             l[0]->setZValue(max + 1);
             updateDimension(l[0]);
@@ -2023,7 +2220,7 @@ void TitleWidget::slotZIndexDown()
     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
     if (l.size() >= 1) {
         qreal currentZ = l[0]->zValue();
-        qreal min = zIndexBounds(false);
+        qreal min = zIndexBounds(false, true);
         if (currentZ >= min) {
             l[0]->setZValue(currentZ - 1);
             updateDimension(l[0]);
@@ -2036,7 +2233,7 @@ void TitleWidget::slotZIndexBottom()
     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
     if (l.size() >= 1) {
         qreal currentZ = l[0]->zValue();
-        qreal min = zIndexBounds(false);
+        qreal min = zIndexBounds(false, false);
         if (currentZ >= min) {
             l[0]->setZValue(min - 1);
             updateDimension(l[0]);