]> git.sesse.net Git - kdenlive/blob - src/titlewidget.cpp
r6466@lapL: simon | 2010-05-28 17:39:22 +0200
[kdenlive] / src / titlewidget.cpp
1 /***************************************************************************
2                           titlewidget.cpp  -  description
3                              -------------------
4     begin                : Feb 28 2008
5     copyright            : (C) 2008 by Marco Gittler
6     email                : g.marco@freenet.de
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17
18 #include "titlewidget.h"
19 #include "kdenlivesettings.h"
20 #include "KoSliderCombo.h"
21 #include "kthumb.h"
22 #include <cmath>
23
24 #include <KDebug>
25 #include <KGlobalSettings>
26 #include <KFileDialog>
27 #include <KStandardDirs>
28 #include <KMessageBox>
29 #include <kio/netaccess.h>
30 #include <kdeversion.h>
31
32 #include <QDomDocument>
33 #include <QGraphicsItem>
34 #include <QGraphicsSvgItem>
35 #include <QTimer>
36 #include <QToolBar>
37 #include <QMenu>
38 #include <QSignalMapper>
39 #include <QTextBlockFormat>
40 #include <QTextCursor>
41 #include <QComboBox>
42 #include <QCryptographicHash>
43
44 #if QT_VERSION >= 0x040600
45 #include <QGraphicsEffect>
46 #include <QGraphicsBlurEffect>
47 #include <QGraphicsDropShadowEffect>
48 #endif
49
50 #include <iostream>
51
52 static QList<TitleTemplate> titletemplates;
53
54 // What exactly is this variable good for?
55 int settingUp = false;
56
57 const int IMAGEITEM = 7;
58 const int RECTITEM = 3;
59 const int TEXTITEM = 8;
60
61 const int NOEFFECT = 0;
62 const int BLUREFFECT = 1;
63 const int SHADOWEFFECT = 2;
64 const int TYPEWRITEREFFECT = 3;
65
66 TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render *render, QWidget *parent) :
67     QDialog(parent),
68     Ui::TitleWidget_UI(),
69     m_startViewport(NULL),
70     m_endViewport(NULL),
71     m_render(render),
72     m_count(0),
73     m_unicodeDialog(new UnicodeDialog(UnicodeDialog::InputHex)),
74     m_projectTitlePath(projectTitlePath),
75     m_tc(tc)
76 {
77     setupUi(this);
78     setFont(KGlobalSettings::toolBarFont());
79     frame_properties->setEnabled(false);
80     frame_properties->setFixedHeight(frame_toolbar->height());
81
82     // Set combo sliders values
83     textAlpha->setMinimum(0);
84     textAlpha->setMaximum(255);
85     textAlpha->setDecimals(0);
86     textAlpha->setValue(255);
87     textAlpha->setToolTip(i18n("Font color opacity"));
88
89     textOutlineAlpha->setMinimum(0);
90     textOutlineAlpha->setMaximum(255);
91     textOutlineAlpha->setDecimals(0);
92     textOutlineAlpha->setValue(255);
93     textOutlineAlpha->setToolTip(i18n("Outline color opacity"));
94
95     textOutline->setMinimum(0);
96     textOutline->setMaximum(200);
97     textOutline->setDecimals(0);
98     textOutline->setValue(0);
99     textOutline->setToolTip(i18n("Outline width"));
100
101     backgroundAlpha->setMinimum(0);
102     backgroundAlpha->setMaximum(255);
103     backgroundAlpha->setDecimals(0);
104     backgroundAlpha->setValue(0);
105     backgroundAlpha->setToolTip(i18n("Background color opacity"));
106
107     itemrotatex->setMinimum(-360);
108     itemrotatex->setMaximum(360);
109     itemrotatex->setDecimals(0);
110     itemrotatex->setValue(0);
111     itemrotatex->setToolTip(i18n("Rotation around the X axis"));
112
113     itemrotatey->setMinimum(-360);
114     itemrotatey->setMaximum(360);
115     itemrotatey->setDecimals(0);
116     itemrotatey->setValue(0);
117     itemrotatey->setToolTip(i18n("Rotation around the Y axis"));
118
119     itemrotatez->setMinimum(-360);
120     itemrotatez->setMaximum(360);
121     itemrotatez->setDecimals(0);
122     itemrotatez->setValue(0);
123     itemrotatez->setToolTip(i18n("Rotation around the Z axis"));
124
125     rectBAlpha->setMinimum(0);
126     rectBAlpha->setMaximum(255);
127     rectBAlpha->setDecimals(0);
128     rectBAlpha->setValue(255);
129     rectBAlpha->setToolTip(i18n("Color opacity"));
130
131     rectFAlpha->setMinimum(0);
132     rectFAlpha->setMaximum(255);
133     rectFAlpha->setDecimals(0);
134     rectFAlpha->setValue(255);
135     rectFAlpha->setToolTip(i18n("Border opacity"));
136
137     rectLineWidth->setMinimum(0);
138     rectLineWidth->setMaximum(100);
139     rectLineWidth->setDecimals(0);
140     rectLineWidth->setValue(0);
141     rectLineWidth->setToolTip(i18n("Border width"));
142
143     itemzoom->setSuffix(i18n("%"));
144     m_frameWidth = render->renderWidth();
145     m_frameHeight = render->renderHeight();
146     showToolbars(TITLE_SELECT);
147
148     //If project is drop frame, set the input mask as such.
149     title_duration->setInputMask("");
150     title_duration->setValidator(m_tc.validator());
151     title_duration->setText(m_tc.reformatSeparators(KdenliveSettings::title_duration()));
152
153     connect(backgroundColor, SIGNAL(clicked()), this, SLOT(slotChangeBackground())) ;
154     connect(backgroundAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotChangeBackground())) ;
155
156     connect(fontColorButton, SIGNAL(clicked()), this, SLOT(slotUpdateText())) ;
157     connect(textOutlineColor, SIGNAL(clicked()), this, SLOT(slotUpdateText())) ;
158     connect(font_family, SIGNAL(currentFontChanged(const QFont &)), this, SLOT(slotUpdateText())) ;
159     connect(font_size, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateText())) ;
160     connect(textAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotUpdateText()));
161     connect(textOutline, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotUpdateText()));
162     connect(textOutlineAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(slotUpdateText()));
163     connect(font_weight_box, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateText()));
164
165     connect(font_family, SIGNAL(editTextChanged(const QString &)), this, SLOT(slotFontText(const QString&)));
166
167     connect(rectFAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
168     connect(rectBAlpha, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
169     connect(rectFColor, SIGNAL(clicked()), this, SLOT(rectChanged()));
170     connect(rectBColor, SIGNAL(clicked()), this, SLOT(rectChanged()));
171     connect(rectLineWidth, SIGNAL(valueChanged(qreal, bool)), this, SLOT(rectChanged()));
172
173     /*connect(startViewportX, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));
174     connect(startViewportY, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));
175     connect(startViewportSize, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));
176     connect(endViewportX, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));
177     connect(endViewportY, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));
178     connect(endViewportSize, SIGNAL(valueChanged(int)), this, SLOT(setupViewports()));*/
179
180     // Fill effects
181     effect_list->addItem(i18n("None"), NOEFFECT);
182     effect_list->addItem(i18n("Typewriter"), TYPEWRITEREFFECT);
183     effect_list->addItem(i18n("Blur"), BLUREFFECT);
184
185
186     connect(zValue, SIGNAL(valueChanged(int)), this, SLOT(zIndexChanged(int)));
187     connect(itemzoom, SIGNAL(valueChanged(int)), this, SLOT(itemScaled(int)));
188     connect(itemrotatex, SIGNAL(valueChanged(qreal, bool)), this, SLOT(itemRotateX(qreal)));
189     connect(itemrotatey, SIGNAL(valueChanged(qreal, bool)), this, SLOT(itemRotateY(qreal)));
190     connect(itemrotatez, SIGNAL(valueChanged(qreal, bool)), this, SLOT(itemRotateZ(qreal)));
191     connect(itemhcenter, SIGNAL(clicked()), this, SLOT(itemHCenter()));
192     connect(itemvcenter, SIGNAL(clicked()), this, SLOT(itemVCenter()));
193     connect(itemtop, SIGNAL(clicked()), this, SLOT(itemTop()));
194     connect(itembottom, SIGNAL(clicked()), this, SLOT(itemBottom()));
195     connect(itemleft, SIGNAL(clicked()), this, SLOT(itemLeft()));
196     connect(itemright, SIGNAL(clicked()), this, SLOT(itemRight()));
197     connect(effect_list, SIGNAL(currentIndexChanged(int)), this, SLOT(slotAddEffect(int)));
198     connect(typewriter_delay, SIGNAL(valueChanged(int)), this, SLOT(slotEditTypewriter(int)));
199     connect(typewriter_start, SIGNAL(valueChanged(int)), this, SLOT(slotEditTypewriter(int)));
200     connect(blur_radius, SIGNAL(valueChanged(int)), this, SLOT(slotEditBlur(int)));
201     connect(shadow_radius, SIGNAL(valueChanged(int)), this, SLOT(slotEditShadow()));
202     connect(shadow_x, SIGNAL(valueChanged(int)), this, SLOT(slotEditShadow()));
203     connect(shadow_y, SIGNAL(valueChanged(int)), this, SLOT(slotEditShadow()));
204     effect_stack->setHidden(true);
205     effect_frame->setEnabled(false);
206
207     connect(origin_x_left, SIGNAL(clicked()), this, SLOT(slotOriginXClicked()));
208     connect(origin_y_top, SIGNAL(clicked()), this, SLOT(slotOriginYClicked()));
209
210     m_signalMapper = new QSignalMapper(this);
211     m_signalMapper->setMapping(value_w, ValueWidth);
212     m_signalMapper->setMapping(value_h, ValueHeight);
213     connect(value_w, SIGNAL(valueChanged(int)), m_signalMapper, SLOT(map()));
214     connect(value_h, SIGNAL(valueChanged(int)), m_signalMapper, SLOT(map()));
215     connect(m_signalMapper, SIGNAL(mapped(int)), this, SLOT(slotValueChanged(int)));
216
217     connect(value_x, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustSelectedItem()));
218     connect(value_y, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustSelectedItem()));
219     connect(value_w, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustSelectedItem()));
220     connect(value_h, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustSelectedItem()));
221     connect(buttonFitZoom, SIGNAL(clicked()), this, SLOT(slotAdjustZoom()));
222     connect(buttonRealSize, SIGNAL(clicked()), this, SLOT(slotZoomOneToOne()));
223     connect(buttonItalic, SIGNAL(clicked()), this, SLOT(slotUpdateText()));
224     connect(buttonUnder, SIGNAL(clicked()), this, SLOT(slotUpdateText()));
225     connect(buttonAlignLeft, SIGNAL(clicked()), this, SLOT(slotUpdateText()));
226     connect(buttonAlignRight, SIGNAL(clicked()), this, SLOT(slotUpdateText()));
227     connect(buttonAlignCenter, SIGNAL(clicked()), this, SLOT(slotUpdateText()));
228     connect(buttonAlignNone, SIGNAL(clicked()), this, SLOT(slotUpdateText()));
229     connect(displayBg, SIGNAL(stateChanged(int)), this, SLOT(displayBackgroundFrame()));
230
231     connect(m_unicodeDialog, SIGNAL(charSelected(QString)), this, SLOT(slotInsertUnicodeString(QString)));
232
233     // mbd
234     connect(this, SIGNAL(accepted()), this, SLOT(slotAccepted()));
235
236     font_weight_box->blockSignals(true);
237     font_weight_box->addItem(i18nc("Font style", "Light"), QFont::Light);
238     font_weight_box->addItem(i18nc("Font style", "Normal"), QFont::Normal);
239     font_weight_box->addItem(i18nc("Font style", "Demi-Bold"), QFont::DemiBold);
240     font_weight_box->addItem(i18nc("Font style", "Bold"), QFont::Bold);
241     font_weight_box->addItem(i18nc("Font style", "Black"), QFont::Black);
242     font_weight_box->setToolTip(i18n("Font weight"));
243     font_weight_box->setCurrentIndex(1);
244     font_weight_box->blockSignals(false);
245
246     buttonFitZoom->setIcon(KIcon("zoom-fit-best"));
247     buttonRealSize->setIcon(KIcon("zoom-original"));
248     buttonItalic->setIcon(KIcon("format-text-italic"));
249     buttonUnder->setIcon(KIcon("format-text-underline"));
250     buttonAlignCenter->setIcon(KIcon("format-justify-center"));
251     buttonAlignLeft->setIcon(KIcon("format-justify-left"));
252     buttonAlignRight->setIcon(KIcon("format-justify-right"));
253     buttonAlignNone->setIcon(KIcon("kdenlive-align-none"));
254
255     buttonAlignNone->setToolTip(i18n("No alignment"));
256     buttonAlignRight->setToolTip(i18n("Align right"));
257     buttonAlignLeft->setToolTip(i18n("Align left"));
258     buttonAlignCenter->setToolTip(i18n("Align center"));
259
260     m_unicodeAction = new QAction(KIcon("kdenlive-insert-unicode"), QString(), this);
261     m_unicodeAction->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_U);
262     m_unicodeAction->setToolTip(i18n("Insert Unicode character") + ' ' + m_unicodeAction->shortcut().toString());
263     connect(m_unicodeAction, SIGNAL(triggered()), this, SLOT(slotInsertUnicode()));
264     buttonInsertUnicode->setDefaultAction(m_unicodeAction);
265
266     m_zUp = new QAction(KIcon("kdenlive-zindex-up"), QString(), this);
267     m_zUp->setShortcut(Qt::Key_PageUp);
268     m_zUp->setToolTip(i18n("Raise object"));
269     connect(m_zUp, SIGNAL(triggered()), this, SLOT(slotZIndexUp()));
270     zUp->setDefaultAction(m_zUp);
271
272     m_zDown = new QAction(KIcon("kdenlive-zindex-down"), QString(), this);
273     m_zDown->setShortcut(Qt::Key_PageDown);
274     m_zDown->setToolTip(i18n("Lower object"));
275     connect(m_zDown, SIGNAL(triggered()), this, SLOT(slotZIndexDown()));
276     zDown->setDefaultAction(m_zDown);
277
278     m_zTop = new QAction(KIcon("kdenlive-zindex-top"), QString(), this);
279     // TODO mbt 1414: Shortcut should change z index only if
280     // cursor is NOT in a text field ...
281     //m_zTop->setShortcut(Qt::Key_Home);
282     m_zTop->setToolTip(i18n("Raise object to top"));
283     connect(m_zTop, SIGNAL(triggered()), this, SLOT(slotZIndexTop()));
284     zTop->setDefaultAction(m_zTop);
285
286     m_zBottom = new QAction(KIcon("kdenlive-zindex-bottom"), QString(), this);
287     // TODO mbt 1414
288     //m_zBottom->setShortcut(Qt::Key_End);
289     m_zBottom->setToolTip(i18n("Lower object to bottom"));
290     connect(m_zBottom, SIGNAL(triggered()), this, SLOT(slotZIndexBottom()));
291     zBottom->setDefaultAction(m_zBottom);
292
293     zDown->setIcon(KIcon("kdenlive-zindex-down"));
294     zTop->setIcon(KIcon("kdenlive-zindex-top"));
295     zBottom->setIcon(KIcon("kdenlive-zindex-bottom"));
296     connect(zDown, SIGNAL(clicked()), this, SLOT(slotZIndexDown()));
297     connect(zTop, SIGNAL(clicked()), this, SLOT(slotZIndexTop()));
298     connect(zBottom, SIGNAL(clicked()), this, SLOT(slotZIndexBottom()));
299
300     origin_x_left->setToolTip(i18n("Invert x axis and change 0 point"));
301     origin_y_top->setToolTip(i18n("Invert y axis and change 0 point"));
302     rectBColor->setToolTip(i18n("Select fill color"));
303     rectFColor->setToolTip(i18n("Select border color"));
304     rectBAlpha->setToolTip(i18n("Fill opacity"));
305     rectFAlpha->setToolTip(i18n("Border opacity"));
306     zoom_slider->setToolTip(i18n("Zoom"));
307     buttonRealSize->setToolTip(i18n("Original size (1:1)"));
308     buttonFitZoom->setToolTip(i18n("Fit zoom"));
309     backgroundColor->setToolTip(i18n("Select background color"));
310     backgroundAlpha->setToolTip(i18n("Background opacity"));
311
312     itemhcenter->setIcon(KIcon("kdenlive-align-hor"));
313     itemhcenter->setToolTip(i18n("Align item horizontally"));
314     itemvcenter->setIcon(KIcon("kdenlive-align-vert"));
315     itemvcenter->setToolTip(i18n("Align item vertically"));
316     itemtop->setIcon(KIcon("kdenlive-align-top"));
317     itemtop->setToolTip(i18n("Align item to top"));
318     itembottom->setIcon(KIcon("kdenlive-align-bottom"));
319     itembottom->setToolTip(i18n("Align item to bottom"));
320     itemright->setIcon(KIcon("kdenlive-align-right"));
321     itemright->setToolTip(i18n("Align item to right"));
322     itemleft->setIcon(KIcon("kdenlive-align-left"));
323     itemleft->setToolTip(i18n("Align item to left"));
324
325
326     QHBoxLayout *layout = new QHBoxLayout;
327     frame_toolbar->setLayout(layout);
328     layout->setContentsMargins(0, 0, 0, 0);
329     QToolBar *m_toolbar = new QToolBar("titleToolBar", this);
330     int s = style()->pixelMetric(QStyle::PM_SmallIconSize);
331     m_toolbar->setIconSize(QSize(s, s));
332
333     m_buttonCursor = m_toolbar->addAction(KIcon("transform-move"), QString());
334     m_buttonCursor->setCheckable(true);
335     m_buttonCursor->setShortcut(Qt::ALT + Qt::Key_S);
336     m_buttonCursor->setToolTip(i18n("Selection Tool") + ' ' + m_buttonCursor->shortcut().toString());
337     connect(m_buttonCursor, SIGNAL(triggered()), this, SLOT(slotSelectTool()));
338
339     m_buttonText = m_toolbar->addAction(KIcon("insert-text"), QString());
340     m_buttonText->setCheckable(true);
341     m_buttonText->setShortcut(Qt::ALT + Qt::Key_T);
342     m_buttonText->setToolTip(i18n("Add Text") + ' ' + m_buttonText->shortcut().toString());
343     connect(m_buttonText, SIGNAL(triggered()), this, SLOT(slotTextTool()));
344
345     m_buttonRect = m_toolbar->addAction(KIcon("kdenlive-insert-rect"), QString());
346     m_buttonRect->setCheckable(true);
347     m_buttonRect->setShortcut(Qt::ALT + Qt::Key_R);
348     m_buttonRect->setToolTip(i18n("Add Rectangle") + ' ' + m_buttonRect->shortcut().toString());
349     connect(m_buttonRect, SIGNAL(triggered()), this, SLOT(slotRectTool()));
350
351     m_buttonImage = m_toolbar->addAction(KIcon("insert-image"), QString());
352     m_buttonImage->setCheckable(false);
353     m_buttonImage->setShortcut(Qt::ALT + Qt::Key_I);
354     m_buttonImage->setToolTip(i18n("Add Image") + ' ' + m_buttonImage->shortcut().toString());
355     connect(m_buttonImage, SIGNAL(triggered()), this, SLOT(slotImageTool()));
356
357     m_toolbar->addSeparator();
358
359     m_buttonLoad = m_toolbar->addAction(KIcon("document-open"), i18n("Open Document"));
360     m_buttonLoad->setCheckable(false);
361     m_buttonLoad->setShortcut(Qt::CTRL + Qt::Key_O);
362     connect(m_buttonLoad, SIGNAL(triggered()), this, SLOT(loadTitle()));
363
364     m_buttonSave = m_toolbar->addAction(KIcon("document-save-as"), i18n("Save As"));
365     m_buttonSave->setCheckable(false);
366     m_buttonSave->setShortcut(Qt::CTRL + Qt::Key_S);
367     connect(m_buttonSave, SIGNAL(triggered()), this, SLOT(saveTitle()));
368
369     layout->addWidget(m_toolbar);
370
371     // initialize graphic scene
372     m_scene = new GraphicsSceneRectMove(this);
373     graphicsView->setScene(m_scene);
374     graphicsView->setMouseTracking(true);
375     m_titledocument.setScene(m_scene, m_frameWidth, m_frameHeight);
376     connect(m_scene, SIGNAL(changed(QList<QRectF>)), this, SLOT(slotChanged()));
377     connect(font_size, SIGNAL(valueChanged(int)), m_scene, SLOT(slotUpdateFontSize(int)));
378
379     // a gradient background
380     /*QRadialGradient *gradient = new QRadialGradient(0, 0, 10);
381     gradient->setSpread(QGradient::ReflectSpread);
382     scene->setBackgroundBrush(*gradient);*/
383
384     m_frameImage = new QGraphicsPixmapItem();
385     QTransform qtrans;
386     qtrans.scale(2.0, 2.0);
387     m_frameImage->setTransform(qtrans);
388     m_frameImage->setZValue(-1200);
389     m_frameImage->setFlags(0);
390     displayBackgroundFrame();
391     graphicsView->scene()->addItem(m_frameImage);
392
393     connect(m_scene, SIGNAL(selectionChanged()), this , SLOT(selectionChanged()));
394     connect(m_scene, SIGNAL(itemMoved()), this , SLOT(selectionChanged()));
395     connect(m_scene, SIGNAL(sceneZoom(bool)), this , SLOT(slotZoom(bool)));
396     connect(m_scene, SIGNAL(actionFinished()), this , SLOT(slotSelectTool()));
397     //connect(m_scene, SIGNAL(actionFinished()), this , SLOT(selectionChanged()));
398     connect(m_scene, SIGNAL(newRect(QGraphicsRectItem *)), this , SLOT(slotNewRect(QGraphicsRectItem *)));
399     connect(m_scene, SIGNAL(newText(QGraphicsTextItem *)), this , SLOT(slotNewText(QGraphicsTextItem *)));
400     connect(zoom_slider, SIGNAL(valueChanged(int)), this , SLOT(slotUpdateZoom(int)));
401
402     QPen framepen(Qt::DotLine);
403     framepen.setColor(Qt::red);
404
405     m_frameBorder = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
406     m_frameBorder->setPen(framepen);
407     m_frameBorder->setZValue(-1100);
408     m_frameBorder->setBrush(Qt::transparent);
409     m_frameBorder->setFlags(0);
410     graphicsView->scene()->addItem(m_frameBorder);
411
412     // mbd: load saved settings
413     readChoices();
414
415     graphicsView->show();
416     //graphicsView->setRenderHint(QPainter::Antialiasing);
417     graphicsView->setInteractive(true);
418     //graphicsView->resize(400, 300);
419     kDebug() << "// TITLE WIDGWT: " << graphicsView->viewport()->width() << "x" << graphicsView->viewport()->height();
420     //toolBox->setItemEnabled(2, false);
421     m_startViewport = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
422     m_endViewport = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
423     m_startViewport->setData(0, m_frameWidth);
424     m_startViewport->setData(1, m_frameHeight);
425     m_endViewport->setData(0, m_frameWidth);
426     m_endViewport->setData(1, m_frameHeight);
427
428     if(!url.isEmpty()) loadTitle(url);
429     else {
430         slotTextTool();
431         QTimer::singleShot(200, this, SLOT(slotAdjustZoom()));
432     }
433     initAnimation();
434     connect(anim_start, SIGNAL(toggled(bool)), this, SLOT(slotAnimStart(bool)));
435     connect(anim_end, SIGNAL(toggled(bool)), this, SLOT(slotAnimEnd(bool)));
436     connect(templateBox, SIGNAL(currentIndexChanged(int)), this, SLOT(templateIndexChanged(int)));
437
438     buttonBox->button(QDialogButtonBox::Ok)->setEnabled(KdenliveSettings::hastitleproducer());
439     refreshTitleTemplates();
440     //templateBox->setIconSize(QSize(60,60));
441     templateBox->clear();
442     templateBox->addItem("");
443     foreach(TitleTemplate t, titletemplates) {
444         templateBox->addItem(t.icon, t.name, t.file);
445     }
446     lastDocumentHash = QCryptographicHash::hash(xml().toString().toAscii(), QCryptographicHash::Md5).toHex();
447 }
448
449 TitleWidget::~TitleWidget()
450 {
451     delete m_buttonRect;
452     delete m_buttonText;
453     delete m_buttonImage;
454     delete m_buttonCursor;
455     delete m_buttonSave;
456     delete m_buttonLoad;
457     delete m_unicodeAction;
458     delete m_zUp;
459     delete m_zDown;
460     delete m_zTop;
461     delete m_zBottom;
462
463     delete m_unicodeDialog;
464     delete m_frameBorder;
465     delete m_frameImage;
466     delete m_startViewport;
467     delete m_endViewport;
468     delete m_scene;
469     delete m_signalMapper;
470 }
471
472 //static
473 QStringList TitleWidget::getFreeTitleInfo(const KUrl &projectUrl, bool isClone)
474 {
475     QStringList result;
476     QString titlePath = projectUrl.path(KUrl::AddTrailingSlash) + "titles/";
477     KStandardDirs::makeDir(titlePath);
478     titlePath.append((isClone == false) ? "title" : "clone");
479     int counter = 0;
480     QString path;
481     while(path.isEmpty() || QFile::exists(path)) {
482         counter++;
483         path = titlePath + QString::number(counter).rightJustified(3, '0', false) + ".png";
484     }
485     result.append(((isClone == false) ? i18n("Title") : i18n("Clone")) + ' ' + QString::number(counter).rightJustified(3, '0', false));
486     result.append(path);
487     return result;
488 }
489
490 // static
491 QString TitleWidget::getTitleResourceFromName(const KUrl &projectUrl, const QString &titleName)
492 {
493     QStringList result;
494     QString titlePath = projectUrl.path(KUrl::AddTrailingSlash) + "titles/";
495     KStandardDirs::makeDir(titlePath);
496     return titlePath + titleName + ".png";
497 }
498
499 // static
500 QStringList TitleWidget::extractImageList(QString xml)
501 {
502     QStringList result;
503     if(xml.isEmpty()) return result;
504     QDomDocument doc;
505     doc.setContent(xml);
506     QDomNodeList images = doc.elementsByTagName("content");
507     for(int i = 0; i < images.count(); i++) {
508         if(images.at(i).toElement().hasAttribute("url"))
509             result.append(images.at(i).toElement().attribute("url"));
510     }
511     return result;
512 }
513
514 // static
515 QStringList TitleWidget::extractFontList(QString xml)
516 {
517     QStringList result;
518     if(xml.isEmpty()) return result;
519     QDomDocument doc;
520     doc.setContent(xml);
521     QDomNodeList images = doc.elementsByTagName("content");
522     for(int i = 0; i < images.count(); i++) {
523         if(images.at(i).toElement().hasAttribute("font"))
524             result.append(images.at(i).toElement().attribute("font"));
525     }
526     return result;
527 }
528 //static
529 void TitleWidget::refreshTitleTemplates()
530 {
531     QStringList titlenamelist = QStringList() << i18n("None");
532     QStringList titlefiles = QStringList() << QString();
533     QStringList filters;
534     filters << "*.kdenlivetitle" ;
535     titletemplates.clear();
536     QStringList titleTemplates = KGlobal::dirs()->findDirs("appdata", "titles");
537     foreach(const QString & folder, titleTemplates) {
538         QStringList filesnames = QDir(folder).entryList(filters, QDir::Files);
539         foreach(const QString & fname, filesnames) {
540             //titlenamelist.append(fname);
541             //titlefiles.append(KUrl(folder).path(KUrl::AddTrailingSlash) + fname);
542             TitleTemplate t;
543             t.name = fname;
544             t.file = KUrl(folder).path(KUrl::AddTrailingSlash) + fname;
545             t.icon = QIcon(KThumb::getImage(t.file, 0, 60, 60));
546             titletemplates.append(t);
547         }
548     }
549     kDebug()  << titlenamelist << titlefiles;
550 }
551 void TitleWidget::templateIndexChanged(int index)
552 {
553     QString item = templateBox->itemData(index).toString();
554     if(item != "") {
555         if(lastDocumentHash != QCryptographicHash::hash(xml().toString().toAscii(), QCryptographicHash::Md5).toHex()) {
556             if(KMessageBox::questionYesNo(this, i18n("Do you really want to load a new template? Changes in this title will be lost!")) == KMessageBox::No) return;
557         }
558         loadTitle(item);
559
560         // mbt 1607: Add property to distinguish between unchanged template titles and user titles.
561         // Text of unchanged template titles should be selected when clicked.
562         QList<QGraphicsItem *> list = graphicsView->scene()->items();
563         foreach(QGraphicsItem * qgItem, list) {
564             if(qgItem->type() == TEXTITEM) {
565                 QGraphicsTextItem *i;
566                 i = static_cast<QGraphicsTextItem *>(qgItem);
567                 i->setProperty("isTemplate", "true");
568                 i->setProperty("templateText", i->toHtml());
569             }
570
571         }
572         lastDocumentHash = QCryptographicHash::hash(xml().toString().toAscii(), QCryptographicHash::Md5).toHex();
573     }
574 }
575 //virtual
576 void TitleWidget::resizeEvent(QResizeEvent * /*event*/)
577 {
578     //slotAdjustZoom();
579 }
580
581 void TitleWidget::slotTextTool()
582 {
583     m_scene->setTool(TITLE_TEXT);
584     showToolbars(TITLE_TEXT);
585     checkButton(TITLE_TEXT);
586 }
587
588 void TitleWidget::slotRectTool()
589 {
590     m_scene->setTool(TITLE_RECTANGLE);
591     showToolbars(TITLE_RECTANGLE);
592     checkButton(TITLE_RECTANGLE);
593 }
594
595 void TitleWidget::slotSelectTool()
596 {
597     m_scene->setTool(TITLE_SELECT);
598
599     // Find out which toolbars need to be shown, depending on selected item
600     TITLETOOL t = TITLE_SELECT;
601     QList<QGraphicsItem *> l = graphicsView->scene()->selectedItems();
602     if(l.size() > 0) {
603         switch(l.at(0)->type()) {
604         case TEXTITEM:
605             t = TITLE_TEXT;
606             break;
607         case RECTITEM:
608             t = TITLE_RECTANGLE;
609             break;
610         case IMAGEITEM:
611             t = TITLE_IMAGE;
612             break;
613         }
614     }
615
616     enableToolbars(t);
617     if(t == TITLE_RECTANGLE && (l.at(0) == m_endViewport || l.at(0) == m_startViewport)) {
618         //graphicsView->centerOn(l.at(0));
619         t = TITLE_SELECT;
620     }
621     showToolbars(t);
622
623     if(l.size() > 0) {
624         updateCoordinates(l.at(0));
625         updateDimension(l.at(0));
626         updateRotZoom(l.at(0));
627     }
628
629     checkButton(TITLE_SELECT);
630 }
631
632 void TitleWidget::slotImageTool()
633 {
634     // TODO: find a way to get a list of all supported image types...
635     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";
636     KUrl url = KFileDialog::getOpenUrl(KUrl(), allExtensions, this, i18n("Load Image")); //"*.svg *.png *.jpg *.jpeg *.gif *.raw"
637     if(!url.isEmpty()) {
638         if(url.path().endsWith(".svg")) {
639             QGraphicsSvgItem *svg = new QGraphicsSvgItem(url.toLocalFile());
640             svg->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
641             svg->setZValue(m_count++);
642             svg->setData(Qt::UserRole, url.path());
643             graphicsView->scene()->addItem(svg);
644         } else {
645             QPixmap pix(url.path());
646             QGraphicsPixmapItem *image = new QGraphicsPixmapItem(pix);
647             image->setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
648             image->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
649             image->setData(Qt::UserRole, url.path());
650             image->setZValue(m_count++);
651             graphicsView->scene()->addItem(image);
652         }
653     }
654     m_scene->setTool(TITLE_SELECT);
655     showToolbars(TITLE_SELECT);
656     checkButton(TITLE_SELECT);
657 }
658
659 void TitleWidget::showToolbars(TITLETOOL toolType)
660 {
661     toolbar_stack->setCurrentIndex((int) toolType);
662 }
663
664 void TitleWidget::enableToolbars(TITLETOOL toolType)
665 {
666     // TITLETOOL is defined in graphicsscenerectmove.h
667     bool enable = false;
668     if(toolType == TITLE_RECTANGLE || toolType == TITLE_IMAGE) enable = true;
669     value_w->setEnabled(enable);
670     value_h->setEnabled(enable);
671 }
672
673 void TitleWidget::checkButton(TITLETOOL toolType)
674 {
675     bool bSelect = false;
676     bool bText = false;
677     bool bRect = false;
678     bool bImage = false;
679
680     switch(toolType) {
681     case TITLE_SELECT:
682         bSelect = true;
683         break;
684     case TITLE_TEXT:
685         bText = true;
686         break;
687     case TITLE_RECTANGLE:
688         bRect = true;
689         break;
690     case TITLE_IMAGE:
691         bImage = true;
692         break;
693     default:
694         break;
695     }
696
697     m_buttonCursor->setChecked(bSelect);
698     m_buttonText->setChecked(bText);
699     m_buttonRect->setChecked(bRect);
700     m_buttonImage->setChecked(bImage);
701 }
702
703 void TitleWidget::displayBackgroundFrame()
704 {
705     if(!displayBg->isChecked()) {
706         QPixmap bg(m_frameWidth / 2, m_frameHeight / 2);
707         QPixmap pattern(20, 20);
708         pattern.fill();
709         QColor bgcolor(210, 210, 210);
710         QPainter p;
711         p.begin(&pattern);
712         p.fillRect(QRect(0, 0, 10, 10), bgcolor);
713         p.fillRect(QRect(10, 10, 20, 20), bgcolor);
714         p.end();
715         QBrush br(pattern);
716
717         p.begin(&bg);
718         p.fillRect(bg.rect(), br);
719         p.end();
720         m_frameImage->setPixmap(bg);
721     } else {
722         m_frameImage->setPixmap(QPixmap::fromImage(m_render->extractFrame((int) m_render->seekPosition().frames(m_render->fps()), m_frameWidth / 2, m_frameHeight / 2)));
723     }
724 }
725
726 void TitleWidget::initAnimation()
727 {
728     align_box->setEnabled(false);
729     QPen startpen(Qt::DotLine);
730     QPen endpen(Qt::DashDotLine);
731     startpen.setColor(QColor(100, 200, 100, 140));
732     endpen.setColor(QColor(200, 100, 100, 140));
733
734     m_startViewport->setPen(startpen);
735     m_endViewport->setPen(endpen);
736
737     m_startViewport->setZValue(-1000);
738     m_endViewport->setZValue(-1000);
739
740     m_startViewport->setFlags(0);
741     m_endViewport->setFlags(0);
742
743     graphicsView->scene()->addItem(m_startViewport);
744     graphicsView->scene()->addItem(m_endViewport);
745
746     connect(keep_aspect, SIGNAL(toggled(bool)), this, SLOT(slotKeepAspect(bool)));
747     connect(resize50, SIGNAL(clicked()), this, SLOT(slotResize50()));
748     connect(resize100, SIGNAL(clicked()), this, SLOT(slotResize100()));
749     connect(resize200, SIGNAL(clicked()), this, SLOT(slotResize200()));
750 }
751
752 void TitleWidget::slotUpdateZoom(int pos)
753 {
754     m_scene->setZoom((double) pos / 100);
755     zoom_label->setText(QString::number(pos) + '%');
756 }
757
758 void TitleWidget::slotZoom(bool up)
759 {
760     int pos = zoom_slider->value();
761     if(up) pos++;
762     else pos--;
763     zoom_slider->setValue(pos);
764 }
765
766 void TitleWidget::slotAdjustZoom()
767 {
768     /*double scalex = graphicsView->width() / (double)(m_frameWidth * 1.2);
769     double scaley = graphicsView->height() / (double)(m_frameHeight * 1.2);
770     if (scalex > scaley) scalex = scaley;
771     int zoompos = (int)(scalex * 7 + 0.5);*/
772     graphicsView->fitInView(m_frameBorder, Qt::KeepAspectRatio);
773     int zoompos = graphicsView->matrix().m11() * 100;
774     zoom_slider->setValue(zoompos);
775     graphicsView->centerOn(m_frameBorder);
776 }
777
778 void TitleWidget::slotZoomOneToOne()
779 {
780     zoom_slider->setValue(100);
781     graphicsView->centerOn(m_frameBorder);
782 }
783
784 void TitleWidget::slotNewRect(QGraphicsRectItem * rect)
785 {
786     updateAxisButtons(rect); // back to default
787
788     QColor f = rectFColor->color();
789     f.setAlpha(rectFAlpha->value());
790     QPen penf(f);
791     penf.setWidth(rectLineWidth->value());
792     penf.setJoinStyle(Qt::RoundJoin);
793     rect->setPen(penf);
794     QColor b = rectBColor->color();
795     b.setAlpha(rectBAlpha->value());
796     rect->setBrush(QBrush(b));
797     rect->setZValue(m_count++);
798     rect->setData(ZOOMFACTOR, 100);
799     //setCurrentItem(rect);
800     //graphicsView->setFocus();
801 }
802
803 void TitleWidget::slotNewText(QGraphicsTextItem *tt)
804 {
805     updateAxisButtons(tt); // back to default
806
807     QFont font = font_family->currentFont();
808     font.setPixelSize(font_size->value());
809     // mbd: issue 551:
810     font.setWeight(font_weight_box->itemData(font_weight_box->currentIndex()).toInt());
811     font.setItalic(buttonItalic->isChecked());
812     font.setUnderline(buttonUnder->isChecked());
813
814     tt->setFont(font);
815     QColor color = fontColorButton->color();
816     color.setAlpha(textAlpha->value());
817     tt->setDefaultTextColor(color);
818
819     QTextCursor cur(tt->document());
820     cur.select(QTextCursor::Document);
821     QTextBlockFormat format = cur.blockFormat();
822     QTextCharFormat cformat = cur.charFormat();
823     QColor outlineColor = textOutlineColor->color();
824     outlineColor.setAlpha(textOutlineAlpha->value());
825     double outlineWidth = textOutline->value() / 10.0;
826
827     tt->setData(101, outlineWidth);
828     tt->setData(102, outlineColor);
829     if(outlineWidth > 0.0) cformat.setTextOutline(QPen(outlineColor, outlineWidth));
830
831     cformat.setForeground(QBrush(color));
832     cur.setCharFormat(cformat);
833     cur.setBlockFormat(format);
834     tt->setTextCursor(cur);
835     tt->setZValue(m_count++);
836     setCurrentItem(tt);
837 }
838
839 void TitleWidget::setFontBoxWeight(int weight)
840 {
841     int index = font_weight_box->findData(weight);
842     if(index < 0) {
843         index = font_weight_box->findData(QFont::Normal);
844     }
845     font_weight_box->setCurrentIndex(index);
846 }
847
848 void TitleWidget::setCurrentItem(QGraphicsItem *item)
849 {
850     m_scene->setSelectedItem(item);
851 }
852
853 void TitleWidget::zIndexChanged(int v)
854 {
855     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
856     if(l.size() >= 1) {
857         l[0]->setZValue(v);
858     }
859 }
860
861 void TitleWidget::selectionChanged()
862 {
863     if(m_scene->tool() != TITLE_SELECT) return;
864
865     std::cout << "Number of selected items: " << graphicsView->scene()->selectedItems().length() << "\n";
866
867     QList<QGraphicsItem *> l;
868
869     // mbt 1607: One text item might have grabbed the keyboard.
870     // Ungrab it for all items that are not selected, otherwise
871     // text input would only work for the text item that grabbed
872     // the keyboard last.
873     l = graphicsView->scene()->items();
874     foreach(QGraphicsItem * item, l) {
875         if(item->type() == TEXTITEM && !item->isSelected()) {
876             QGraphicsTextItem *i = static_cast<QGraphicsTextItem *>(item);
877             i->ungrabKeyboard();
878         }
879     }
880
881     l = graphicsView->scene()->selectedItems();
882     //toolBox->setItemEnabled(2, false);
883     //toolBox->setItemEnabled(3, false);
884     effect_list->blockSignals(true);
885     value_x->blockSignals(true);
886     value_y->blockSignals(true);
887     value_w->blockSignals(true);
888     value_h->blockSignals(true);
889     itemzoom->blockSignals(true);
890     itemrotatex->blockSignals(true);
891     itemrotatey->blockSignals(true);
892     itemrotatez->blockSignals(true);
893     if(l.size() == 0) {
894         effect_stack->setHidden(true);
895         effect_frame->setEnabled(false);
896         effect_list->setCurrentIndex(0);
897         bool blockX = !origin_x_left->signalsBlocked();
898         bool blockY = !origin_y_top->signalsBlocked();
899         if(blockX) origin_x_left->blockSignals(true);
900         if(blockY) origin_y_top->blockSignals(true);
901         origin_x_left->setChecked(false);
902         origin_y_top->setChecked(false);
903         updateTextOriginX();
904         updateTextOriginY();
905         enableToolbars(TITLE_SELECT);
906         if(blockX) origin_x_left->blockSignals(false);
907         if(blockY) origin_y_top->blockSignals(false);
908         itemzoom->setEnabled(false);
909         itemrotatex->setEnabled(false);
910         itemrotatey->setEnabled(false);
911         itemrotatez->setEnabled(false);
912         frame_properties->setEnabled(false);
913     } else if(l.size() == 1) {
914         effect_frame->setEnabled(true);
915         frame_properties->setEnabled(true);
916         if(l.at(0) != m_startViewport && l.at(0) != m_endViewport) {
917             itemzoom->setEnabled(true);
918             itemrotatex->setEnabled(true);
919             itemrotatey->setEnabled(true);
920             itemrotatez->setEnabled(true);
921         } else {
922             itemzoom->setEnabled(false);
923             itemrotatex->setEnabled(false);
924             itemrotatey->setEnabled(false);
925             itemrotatez->setEnabled(false);
926             updateInfoText();
927         }
928         if(l.at(0)->type() == TEXTITEM) {
929             showToolbars(TITLE_TEXT);
930             QGraphicsTextItem* i = static_cast <QGraphicsTextItem *>(l.at(0));
931             if(!i->data(100).isNull()) {
932                 // Item has an effect
933                 QStringList effdata = i->data(100).toStringList();
934                 QString effectName = effdata.takeFirst();
935                 if(effectName == "typewriter") {
936                     QStringList params = effdata.at(0).split(';');
937                     typewriter_delay->setValue(params.at(0).toInt());
938                     typewriter_start->setValue(params.at(1).toInt());
939                     effect_list->setCurrentIndex(effect_list->findData((int) TYPEWRITEREFFECT));
940                     effect_stack->setHidden(false);
941                 }
942             } else {
943 #if QT_VERSION >= 0x040600
944                 if(i->graphicsEffect()) {
945                     QGraphicsBlurEffect *blur = static_cast <QGraphicsBlurEffect *>(i->graphicsEffect());
946                     if(blur) {
947                         effect_list->setCurrentIndex(effect_list->findData((int) BLUREFFECT));
948                         int rad = (int) blur->blurRadius();
949                         blur_radius->setValue(rad);
950                         effect_stack->setHidden(false);
951                     } else {
952                         QGraphicsDropShadowEffect *shad = static_cast <QGraphicsDropShadowEffect *>(i->graphicsEffect());
953                         if(shad) {
954                             effect_list->setCurrentIndex(effect_list->findData((int) SHADOWEFFECT));
955                             shadow_radius->setValue(shad->blurRadius());
956                             shadow_x->setValue(shad->xOffset());
957                             shadow_y->setValue(shad->yOffset());
958                             effect_stack->setHidden(false);
959                         }
960                     }
961                 } else {
962                     effect_list->setCurrentIndex(effect_list->findData((int) NOEFFECT));
963                     effect_stack->setHidden(true);
964                 }
965 #else
966                 effect_list->setCurrentIndex(effect_list->findData((int) NOEFFECT));
967                 effect_stack->setHidden(true);
968 #endif
969             }
970             //if (l[0]->hasFocus())
971             //toolBox->setCurrentIndex(0);
972             //toolBox->setItemEnabled(2, true);
973             font_size->blockSignals(true);
974             font_family->blockSignals(true);
975             font_weight_box->blockSignals(true);
976             buttonItalic->blockSignals(true);
977             buttonUnder->blockSignals(true);
978             fontColorButton->blockSignals(true);
979             textAlpha->blockSignals(true);
980             buttonAlignLeft->blockSignals(true);
981             buttonAlignRight->blockSignals(true);
982             buttonAlignNone->blockSignals(true);
983             buttonAlignCenter->blockSignals(true);
984
985             QFont font = i->font();
986             font_family->setCurrentFont(font);
987             font_size->setValue(font.pixelSize());
988             m_scene->slotUpdateFontSize(font.pixelSize());
989             buttonItalic->setChecked(font.italic());
990             buttonUnder->setChecked(font.underline());
991             setFontBoxWeight(font.weight());
992
993             QTextCursor cursor(i->document());
994             cursor.select(QTextCursor::Document);
995             QColor color = cursor.charFormat().foreground().color();
996             textAlpha->setValue(color.alpha());
997             color.setAlpha(255);
998             fontColorButton->setColor(color);
999
1000             if(!i->data(101).isNull()) {
1001                 textOutline->blockSignals(true);
1002                 textOutline->setValue(i->data(101).toDouble() * 10);
1003                 textOutline->blockSignals(false);
1004             }
1005             if(!i->data(102).isNull()) {
1006                 textOutlineColor->blockSignals(true);
1007                 textOutlineAlpha->blockSignals(true);
1008                 color = QColor(i->data(102).toString());
1009                 textOutlineAlpha->setValue(color.alpha());
1010                 color.setAlpha(255);
1011                 textOutlineColor->setColor(color);
1012                 textOutlineColor->blockSignals(false);
1013                 textOutlineAlpha->blockSignals(false);
1014             }
1015             QTextCursor cur = i->textCursor();
1016             QTextBlockFormat format = cur.blockFormat();
1017             if(i->textWidth() == -1) buttonAlignNone->setChecked(true);
1018             else if(format.alignment() == Qt::AlignHCenter) buttonAlignCenter->setChecked(true);
1019             else if(format.alignment() == Qt::AlignRight) buttonAlignRight->setChecked(true);
1020             else if(format.alignment() == Qt::AlignLeft) buttonAlignLeft->setChecked(true);
1021
1022             font_size->blockSignals(false);
1023             font_family->blockSignals(false);
1024             font_weight_box->blockSignals(false);
1025             buttonItalic->blockSignals(false);
1026             buttonUnder->blockSignals(false);
1027             fontColorButton->blockSignals(false);
1028             textAlpha->blockSignals(false);
1029             buttonAlignLeft->blockSignals(false);
1030             buttonAlignRight->blockSignals(false);
1031             buttonAlignNone->blockSignals(false);
1032             buttonAlignCenter->blockSignals(false);
1033
1034             // mbt 1607: Select text if the text item is an unchanged template item.
1035             if(i->property("isTemplate").isValid()) {
1036                 cur.setPosition(0, QTextCursor::MoveAnchor);
1037                 cur.select(QTextCursor::Document);
1038                 i->setTextCursor(cur);
1039                 // Make text editable now.
1040                 i->grabKeyboard();
1041                 i->setTextInteractionFlags(Qt::TextEditorInteraction);
1042             }
1043
1044             updateAxisButtons(i);
1045             updateCoordinates(i);
1046             updateDimension(i);
1047             enableToolbars(TITLE_TEXT);
1048
1049         } else if((l.at(0))->type() == RECTITEM) {
1050             showToolbars(TITLE_RECTANGLE);
1051             settingUp = true;
1052             QGraphicsRectItem *rec = static_cast <QGraphicsRectItem *>(l.at(0));
1053             if(rec == m_startViewport || rec == m_endViewport) {
1054                 /*toolBox->setCurrentIndex(3);
1055                 toolBox->widget(0)->setEnabled(false);
1056                 toolBox->widget(1)->setEnabled(false);*/
1057                 enableToolbars(TITLE_SELECT);
1058             } else {
1059                 /*toolBox->widget(0)->setEnabled(true);
1060                 toolBox->widget(1)->setEnabled(true);
1061                 toolBox->setCurrentIndex(0);*/
1062                 //toolBox->setItemEnabled(3, true);
1063                 rectFAlpha->setValue(rec->pen().color().alpha());
1064                 rectBAlpha->setValue(rec->brush().color().alpha());
1065                 //kDebug() << rec->brush().color().alpha();
1066                 QColor fcol = rec->pen().color();
1067                 QColor bcol = rec->brush().color();
1068                 //fcol.setAlpha(255);
1069                 //bcol.setAlpha(255);
1070                 rectFColor->setColor(fcol);
1071                 rectBColor->setColor(bcol);
1072                 settingUp = false;
1073                 rectLineWidth->setValue(rec->pen().width());
1074                 enableToolbars(TITLE_RECTANGLE);
1075             }
1076
1077             updateAxisButtons(l.at(0));
1078             updateCoordinates(rec);
1079             updateDimension(rec);
1080
1081         } else if(l.at(0)->type() == IMAGEITEM) {
1082             showToolbars(TITLE_IMAGE);
1083
1084             updateCoordinates(l.at(0));
1085             updateDimension(l.at(0));
1086
1087             enableToolbars(TITLE_IMAGE);
1088
1089         } else {
1090             //toolBox->setCurrentIndex(0);
1091             showToolbars(TITLE_SELECT);
1092             enableToolbars(TITLE_SELECT);
1093             frame_properties->setEnabled(false);
1094         }
1095         zValue->setValue((int)l.at(0)->zValue());
1096         if(!l.at(0)->data(ZOOMFACTOR).isNull()) itemzoom->setValue(l.at(0)->data(ZOOMFACTOR).toInt());
1097         else itemzoom->setValue((int)(m_transformations.value(l.at(0)).scalex * 100.0 + 0.5));
1098         itemrotatex->setValue((int)(m_transformations.value(l.at(0)).rotatex));
1099         itemrotatey->setValue((int)(m_transformations.value(l.at(0)).rotatey));
1100         itemrotatez->setValue((int)(m_transformations.value(l.at(0)).rotatez));
1101         value_x->blockSignals(false);
1102         value_y->blockSignals(false);
1103         value_w->blockSignals(false);
1104         value_h->blockSignals(false);
1105         itemzoom->blockSignals(false);
1106         itemrotatex->blockSignals(false);
1107         itemrotatey->blockSignals(false);
1108         itemrotatez->blockSignals(false);
1109     } else {
1110         // More than one item selected
1111         //TODO
1112     }
1113     // Tools working on more than one element.
1114     if(l.size() > 0)
1115         effect_list->blockSignals(false);
1116
1117 }
1118
1119 void TitleWidget::slotValueChanged(int type)
1120 {
1121     QList<QGraphicsItem *> l = graphicsView->scene()->selectedItems();
1122     if(l.size() > 0 && l.at(0)->type() == IMAGEITEM) {
1123
1124         int val = 0;
1125         switch(type) {
1126         case ValueWidth:
1127             val = value_w->value();
1128             break;
1129         case ValueHeight:
1130             val = value_h->value();
1131             break;
1132         }
1133
1134         QGraphicsItem *i = l.at(0);
1135         Transform t = m_transformations.value(i);
1136
1137         // Ratio width:height
1138         double phi = (double) i->boundingRect().width() / i->boundingRect().height();
1139         // TODO: proper calculation for rotation around 3 axes
1140         double alpha = (double) t.rotatez / 180.0 * M_PI;
1141
1142         // New length
1143         double length = val;
1144
1145         // Scaling factor
1146         double scale = 1;
1147
1148         switch(type) {
1149         case ValueWidth:
1150             // Add 0.5 because otherwise incrementing by 1 might have no effect
1151             length = val / (cos(alpha) + 1 / phi * sin(alpha)) + 0.5;
1152             scale = length / i->boundingRect().width();
1153             break;
1154         case ValueHeight:
1155             length = val / (phi * sin(alpha) + cos(alpha)) + 0.5;
1156             scale = length / i->boundingRect().height();
1157             break;
1158         }
1159
1160         t.scalex = scale;
1161         t.scaley = scale;
1162         QTransform qtrans;
1163         qtrans.scale(scale, scale);
1164         qtrans.rotate(t.rotatex, Qt::XAxis);
1165         qtrans.rotate(t.rotatey, Qt::YAxis);
1166         qtrans.rotate(t.rotatez, Qt::ZAxis);
1167         i->setTransform(qtrans);
1168         m_transformations[i] = t;
1169
1170         updateDimension(i);
1171         updateRotZoom(i);
1172     }
1173 }
1174
1175 void TitleWidget::slotAdjustSelectedItem()
1176 {
1177     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1178     if(l.size() >= 1) {
1179         if(l.at(0)->type() == RECTITEM) {
1180             //rect item
1181             QGraphicsRectItem *rec = static_cast <QGraphicsRectItem *>(l.at(0));
1182             updatePosition(rec);
1183             rec->setRect(QRect(0, 0, value_w->value(), value_h->value()));
1184         } else if(l.at(0)->type() == TEXTITEM) {
1185             //text item
1186             updatePosition(l.at(0));
1187         } else if(l.at(0)->type() == IMAGEITEM) {
1188             //image item
1189             updatePosition(l.at(0));
1190         }
1191     }
1192 }
1193
1194 void TitleWidget::updateDimension(QGraphicsItem *i)
1195 {
1196     value_w->blockSignals(true);
1197     value_h->blockSignals(true);
1198     zValue->blockSignals(true);
1199
1200     zValue->setValue((int) i->zValue());
1201     if(i->type() == IMAGEITEM) {
1202         // Get multipliers for rotation/scaling
1203
1204         /*Transform t = m_transformations.value(i);
1205         QRectF r = i->boundingRect();
1206         int width = (int) ( abs(r.width()*t.scalex * cos(t.rotate/180.0*M_PI))
1207                     + abs(r.height()*t.scaley * sin(t.rotate/180.0*M_PI)) );
1208         int height = (int) ( abs(r.height()*t.scaley * cos(t.rotate/180*M_PI))
1209                     + abs(r.width()*t.scalex * sin(t.rotate/180*M_PI)) );*/
1210
1211         value_w->setValue(i->sceneBoundingRect().width());
1212         value_h->setValue(i->sceneBoundingRect().height());
1213     } else if(i->type() == RECTITEM) {
1214         QGraphicsRectItem *r = static_cast <QGraphicsRectItem *>(i);
1215         value_w->setValue((int) r->rect().width());
1216         value_h->setValue((int) r->rect().height());
1217     } else if(i->type() == TEXTITEM) {
1218         QGraphicsTextItem *t = static_cast <QGraphicsTextItem *>(i);
1219         value_w->setValue((int) t->boundingRect().width());
1220         value_h->setValue((int) t->boundingRect().height());
1221     }
1222
1223     zValue->blockSignals(false);
1224     value_w->blockSignals(false);
1225     value_h->blockSignals(false);
1226 }
1227
1228 void TitleWidget::updateCoordinates(QGraphicsItem *i)
1229 {
1230     // Block signals emitted by this method
1231     value_x->blockSignals(true);
1232     value_y->blockSignals(true);
1233
1234     if(i->type() == TEXTITEM) {
1235
1236         QGraphicsTextItem *rec = static_cast <QGraphicsTextItem *>(i);
1237
1238         // Set the correct x coordinate value
1239         if(origin_x_left->isChecked()) {
1240             // Origin (0 point) is at m_frameWidth, coordinate axis is inverted
1241             value_x->setValue((int)(m_frameWidth - rec->pos().x() - rec->boundingRect().width()));
1242         } else {
1243             // Origin is at 0 (default)
1244             value_x->setValue((int) rec->pos().x());
1245         }
1246
1247         // Same for y
1248         if(origin_y_top->isChecked()) {
1249             value_y->setValue((int)(m_frameHeight - rec->pos().y() - rec->boundingRect().height()));
1250         } else {
1251             value_y->setValue((int) rec->pos().y());
1252         }
1253
1254     } else if(i->type() == RECTITEM) {
1255
1256         QGraphicsRectItem *rec = static_cast <QGraphicsRectItem *>(i);
1257
1258         if(origin_x_left->isChecked()) {
1259             // Origin (0 point) is at m_frameWidth
1260             value_x->setValue((int)(m_frameWidth - rec->pos().x() - rec->rect().width()));
1261         } else {
1262             // Origin is at 0 (default)
1263             value_x->setValue((int) rec->pos().x());
1264         }
1265
1266         if(origin_y_top->isChecked()) {
1267             value_y->setValue((int)(m_frameHeight - rec->pos().y() - rec->rect().height()));
1268         } else {
1269             value_y->setValue((int) rec->pos().y());
1270         }
1271
1272     } else if(i->type() == IMAGEITEM) {
1273
1274         if(origin_x_left->isChecked()) {
1275             value_x->setValue((int)(m_frameWidth - i->pos().x() - i->sceneBoundingRect().width()));
1276         } else {
1277             value_x->setValue((int) i->pos().x());
1278         }
1279
1280         if(origin_y_top->isChecked()) {
1281             value_y->setValue((int)(m_frameHeight - i->pos().y() - i->sceneBoundingRect().height()));
1282         } else {
1283             value_y->setValue((int) i->pos().y());
1284         }
1285
1286     }
1287
1288     // Stop blocking signals now
1289     value_x->blockSignals(false);
1290     value_y->blockSignals(false);
1291 }
1292
1293 void TitleWidget::updateRotZoom(QGraphicsItem *i)
1294 {
1295     itemzoom->blockSignals(true);
1296     itemrotatex->blockSignals(true);
1297     itemrotatey->blockSignals(true);
1298     itemrotatez->blockSignals(true);
1299
1300     Transform t = m_transformations.value(i);
1301
1302     if(!i->data(ZOOMFACTOR).isNull()) itemzoom->setValue(i->data(ZOOMFACTOR).toInt());
1303     else itemzoom->setValue((int)(t.scalex * 100.0 + 0.5));
1304
1305     itemrotatex->setValue((int)(t.rotatex));
1306     itemrotatey->setValue((int)(t.rotatey));
1307     itemrotatez->setValue((int)(t.rotatez));
1308
1309     itemzoom->blockSignals(false);
1310     itemrotatex->blockSignals(false);
1311     itemrotatey->blockSignals(false);
1312     itemrotatez->blockSignals(false);
1313 }
1314
1315 void TitleWidget::updatePosition(QGraphicsItem *i)
1316 {
1317     if(i->type() == TEXTITEM) {
1318         QGraphicsTextItem *rec = static_cast <QGraphicsTextItem *>(i);
1319
1320         int posX;
1321         if(origin_x_left->isChecked()) {
1322             /*
1323              * Origin of the X axis is at m_frameWidth, and distance from right
1324              * border of the item to the right border of the frame is taken. See
1325              * comment to slotOriginXClicked().
1326              */
1327             posX = m_frameWidth - value_x->value() - rec->boundingRect().width();
1328         } else {
1329             posX = value_x->value();
1330         }
1331
1332         int posY;
1333         if(origin_y_top->isChecked()) {
1334             /* Same for y axis */
1335             posY = m_frameHeight - value_y->value() - rec->boundingRect().height();
1336         } else {
1337             posY = value_y->value();
1338         }
1339
1340         rec->setPos(posX, posY);
1341
1342     } else if(i->type() == RECTITEM) {
1343
1344         QGraphicsRectItem *rec = static_cast <QGraphicsRectItem *>(i);
1345
1346         int posX;
1347         if(origin_x_left->isChecked()) {
1348             posX = m_frameWidth - value_x->value() - rec->rect().width();
1349         } else {
1350             posX = value_x->value();
1351         }
1352
1353         int posY;
1354         if(origin_y_top->isChecked()) {
1355             posY = m_frameHeight - value_y->value() - rec->rect().height();
1356         } else {
1357             posY = value_y->value();
1358         }
1359
1360         rec->setPos(posX, posY);
1361
1362     } else if(i->type() == IMAGEITEM) {
1363         int posX;
1364         if(origin_x_left->isChecked()) {
1365             // Use the sceneBoundingRect because this also regards transformations like zoom
1366             posX = m_frameWidth - value_x->value() - i->sceneBoundingRect().width();
1367         } else {
1368             posX = value_x->value();
1369         }
1370
1371         int posY;
1372         if(origin_y_top->isChecked()) {
1373             posY = m_frameHeight - value_y->value() - i->sceneBoundingRect().height();
1374         } else {
1375             posY = value_y->value();
1376         }
1377
1378         i->setPos(posX, posY);
1379
1380     }
1381
1382 }
1383
1384 void TitleWidget::updateTextOriginX()
1385 {
1386     if(origin_x_left->isChecked()) {
1387         origin_x_left->setText(i18n("\u2212X"));
1388     } else {
1389         origin_x_left->setText(i18n("+X"));
1390     }
1391 }
1392
1393 void TitleWidget::slotOriginXClicked()
1394 {
1395     // Update the text displayed on the button.
1396     updateTextOriginX();
1397
1398     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1399     if(l.size() >= 1) {
1400         updateCoordinates(l.at(0));
1401
1402         // Remember x axis setting
1403         l.at(0)->setData(TitleDocument::OriginXLeft, origin_x_left->isChecked() ?
1404                          TitleDocument::AxisInverted : TitleDocument::AxisDefault);
1405     }
1406     graphicsView->setFocus();
1407 }
1408
1409 void TitleWidget::updateTextOriginY()
1410 {
1411     if(origin_y_top->isChecked()) {
1412         origin_y_top->setText(i18n("\u2212Y"));
1413     } else {
1414         origin_y_top->setText(i18n("+Y"));
1415     }
1416 }
1417
1418 void TitleWidget::slotOriginYClicked()
1419 {
1420     // Update the text displayed on the button.
1421     updateTextOriginY();
1422
1423     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1424     if(l.size() >= 1) {
1425         updateCoordinates(l.at(0));
1426
1427         l.at(0)->setData(TitleDocument::OriginYTop, origin_y_top->isChecked() ?
1428                          TitleDocument::AxisInverted : TitleDocument::AxisDefault);
1429
1430     }
1431     graphicsView->setFocus();
1432 }
1433
1434 void TitleWidget::updateAxisButtons(QGraphicsItem *i)
1435 {
1436     int xAxis = i->data(TitleDocument::OriginXLeft).toInt();
1437     int yAxis = i->data(TitleDocument::OriginYTop).toInt();
1438     origin_x_left->blockSignals(true);
1439     origin_y_top->blockSignals(true);
1440
1441     if(xAxis == TitleDocument::AxisInverted) {
1442         origin_x_left->setChecked(true);
1443     } else {
1444         origin_x_left->setChecked(false);
1445     }
1446     updateTextOriginX();
1447
1448     if(yAxis == TitleDocument::AxisInverted) {
1449         origin_y_top->setChecked(true);
1450     } else {
1451         origin_y_top->setChecked(false);
1452     }
1453     updateTextOriginY();
1454
1455     origin_x_left->blockSignals(false);
1456     origin_y_top->blockSignals(false);
1457 }
1458
1459 void TitleWidget::slotChangeBackground()
1460 {
1461     QColor color = backgroundColor->color();
1462     color.setAlpha(backgroundAlpha->value());
1463     m_frameBorder->setBrush(QBrush(color));
1464 }
1465
1466 void TitleWidget::slotChanged()
1467 {
1468     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1469     if(l.size() >= 1 && l.at(0)->type() == TEXTITEM) {
1470         textChanged(static_cast <QGraphicsTextItem *>(l.at(0)));
1471     }
1472 }
1473
1474 void TitleWidget::textChanged(QGraphicsTextItem *i)
1475 {
1476     /*
1477      * If the user has set origin_x_left (the same for y), we need to look
1478      * whether a text element has been selected. If yes, we need to ensure that
1479      * the right border of the text field remains fixed also when some text has
1480      * been entered.
1481      *
1482      * This is also known as right-justified, with the difference that it is not
1483      * valid for text but for its boundingRect. Text may still be
1484      * left-justified.
1485      */
1486     updateDimension(i);
1487
1488     if(origin_x_left->isChecked() || origin_y_top->isChecked()) {
1489         if(!i->toPlainText().isEmpty())
1490             updatePosition(i);
1491         else {
1492             /*
1493              * Don't do anything if the string is empty. If the position were
1494              * updated here, a newly created text field would be set to the
1495              * position of the last selected text field.
1496              */
1497         }
1498     }
1499
1500     // mbt 1607: Template text has changed; don't auto-select content anymore.
1501     if(i->property("isTemplate").isValid()) {
1502         if(i->property("templateText").isValid()) {
1503             if(i->property("templateText") == i->toHtml()) {
1504                 // Unchanged, do nothing.
1505             } else {
1506                 i->setProperty("isTemplate", QVariant::Invalid);
1507                 i->setProperty("templateText", QVariant::Invalid);
1508             }
1509         }
1510     }
1511 }
1512
1513 void TitleWidget::slotInsertUnicode()
1514 {
1515     m_unicodeDialog->exec();
1516 }
1517
1518 void TitleWidget::slotInsertUnicodeString(QString text)
1519 {
1520     QList<QGraphicsItem *> l = graphicsView->scene()->selectedItems();
1521     if(l.size() > 0) {
1522         if(l.at(0)->type() == TEXTITEM) {
1523             QGraphicsTextItem *t = static_cast <QGraphicsTextItem *>(l.at(0));
1524             t->textCursor().insertText(text);
1525         }
1526     }
1527 }
1528
1529 void TitleWidget::slotUpdateText()
1530 {
1531     QFont font = font_family->currentFont();
1532     font.setPixelSize(font_size->value());
1533     font.setItalic(buttonItalic->isChecked());
1534     font.setUnderline(buttonUnder->isChecked());
1535     font.setWeight(font_weight_box->itemData(font_weight_box->currentIndex()).toInt());
1536     QColor color = fontColorButton->color();
1537     color.setAlpha(textAlpha->value());
1538
1539     QColor outlineColor = textOutlineColor->color();
1540     outlineColor.setAlpha(textOutlineAlpha->value());
1541     double outlineWidth = textOutline->value() / 10.0;
1542
1543     int i;
1544     for(i = 0; i < graphicsView->scene()->selectedItems().length(); i++) {
1545         QGraphicsTextItem* item = NULL;
1546         QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1547         if(l.at(i)->type() == TEXTITEM) {
1548             item = static_cast <QGraphicsTextItem *>(l.at(i));
1549         }
1550         if(!item) {
1551             // No text item, try next one.
1552             continue;
1553         }
1554
1555         // Set alignment of all text in the text item
1556         QTextCursor cur(item->document());
1557         cur.select(QTextCursor::Document);
1558         QTextBlockFormat format = cur.blockFormat();
1559         if(buttonAlignLeft->isChecked() || buttonAlignCenter->isChecked() || buttonAlignRight->isChecked()) {
1560             item->setTextWidth(item->boundingRect().width());
1561             if(buttonAlignCenter->isChecked()) format.setAlignment(Qt::AlignHCenter);
1562             else if(buttonAlignRight->isChecked()) format.setAlignment(Qt::AlignRight);
1563             else if(buttonAlignLeft->isChecked()) format.setAlignment(Qt::AlignLeft);
1564         } else {
1565             format.setAlignment(Qt::AlignLeft);
1566             item->setTextWidth(-1);
1567         }
1568
1569         // Set font properties
1570         item->setFont(font);
1571         QTextCharFormat cformat = cur.charFormat();
1572
1573         item->setData(101, outlineWidth);
1574         item->setData(102, outlineColor);
1575         if(outlineWidth > 0.0) cformat.setTextOutline(QPen(outlineColor, outlineWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
1576
1577         cformat.setForeground(QBrush(color));
1578         cur.setCharFormat(cformat);
1579         cur.setBlockFormat(format);
1580 //  item->setTextCursor(cur);
1581         cur.clearSelection();
1582         item->setTextCursor(cur);
1583     }
1584 }
1585
1586 void TitleWidget::rectChanged()
1587 {
1588     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1589     int i;
1590     for(i = 0; i < l.length(); i++) {
1591         if(l.at(i)->type() == RECTITEM && !settingUp) {
1592             QGraphicsRectItem *rec = static_cast<QGraphicsRectItem *>(l.at(i));
1593             QColor f = rectFColor->color();
1594             f.setAlpha(rectFAlpha->value());
1595             QPen penf(f);
1596             penf.setWidth(rectLineWidth->value());
1597             penf.setJoinStyle(Qt::RoundJoin);
1598             rec->setPen(penf);
1599             QColor b = rectBColor->color();
1600             b.setAlpha(rectBAlpha->value());
1601             rec->setBrush(QBrush(b));
1602         }
1603     }
1604 }
1605
1606 void TitleWidget::itemScaled(int val)
1607 {
1608     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1609     if(l.size() == 1) {
1610         Transform x = m_transformations.value(l.at(0));
1611         x.scalex = (double)val / 100.0;
1612         x.scaley = (double)val / 100.0;
1613         QTransform qtrans;
1614         qtrans.scale(x.scalex, x.scaley);
1615         qtrans.rotate(x.rotatex, Qt::XAxis);
1616         qtrans.rotate(x.rotatey, Qt::YAxis);
1617         qtrans.rotate(x.rotatez, Qt::ZAxis);
1618         l[0]->setTransform(qtrans);
1619         l[0]->setData(ZOOMFACTOR, val);
1620         m_transformations[l.at(0)] = x;
1621         updateDimension(l.at(0));
1622     }
1623 }
1624
1625 void TitleWidget::itemRotateX(qreal val)
1626 {
1627     itemRotate(val, 0);
1628 }
1629
1630 void TitleWidget::itemRotateY(qreal val)
1631 {
1632     itemRotate(val, 1);
1633 }
1634
1635 void TitleWidget::itemRotateZ(qreal val)
1636 {
1637     itemRotate(val, 2);
1638 }
1639
1640 void TitleWidget::itemRotate(qreal val, int axis)
1641 {
1642     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1643     if(l.size() == 1) {
1644         Transform x = m_transformations[l.at(0)];
1645         switch(axis) {
1646         case 0:
1647             x.rotatex = val;
1648             break;
1649         case 1:
1650             x.rotatey = val;
1651             break;
1652         case 2:
1653             x.rotatez = val;
1654             break;
1655         }
1656
1657         l[0]->setData(ROTATEFACTOR, QList<QVariant>() << QVariant(x.rotatex) << QVariant(x.rotatey) << QVariant(x.rotatez));
1658
1659         QTransform qtrans;
1660         qtrans.scale(x.scalex, x.scaley);
1661         qtrans.rotate(x.rotatex, Qt::XAxis);
1662         qtrans.rotate(x.rotatey, Qt::YAxis);
1663         qtrans.rotate(x.rotatez, Qt::ZAxis);
1664         l[0]->setTransform(qtrans);
1665         m_transformations[l.at(0)] = x;
1666         if(l[0]->data(ZOOMFACTOR).isNull()) l[0]->setData(ZOOMFACTOR, 100);
1667         updateDimension(l.at(0));
1668     }
1669 }
1670
1671 void TitleWidget::itemHCenter()
1672 {
1673     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1674     if(l.size() == 1) {
1675         QGraphicsItem *item = l.at(0);
1676         QRectF br = item->sceneBoundingRect();
1677         int width = (int)br.width();
1678         int newPos = (int)((m_frameWidth - width) / 2);
1679         newPos += item->pos().x() - br.left(); // Check item transformation
1680         item->setPos(newPos, item->pos().y());
1681         updateCoordinates(item);
1682     }
1683 }
1684
1685 void TitleWidget::itemVCenter()
1686 {
1687     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1688     if(l.size() == 1) {
1689         QGraphicsItem *item = l.at(0);
1690         QRectF br = item->sceneBoundingRect();
1691         int height = (int)br.height();
1692         int newPos = (int)((m_frameHeight - height) / 2);
1693         newPos += item->pos().y() - br.top(); // Check item transformation
1694         item->setPos(item->pos().x(), newPos);
1695         updateCoordinates(item);
1696     }
1697 }
1698
1699 void TitleWidget::itemTop()
1700 {
1701     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1702     if(l.size() == 1) {
1703         QGraphicsItem *item = l.at(0);
1704         QRectF br = item->sceneBoundingRect();
1705         double diff;
1706         if(br.top() > 0) diff = -br.top();
1707         else diff = -br.bottom();
1708         item->moveBy(0, diff);
1709         updateCoordinates(item);
1710     }
1711 }
1712
1713 void TitleWidget::itemBottom()
1714 {
1715     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1716     if(l.size() == 1) {
1717         QGraphicsItem *item = l.at(0);
1718         QRectF br = item->sceneBoundingRect();
1719         double diff;
1720         if(br.bottom() > m_frameHeight) diff = m_frameHeight - br.top();
1721         else diff = m_frameHeight - br.bottom();
1722         item->moveBy(0, diff);
1723         updateCoordinates(item);
1724     }
1725 }
1726
1727 void TitleWidget::itemLeft()
1728 {
1729     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1730     if(l.size() == 1) {
1731         QGraphicsItem *item = l.at(0);
1732         QRectF br = item->sceneBoundingRect();
1733         double diff;
1734         if(br.left() > 0) diff = -br.left();
1735         else diff = -br.right();
1736         item->moveBy(diff, 0);
1737         updateCoordinates(item);
1738     }
1739 }
1740
1741 void TitleWidget::itemRight()
1742 {
1743     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
1744     if(l.size() == 1) {
1745         QGraphicsItem *item = l.at(0);
1746         QRectF br = item->sceneBoundingRect();
1747         double diff;
1748         if(br.right() < m_frameWidth) diff = m_frameWidth - br.right();
1749         else diff = m_frameWidth - br.left();
1750         item->moveBy(diff, 0);
1751         updateCoordinates(item);
1752     }
1753 }
1754
1755 void TitleWidget::setupViewports()
1756 {
1757     //double aspect_ratio = 4.0 / 3.0;//read from project
1758     //better zoom centered, but render uses only the created rect, so no problem to change the zoom function
1759     /*QRectF sp(0, 0, startViewportSize->value() * m_frameWidth / 100.0 , startViewportSize->value()* m_frameHeight / 100.0);
1760     QRectF ep(0, 0, endViewportSize->value() * m_frameWidth / 100.0, endViewportSize->value() * m_frameHeight / 100.0);
1761     // use a polygon thiat uses 16:9 and 4:3 rects forpreview the size in all aspect ratios ?
1762     QPolygonF spoly(sp);
1763     QPolygonF epoly(ep);
1764     spoly.translate(startViewportX->value(), startViewportY->value());
1765     epoly.translate(endViewportX->value(), endViewportY->value());
1766     m_startViewport->setPolygon(spoly);
1767     m_endViewport->setPolygon(epoly);
1768     if (! insertingValues) {
1769         m_startViewport->setData(0, startViewportX->value());
1770         m_startViewport->setData(1, startViewportY->value());
1771         m_startViewport->setData(2, startViewportSize->value());
1772
1773         m_endViewport->setData(0, endViewportX->value());
1774         m_endViewport->setData(1, endViewportY->value());
1775         m_endViewport->setData(2, endViewportSize->value());
1776     }*/
1777 }
1778
1779 void TitleWidget::loadTitle(KUrl url)
1780 {
1781     if(url.isEmpty()) url = KFileDialog::getOpenUrl(KUrl(m_projectTitlePath), "application/x-kdenlivetitle", this, i18n("Load Title"));
1782     if(!url.isEmpty()) {
1783         QList<QGraphicsItem *> items = m_scene->items();
1784         for(int i = 0; i < items.size(); i++) {
1785             if(items.at(i)->zValue() > -1000) delete items.at(i);
1786         }
1787         m_scene->clearTextSelection();
1788         QDomDocument doc;
1789         QString tmpfile;
1790
1791         if(KIO::NetAccess::download(url, tmpfile, 0)) {
1792             QFile file(tmpfile);
1793             if(file.open(QIODevice::ReadOnly)) {
1794                 doc.setContent(&file, false);
1795                 file.close();
1796             } else return;
1797             KIO::NetAccess::removeTempFile(tmpfile);
1798         }
1799         setXml(doc);
1800
1801         /*int out;
1802         m_count = m_titledocument.loadDocument(url, m_startViewport, m_endViewport, &out) + 1;
1803         adjustFrameSize();
1804         title_duration->setText(m_tc.getTimecode(GenTime(out, m_render->fps())));
1805         insertingValues = true;
1806         startViewportX->setValue(m_startViewport->data(0).toInt());
1807         startViewportY->setValue(m_startViewport->data(1).toInt());
1808         startViewportSize->setValue(m_startViewport->data(2).toInt());
1809         endViewportX->setValue(m_endViewport->data(0).toInt());
1810         endViewportY->setValue(m_endViewport->data(1).toInt());
1811         endViewportSize->setValue(m_endViewport->data(2).toInt());
1812
1813         insertingValues = false;
1814         slotSelectTool();
1815         slotAdjustZoom();*/
1816     }
1817 }
1818
1819 void TitleWidget::saveTitle(KUrl url)
1820 {
1821     if(anim_start->isChecked()) slotAnimStart(false);
1822     if(anim_end->isChecked()) slotAnimEnd(false);
1823     if(url.isEmpty()) {
1824         KFileDialog *fs = new KFileDialog(KUrl(m_projectTitlePath), "application/x-kdenlivetitle", this);
1825         fs->setOperationMode(KFileDialog::Saving);
1826         fs->setMode(KFile::File);
1827 #if KDE_IS_VERSION(4,2,0)
1828         fs->setConfirmOverwrite(true);
1829 #endif
1830         fs->setKeepLocation(true);
1831         fs->exec();
1832         url = fs->selectedUrl();
1833         delete fs;
1834     }
1835     if(!url.isEmpty()) {
1836         if(m_titledocument.saveDocument(url, m_startViewport, m_endViewport, m_tc.getFrameCount(title_duration->text()) - 1) == false)
1837             KMessageBox::error(this, i18n("Cannot write to file %1", url.path()));
1838     }
1839 }
1840
1841 QDomDocument TitleWidget::xml()
1842 {
1843     QDomDocument doc = m_titledocument.xml(m_startViewport, m_endViewport);
1844     doc.documentElement().setAttribute("out", m_tc.getFrameCount(title_duration->text()) - 1);
1845     return doc;
1846 }
1847
1848 int TitleWidget::outPoint() const
1849 {
1850     return m_tc.getFrameCount(title_duration->text()) - 1;
1851 }
1852
1853 void TitleWidget::setXml(QDomDocument doc)
1854 {
1855     int out;
1856     m_count = m_titledocument.loadFromXml(doc, m_startViewport, m_endViewport, &out);
1857     adjustFrameSize();
1858     title_duration->setText(m_tc.getTimecode(GenTime(out + 1, m_render->fps())));
1859     /*if (doc.documentElement().hasAttribute("out")) {
1860     GenTime duration = GenTime(doc.documentElement().attribute("out").toDouble() / 1000.0);
1861     title_duration->setText(m_tc.getTimecode(duration));
1862     }
1863     else title_duration->setText(m_tc.getTimecode(GenTime(5000)));*/
1864
1865     QDomElement e = doc.documentElement();
1866     m_transformations.clear();
1867     QList <QGraphicsItem *> items = graphicsView->scene()->items();
1868     const double PI = 4.0 * atan(1.0);
1869     for(int i = 0; i < items.count(); i++) {
1870         QTransform t = items.at(i)->transform();
1871         Transform x;
1872         x.scalex = t.m11();
1873         x.scaley = t.m22();
1874         if(!items.at(i)->data(ROTATEFACTOR).isNull()) {
1875             QList<QVariant> rotlist = items.at(i)->data(ROTATEFACTOR).toList();
1876             if(rotlist.count() >= 3) {
1877                 x.rotatex = rotlist[0].toDouble();
1878                 x.rotatey = rotlist[1].toDouble();
1879                 x.rotatez = rotlist[2].toDouble();
1880
1881                 // Try to adjust zoom
1882                 t.rotate(x.rotatex *(-1), Qt::XAxis);
1883                 t.rotate(x.rotatey *(-1), Qt::YAxis);
1884                 t.rotate(x.rotatez *(-1), Qt::ZAxis);
1885                 x.scalex = t.m11();
1886                 x.scaley = t.m22();
1887             } else {
1888                 x.rotatex = 0;
1889                 x.rotatey = 0;
1890                 x.rotatez = 0;
1891             }
1892         } else {
1893             x.rotatex = 0;
1894             x.rotatey = 0;
1895             x.rotatez = 180. / PI * atan2(-t.m21(), t.m11());
1896         }
1897         m_transformations[items.at(i)] = x;
1898     }
1899     // mbd: Update the GUI color selectors to match the stuff from the loaded document
1900     QColor background_color = m_titledocument.getBackgroundColor();
1901     backgroundAlpha->blockSignals(true);
1902     backgroundColor->blockSignals(true);
1903     backgroundAlpha->setValue(background_color.alpha());
1904     background_color.setAlpha(255);
1905     backgroundColor->setColor(background_color);
1906     backgroundAlpha->blockSignals(false);
1907     backgroundColor->blockSignals(false);
1908
1909     /*startViewportX->setValue(m_startViewport->data(0).toInt());
1910     startViewportY->setValue(m_startViewport->data(1).toInt());
1911     startViewportSize->setValue(m_startViewport->data(2).toInt());
1912     endViewportX->setValue(m_endViewport->data(0).toInt());
1913     endViewportY->setValue(m_endViewport->data(1).toInt());
1914     endViewportSize->setValue(m_endViewport->data(2).toInt());*/
1915
1916     QTimer::singleShot(200, this, SLOT(slotAdjustZoom()));
1917     slotSelectTool();
1918     selectionChanged();
1919 }
1920
1921 void TitleWidget::slotAccepted()
1922 {
1923     if(anim_start->isChecked()) slotAnimStart(false);
1924     if(anim_end->isChecked()) slotAnimEnd(false);
1925     writeChoices();
1926 }
1927
1928 void TitleWidget::writeChoices()
1929 {
1930     // Get a pointer to a shared configuration instance, then get the TitleWidget group.
1931     KSharedConfigPtr config = KGlobal::config();
1932     KConfigGroup titleConfig(config, "TitleWidget");
1933     // Write the entries
1934     titleConfig.writeEntry("font_family", font_family->currentFont());
1935     //titleConfig.writeEntry("font_size", font_size->value());
1936     titleConfig.writeEntry("font_pixel_size", font_size->value());
1937     titleConfig.writeEntry("font_color", fontColorButton->color());
1938     titleConfig.writeEntry("font_alpha", textAlpha->value());
1939     titleConfig.writeEntry("font_outline", textOutline->value());
1940     titleConfig.writeEntry("font_outline_color", textOutlineColor->color());
1941     titleConfig.writeEntry("font_outline_alpha", textOutlineAlpha->value());
1942     titleConfig.writeEntry("font_weight", font_weight_box->itemData(font_weight_box->currentIndex()).toInt());
1943     titleConfig.writeEntry("font_italic", buttonItalic->isChecked());
1944     titleConfig.writeEntry("font_underlined", buttonUnder->isChecked());
1945
1946     titleConfig.writeEntry("rect_foreground_color", rectFColor->color());
1947     titleConfig.writeEntry("rect_foreground_alpha", rectFAlpha->value());
1948     titleConfig.writeEntry("rect_background_color", rectBColor->color());
1949     titleConfig.writeEntry("rect_background_alpha", rectBAlpha->value());
1950     titleConfig.writeEntry("rect_line_width", rectLineWidth->value());
1951
1952     titleConfig.writeEntry("background_color", backgroundColor->color());
1953     titleConfig.writeEntry("background_alpha", backgroundAlpha->value());
1954
1955     //! \todo Not sure if I should sync - it is probably safe to do it
1956     config->sync();
1957
1958 }
1959
1960 void TitleWidget::readChoices()
1961 {
1962     // Get a pointer to a shared configuration instance, then get the TitleWidget group.
1963     KSharedConfigPtr config = KGlobal::config();
1964     KConfigGroup titleConfig(config, "TitleWidget");
1965     // read the entries
1966     font_family->setCurrentFont(titleConfig.readEntry("font_family", font_family->currentFont()));
1967     font_size->setValue(titleConfig.readEntry("font_pixel_size", font_size->value()));
1968     m_scene->slotUpdateFontSize(font_size->value());
1969     fontColorButton->setColor(titleConfig.readEntry("font_color", fontColorButton->color()));
1970     textAlpha->setValue(titleConfig.readEntry("font_alpha", textAlpha->value()));
1971
1972     textOutlineColor->setColor(titleConfig.readEntry("font_outline_color", textOutlineColor->color()));
1973     textOutlineAlpha->setValue(titleConfig.readEntry("font_outline_alpha", textOutlineAlpha->value()));
1974     textOutline->setValue(titleConfig.readEntry("font_outline", textOutline->value()));
1975
1976     int weight;
1977     if(titleConfig.readEntry("font_bold", false)) weight = QFont::Bold;
1978     else weight = titleConfig.readEntry("font_weight", font_weight_box->itemData(font_weight_box->currentIndex()).toInt());
1979     setFontBoxWeight(weight);
1980     buttonItalic->setChecked(titleConfig.readEntry("font_italic", buttonItalic->isChecked()));
1981     buttonUnder->setChecked(titleConfig.readEntry("font_underlined", buttonUnder->isChecked()));
1982
1983     rectFColor->setColor(titleConfig.readEntry("rect_foreground_color", rectFColor->color()));
1984     rectFAlpha->setValue(titleConfig.readEntry("rect_foreground_alpha", rectFAlpha->value()));
1985     rectBColor->setColor(titleConfig.readEntry("rect_background_color", rectBColor->color()));
1986     rectBAlpha->setValue(titleConfig.readEntry("rect_background_alpha", rectBAlpha->value()));
1987     rectLineWidth->setValue(titleConfig.readEntry("rect_line_width", rectLineWidth->value()));
1988
1989     backgroundColor->setColor(titleConfig.readEntry("background_color", backgroundColor->color()));
1990     backgroundAlpha->setValue(titleConfig.readEntry("background_alpha", backgroundAlpha->value()));
1991 }
1992
1993 void TitleWidget::adjustFrameSize()
1994 {
1995     m_frameWidth = m_titledocument.frameWidth();
1996     m_frameHeight = m_titledocument.frameHeight();
1997     m_frameBorder->setRect(0, 0, m_frameWidth, m_frameHeight);
1998     displayBackgroundFrame();
1999 }
2000
2001 void TitleWidget::slotAnimStart(bool anim)
2002 {
2003     if(anim && anim_end->isChecked()) {
2004         anim_end->setChecked(false);
2005         m_endViewport->setZValue(-1000);
2006         m_endViewport->setBrush(QBrush());
2007     }
2008     slotSelectTool();
2009     QList<QGraphicsItem *> list = m_scene->items();
2010     for(int i = 0; i < list.count(); i++) {
2011         if(list.at(i)->zValue() > -1000) {
2012             list.at(i)->setFlag(QGraphicsItem::ItemIsMovable, !anim);
2013             list.at(i)->setFlag(QGraphicsItem::ItemIsSelectable, !anim);
2014         }
2015     }
2016     align_box->setEnabled(anim);
2017     itemzoom->setEnabled(!anim);
2018     itemrotatex->setEnabled(!anim);
2019     itemrotatey->setEnabled(!anim);
2020     itemrotatez->setEnabled(!anim);
2021     frame_toolbar->setEnabled(!anim);
2022     toolbar_stack->setEnabled(!anim);
2023     if(anim) {
2024         keep_aspect->setChecked(!m_startViewport->data(0).isNull());
2025         m_startViewport->setZValue(1100);
2026         QColor col = m_startViewport->pen().color();
2027         col.setAlpha(100);
2028         m_startViewport->setBrush(col);
2029         m_startViewport->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
2030         m_startViewport->setSelected(true);
2031         selectionChanged();
2032         slotSelectTool();
2033         if(m_startViewport->childItems().isEmpty()) addAnimInfoText();
2034     } else {
2035         m_startViewport->setZValue(-1000);
2036         m_startViewport->setBrush(QBrush());
2037         m_startViewport->setFlags(0);
2038         if(!anim_end->isChecked()) deleteAnimInfoText();
2039     }
2040
2041 }
2042
2043 void TitleWidget::slotAnimEnd(bool anim)
2044 {
2045     if(anim && anim_start->isChecked()) {
2046         anim_start->setChecked(false);
2047         m_startViewport->setZValue(-1000);
2048         m_startViewport->setBrush(QBrush());
2049     }
2050     slotSelectTool();
2051     QList<QGraphicsItem *> list = m_scene->items();
2052     for(int i = 0; i < list.count(); i++) {
2053         if(list.at(i)->zValue() > -1000) {
2054             list.at(i)->setFlag(QGraphicsItem::ItemIsMovable, !anim);
2055             list.at(i)->setFlag(QGraphicsItem::ItemIsSelectable, !anim);
2056         }
2057     }
2058     align_box->setEnabled(anim);
2059     itemzoom->setEnabled(!anim);
2060     itemrotatex->setEnabled(!anim);
2061     itemrotatey->setEnabled(!anim);
2062     itemrotatez->setEnabled(!anim);
2063     frame_toolbar->setEnabled(!anim);
2064     toolbar_stack->setEnabled(!anim);
2065     if(anim) {
2066         keep_aspect->setChecked(!m_endViewport->data(0).isNull());
2067         m_endViewport->setZValue(1100);
2068         QColor col = m_endViewport->pen().color();
2069         col.setAlpha(100);
2070         m_endViewport->setBrush(col);
2071         m_endViewport->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
2072         m_endViewport->setSelected(true);
2073         selectionChanged();
2074         slotSelectTool();
2075         if(m_endViewport->childItems().isEmpty()) addAnimInfoText();
2076     } else {
2077         m_endViewport->setZValue(-1000);
2078         m_endViewport->setBrush(QBrush());
2079         m_endViewport->setFlags(0);
2080         if(!anim_start->isChecked()) deleteAnimInfoText();
2081     }
2082 }
2083
2084 void TitleWidget::addAnimInfoText()
2085 {
2086     // add text to anim viewport
2087     QGraphicsTextItem *t = new QGraphicsTextItem(i18n("Start"), m_startViewport);
2088     QGraphicsTextItem *t2 = new QGraphicsTextItem(i18n("End"), m_endViewport);
2089     QFont font = t->font();
2090     font.setPixelSize(m_startViewport->rect().width() / 10);
2091     QColor col = m_startViewport->pen().color();
2092     col.setAlpha(255);
2093     t->setDefaultTextColor(col);
2094     t->setFont(font);
2095     font.setPixelSize(m_endViewport->rect().width() / 10);
2096     col = m_endViewport->pen().color();
2097     col.setAlpha(255);
2098     t2->setDefaultTextColor(col);
2099     t2->setFont(font);
2100 }
2101
2102 void TitleWidget::updateInfoText()
2103 {
2104     // update info text font
2105     if(!m_startViewport->childItems().isEmpty()) {
2106         QGraphicsTextItem *item = static_cast <QGraphicsTextItem *>(m_startViewport->childItems().at(0));
2107         if(item) {
2108             QFont font = item->font();
2109             font.setPixelSize(m_startViewport->rect().width() / 10);
2110             item->setFont(font);
2111         }
2112     }
2113     if(!m_endViewport->childItems().isEmpty()) {
2114         QGraphicsTextItem *item = static_cast <QGraphicsTextItem *>(m_endViewport->childItems().at(0));
2115         if(item) {
2116             QFont font = item->font();
2117             font.setPixelSize(m_endViewport->rect().width() / 10);
2118             item->setFont(font);
2119         }
2120     }
2121 }
2122
2123 void TitleWidget::deleteAnimInfoText()
2124 {
2125     // end animation editing, remove info text
2126     while(!m_startViewport->childItems().isEmpty()) {
2127         QGraphicsItem *item = m_startViewport->childItems().at(0);
2128         m_scene->removeItem(item);
2129         delete item;
2130     }
2131     while(!m_endViewport->childItems().isEmpty()) {
2132         QGraphicsItem *item = m_endViewport->childItems().at(0);
2133         m_scene->removeItem(item);
2134         delete item;
2135     }
2136 }
2137
2138 void TitleWidget::slotKeepAspect(bool keep)
2139 {
2140     if(m_endViewport->zValue() == 1100) {
2141         m_endViewport->setData(0, keep == true ? m_frameWidth : QVariant());
2142         m_endViewport->setData(1, keep == true ? m_frameHeight : QVariant());
2143     } else {
2144         m_startViewport->setData(0, keep == true ? m_frameWidth : QVariant());
2145         m_startViewport->setData(1, keep == true ? m_frameHeight : QVariant());
2146     }
2147 }
2148
2149 void TitleWidget::slotResize50()
2150 {
2151     if(m_endViewport->zValue() == 1100) {
2152         m_endViewport->setRect(0, 0, m_frameWidth / 2, m_frameHeight / 2);
2153     } else m_startViewport->setRect(0, 0, m_frameWidth / 2, m_frameHeight / 2);
2154 }
2155
2156 void TitleWidget::slotResize100()
2157 {
2158     if(m_endViewport->zValue() == 1100) {
2159         m_endViewport->setRect(0, 0, m_frameWidth, m_frameHeight);
2160     } else m_startViewport->setRect(0, 0, m_frameWidth, m_frameHeight);
2161 }
2162
2163 void TitleWidget::slotResize200()
2164 {
2165     if(m_endViewport->zValue() == 1100) {
2166         m_endViewport->setRect(0, 0, m_frameWidth * 2, m_frameHeight * 2);
2167     } else m_startViewport->setRect(0, 0, m_frameWidth * 2, m_frameHeight * 2);
2168 }
2169
2170 void TitleWidget::slotAddEffect(int ix)
2171 {
2172     QList<QGraphicsItem *> list = graphicsView->scene()->selectedItems();
2173     int effect = effect_list->itemData(ix).toInt();
2174
2175     if(list.size() == 1) {
2176         if(effect == NOEFFECT)
2177             effect_stack->setHidden(true);
2178         else {
2179             effect_stack->setCurrentIndex(effect - 1);
2180             effect_stack->setHidden(false);
2181         }
2182     } else // Hide the effects stack when more than one element is selected.
2183         effect_stack->setHidden(true);
2184
2185     foreach(QGraphicsItem * item, list) {
2186         switch(effect) {
2187         case NOEFFECT:
2188             item->setData(100, QVariant());
2189 #if QT_VERSION >= 0x040600
2190             item->setGraphicsEffect(0);
2191 #endif
2192             break;
2193         case TYPEWRITEREFFECT:
2194             /*
2195              * Allow the user to set the typewriter effect to more than one
2196              * element, but do not add it to non-text elements.
2197              */
2198             if(item->type() == TEXTITEM) {
2199                 QStringList effdata = QStringList() << "typewriter" << QString::number(typewriter_delay->value()) + ";" + QString::number(typewriter_start->value());
2200                 item->setData(100, effdata);
2201             }
2202             break;
2203 #if QT_VERSION >= 0x040600
2204             // Do not remove the non-QGraphicsEffects.
2205         case BLUREFFECT:
2206             item->setGraphicsEffect(new QGraphicsBlurEffect());
2207             break;
2208         case SHADOWEFFECT:
2209             item->setGraphicsEffect(new QGraphicsDropShadowEffect());
2210             break;
2211 #endif
2212         }
2213     }
2214 }
2215
2216 void TitleWidget::slotFontText(const QString& s)
2217 {
2218     const QFont f(s);
2219     if(f.exactMatch()) {
2220         // Font really exists (could also just be a «d» if the user
2221         // starts typing «dejavu» for example).
2222         font_family->setCurrentFont(f);
2223     }
2224     // Note: Typing dejavu serif does not recognize the font (takes sans)
2225     // in older Qt versions. Case must match there (except for first letter)
2226 }
2227
2228 void TitleWidget::slotEditTypewriter(int /*ix*/)
2229 {
2230     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
2231     if(l.size() == 1) {
2232         QStringList effdata = QStringList() << "typewriter" << QString::number(typewriter_delay->value()) + ";" + QString::number(typewriter_start->value());
2233         l[0]->setData(100, effdata);
2234     }
2235 }
2236
2237 void TitleWidget::slotEditBlur(int ix)
2238 {
2239 #if QT_VERSION < 0x040600
2240     return;
2241 #else
2242     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
2243     if(l.size() == 1) {
2244         QGraphicsEffect *eff = l[0]->graphicsEffect();
2245         QGraphicsBlurEffect *blur = static_cast <QGraphicsBlurEffect *>(eff);
2246         if(blur) blur->setBlurRadius(ix);
2247     }
2248 #endif
2249 }
2250
2251 void TitleWidget::slotEditShadow()
2252 {
2253 #if QT_VERSION < 0x040600
2254     return;
2255 #else
2256     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
2257     if(l.size() == 1) {
2258         QGraphicsEffect *eff = l[0]->graphicsEffect();
2259         QGraphicsDropShadowEffect *shadow = static_cast <QGraphicsDropShadowEffect *>(eff);
2260         if(shadow) {
2261             shadow->setBlurRadius(shadow_radius->value());
2262             shadow->setOffset(shadow_x->value(), shadow_y->value());
2263         }
2264     }
2265 #endif
2266 }
2267
2268 qreal TitleWidget::zIndexBounds(bool maxBound, bool intersectingOnly)
2269 {
2270     qreal bound = maxBound ? -99 : 99;
2271     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
2272     if(l.size() > 0) {
2273         QList<QGraphicsItem*> lItems;
2274         // Get items (all or intersecting only)
2275         if(intersectingOnly) {
2276             lItems = graphicsView->scene()->items(l[0]->sceneBoundingRect(), Qt::IntersectsItemShape);
2277         } else {
2278             lItems = graphicsView->scene()->items();
2279         }
2280         if(lItems.size() > 0) {
2281             int n = lItems.size();
2282             qreal z;
2283             if(maxBound) {
2284                 for(int i = 0; i < n; i++) {
2285                     z = lItems[i]->zValue();
2286                     if(z > bound && !lItems[i]->isSelected()) {
2287                         bound = z;
2288                     }
2289                 }
2290             } else {
2291                 // Get minimum z index.
2292                 for(int i = 0; i < n; i++) {
2293                     z = lItems[i]->zValue();
2294                     if(z < bound && !lItems[i]->isSelected() && z > -999) {
2295                         // There are items at the very bottom (background e.g.) with z-index < -1000.
2296                         bound = z;
2297                     }
2298                 }
2299             }
2300         }
2301     }
2302     return bound;
2303 }
2304
2305 void TitleWidget::slotZIndexUp()
2306 {
2307     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
2308     if(l.size() >= 1) {
2309         qreal currentZ = l[0]->zValue();
2310         qreal max = zIndexBounds(true, true);
2311         if(currentZ <= max) {
2312             l[0]->setZValue(currentZ + 1);
2313             updateDimension(l[0]);
2314         }
2315     }
2316 }
2317
2318 void TitleWidget::slotZIndexTop()
2319 {
2320     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
2321     if(l.size() >= 1) {
2322         qreal currentZ = l[0]->zValue();
2323         qreal max = zIndexBounds(true, false);
2324         if(currentZ <= max) {
2325             l[0]->setZValue(max + 1);
2326             updateDimension(l[0]);
2327         }
2328     }
2329 }
2330
2331 void TitleWidget::slotZIndexDown()
2332 {
2333     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
2334     if(l.size() >= 1) {
2335         qreal currentZ = l[0]->zValue();
2336         qreal min = zIndexBounds(false, true);
2337         if(currentZ >= min) {
2338             l[0]->setZValue(currentZ - 1);
2339             updateDimension(l[0]);
2340         }
2341     }
2342 }
2343
2344 void TitleWidget::slotZIndexBottom()
2345 {
2346     QList<QGraphicsItem*> l = graphicsView->scene()->selectedItems();
2347     if(l.size() >= 1) {
2348         qreal currentZ = l[0]->zValue();
2349         qreal min = zIndexBounds(false, false);
2350         if(currentZ >= min) {
2351             l[0]->setZValue(min - 1);
2352             updateDimension(l[0]);
2353         }
2354     }
2355 }