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