titlewidget.cpp 129 KB
Newer Older
1
/***************************************************************************
2
                          titlewidget.cpp  -  description
3
4
5
6
7
8
9
10
11
12
13
14
15
16
                             -------------------
    begin                : Feb 28 2008
    copyright            : (C) 2008 by Marco Gittler
    email                : g.marco@freenet.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
17
18
19
20
21
/***************************************************************************
 *                                                                         *
 *   Modifications by Rafał Lalik to implement Patterns mechanism          *
 *                                                                         *
 ***************************************************************************/
22

23
#include "titlewidget.h"
24
#include "core.h"
25
#include "bin/bin.h"
Nicolas Carion's avatar
Nicolas Carion committed
26
#include "doc/kthumb.h"
27
#include "gradientwidget.h"
28
#include "kdenlivesettings.h"
29
#include "monitor/monitor.h"
30
31
#include "titler/patternsmodel.h"
#include "profiles/profilemodel.hpp"
32

Simon Eugster's avatar
Simon Eugster committed
33
34
#include <cmath>

35
#include <KMessageBox>
36
#include <KMessageWidget>
37
#include <KRecentDirs>
Nicolas Carion's avatar
Nicolas Carion committed
38
#include <klocalizedstring.h>
39
#include <kns3/downloaddialog.h>
40

Laurent Montel's avatar
Laurent Montel committed
41
#include "kdenlive_debug.h"
42
#include <QButtonGroup>
Nicolas Carion's avatar
Nicolas Carion committed
43
#include <QCryptographicHash>
44
#include <QDomDocument>
Nicolas Carion's avatar
Nicolas Carion committed
45
46
#include <QFileDialog>
#include <QFontDatabase>
47
48
49
#include <QGraphicsBlurEffect>
#include <QGraphicsDropShadowEffect>
#include <QGraphicsEffect>
Marco Gittler's avatar
Marco Gittler committed
50
#include <QGraphicsItem>
51
#include <QGraphicsSvgItem>
Nicolas Carion's avatar
Nicolas Carion committed
52
53
#include <QImageReader>
#include <QKeyEvent>
54
#include <QSignalMapper>
55
#include <QSpinBox>
56
57
#include <QTextBlockFormat>
#include <QTextCursor>
Nicolas Carion's avatar
Nicolas Carion committed
58
59
#include <QTimer>
#include <QToolBar>
60
#include <QMenu>
61

62
#include <QStandardPaths>
Nicolas Carion's avatar
Nicolas Carion committed
63
#include <iostream>
64
#include <mlt++/MltProfile.h>
Nicolas Carion's avatar
Nicolas Carion committed
65
#include <utility>
66

67
68
static QList<TitleTemplate> titletemplates;

69
// What exactly is this variable good for?
Nicolas Carion's avatar
Nicolas Carion committed
70
int settingUp = 0;
71

72
73
74
75
const int IMAGEITEM = 7;
const int RECTITEM = 3;
const int TEXTITEM = 8;

Vincent Pinon's avatar
Vincent Pinon committed
76
/*
77
78
79
80
const int NOEFFECT = 0;
const int BLUREFFECT = 1;
const int SHADOWEFFECT = 2;
const int TYPEWRITEREFFECT = 3;
Vincent Pinon's avatar
Vincent Pinon committed
81
*/
82

83
84
85
86
void TitleWidget::refreshTemplateBoxContents()
{
    templateBox->clear();
    templateBox->addItem(QString());
Vincent Pinon's avatar
Vincent Pinon committed
87
    for (const TitleTemplate &t : qAsConst(titletemplates)) {
88
89
90
91
        templateBox->addItem(t.icon, t.name, t.file);
    }
}

Nicolas Carion's avatar
Nicolas Carion committed
92
TitleWidget::TitleWidget(const QUrl &url, const Timecode &tc, QString projectTitlePath, Monitor *monitor, QWidget *parent)
93
94
95
96
97
98
    : QDialog(parent)
    , Ui::TitleWidget_UI()
    , m_startViewport(nullptr)
    , m_endViewport(nullptr)
    , m_count(0)
    , m_unicodeDialog(new UnicodeDialog(UnicodeDialog::InputHex))
99
    , m_missingMessage(nullptr)
Nicolas Carion's avatar
Nicolas Carion committed
100
    , m_projectTitlePath(std::move(projectTitlePath))
101
    , m_tc(tc)
102
    , m_fps(pCore->getCurrentFps())
103
    , m_guides(QList<QGraphicsLineItem *>())
104
{
105
    setupUi(this);
106
    setMinimumSize(200, 200);
107
    setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
108
    frame_properties->setEnabled(false);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
109
    frame_properties->setFixedHeight(frame_toolbar->height());
110
111
    int size = style()->pixelMetric(QStyle::PM_SmallIconSize);
    QSize iconSize(size, size);
112

113
114
115
116
    rectBColor->setAlphaChannelEnabled(true);
    rectFColor->setAlphaChannelEnabled(true);
    fontColorButton->setAlphaChannelEnabled(true);
    textOutlineColor->setAlphaChannelEnabled(true);
117
    shadowColor->setAlphaChannelEnabled(true);
118

Nicolas Carion's avatar
Nicolas Carion committed
119
    auto *colorGroup = new QButtonGroup(this);
120
121
122
    colorGroup->addButton(gradient_color);
    colorGroup->addButton(plain_color);

Nicolas Carion's avatar
Nicolas Carion committed
123
    auto *alignGroup = new QButtonGroup(this);
124
125
126
127
    alignGroup->addButton(buttonAlignLeft);
    alignGroup->addButton(buttonAlignCenter);
    alignGroup->addButton(buttonAlignRight);

128
129
    textOutline->setMinimum(0);
    textOutline->setMaximum(200);
Nicolas Carion's avatar
Nicolas Carion committed
130
    // textOutline->setDecimals(0);
131
132
    textOutline->setValue(0);
    textOutline->setToolTip(i18n("Outline width"));
133
134
135

    backgroundAlpha->setMinimum(0);
    backgroundAlpha->setMaximum(255);
136
137
    bgAlphaSlider->setMinimum(0);
    bgAlphaSlider->setMaximum(255);
138
139
140
    backgroundAlpha->setValue(0);
    backgroundAlpha->setToolTip(i18n("Background color opacity"));

141
142
    itemrotatex->setMinimum(-360);
    itemrotatex->setMaximum(360);
Nicolas Carion's avatar
Nicolas Carion committed
143
    // itemrotatex->setDecimals(0);
144
145
146
147
148
    itemrotatex->setValue(0);
    itemrotatex->setToolTip(i18n("Rotation around the X axis"));

    itemrotatey->setMinimum(-360);
    itemrotatey->setMaximum(360);
Nicolas Carion's avatar
Nicolas Carion committed
149
    // itemrotatey->setDecimals(0);
150
151
152
153
154
    itemrotatey->setValue(0);
    itemrotatey->setToolTip(i18n("Rotation around the Y axis"));

    itemrotatez->setMinimum(-360);
    itemrotatez->setMaximum(360);
Nicolas Carion's avatar
Nicolas Carion committed
155
    // itemrotatez->setDecimals(0);
156
157
    itemrotatez->setValue(0);
    itemrotatez->setToolTip(i18n("Rotation around the Z axis"));
158
159

    rectLineWidth->setMinimum(0);
160
    rectLineWidth->setMaximum(500);
Nicolas Carion's avatar
Nicolas Carion committed
161
    // rectLineWidth->setDecimals(0);
162
163
164
    rectLineWidth->setValue(0);
    rectLineWidth->setToolTip(i18n("Border width"));

165
    itemzoom->setSuffix(i18n("%"));
166
    QSize profileSize = pCore->getCurrentFrameSize();
167
    m_frameWidth = (int)(profileSize.height() * pCore->getCurrentDar() + 0.5);
168
    m_frameHeight = profileSize.height();
169
    showToolbars(TITLE_SELECT);
170

171
172
    splitter->setStretchFactor(0, 20);

Nicolas Carion's avatar
Nicolas Carion committed
173
    // If project is drop frame, set the input mask as such.
174
    title_duration->setInputMask(m_tc.mask());
175
    title_duration->setText(m_tc.reformatSeparators(KdenliveSettings::title_duration()));
176

Laurent Montel's avatar
Laurent Montel committed
177
    connect(backgroundColor, &KColorButton::changed, this, &TitleWidget::slotChangeBackground);
178
    connect(backgroundAlpha, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotChangeBackground);
179

Laurent Montel's avatar
Laurent Montel committed
180
181
    connect(shadowBox, &QGroupBox::toggled, this, &TitleWidget::slotUpdateShadow);
    connect(shadowColor, &KColorButton::changed, this, &TitleWidget::slotUpdateShadow);
182
183
184
    connect(blur_radius, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateShadow);
    connect(shadowX, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateShadow);
    connect(shadowY, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateShadow);
185

186
187
188
189
190
191
192
193
194
    connect(typewriterBox, &QGroupBox::toggled, this, &TitleWidget::slotUpdateTW);
    connect(tw_sb_step, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateTW);
    connect(tw_sb_sigma, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateTW);
    connect(tw_sb_seed, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateTW);
    connect(tw_rd_char, &QRadioButton::toggled, this, &TitleWidget::slotUpdateTW);
    connect(tw_rd_word, &QRadioButton::toggled, this, &TitleWidget::slotUpdateTW);
    connect(tw_rd_line, &QRadioButton::toggled, this, &TitleWidget::slotUpdateTW);
    connect(tw_rd_custom, &QRadioButton::toggled, this, &TitleWidget::slotUpdateTW);
    tw_rd_custom->setEnabled(false);
195
    if (mlt_version_get_int() < 0x061900) {
196
197
198
199
200
201
202
203
204
205
        typewriterBox->setEnabled(false);

		auto *twinfo = new KMessageWidget(typewriterBox);
		twinfo->setText(i18n("Typewriter requires MLT-6.26.0 or newer."));
		twinfo->setMessageType(KMessageWidget::Warning);
		twinfo->setCloseButtonVisible(false);
		twinfo->setEnabled(true);
		gridLayout_12->addWidget(twinfo, 3, 0, 1, 4, 0);
    }

Laurent Montel's avatar
Laurent Montel committed
206
207
208
    connect(fontColorButton, &KColorButton::changed, this, &TitleWidget::slotUpdateText);
    connect(plain_color, &QAbstractButton::clicked, this, &TitleWidget::slotUpdateText);
    connect(gradient_color, &QAbstractButton::clicked, this, &TitleWidget::slotUpdateText);
209
210
    connect(gradients_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateText()));

Laurent Montel's avatar
Laurent Montel committed
211
212
    connect(textOutlineColor, &KColorButton::changed, this, &TitleWidget::slotUpdateText);
    connect(font_family, &QFontComboBox::currentFontChanged, this, &TitleWidget::slotUpdateText);
213
214
215
216
    connect(font_size, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateText);
    connect(letter_spacing, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateText);
    connect(line_spacing, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateText);
    connect(textOutline, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateText);
Simon Eugster's avatar
Titler:    
Simon Eugster committed
217
    connect(font_weight_box, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateText()));
218

Laurent Montel's avatar
Laurent Montel committed
219
220
221
222
    connect(rectFColor, &KColorButton::changed, this, &TitleWidget::rectChanged);
    connect(rectBColor, &KColorButton::changed, this, &TitleWidget::rectChanged);
    connect(plain_rect, &QAbstractButton::clicked, this, &TitleWidget::rectChanged);
    connect(gradient_rect, &QAbstractButton::clicked, this, &TitleWidget::rectChanged);
223
    connect(gradients_rect_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(rectChanged()));
224
    connect(rectLineWidth, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::rectChanged);
225

226
227
228
229
230
    connect(zValue, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::zIndexChanged);
    connect(itemzoom, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::itemScaled);
    connect(itemrotatex, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::itemRotateX);
    connect(itemrotatey, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::itemRotateY);
    connect(itemrotatez, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::itemRotateZ);
Laurent Montel's avatar
Laurent Montel committed
231
232
233
234
235
236
    connect(itemhcenter, &QAbstractButton::clicked, this, &TitleWidget::itemHCenter);
    connect(itemvcenter, &QAbstractButton::clicked, this, &TitleWidget::itemVCenter);
    connect(itemtop, &QAbstractButton::clicked, this, &TitleWidget::itemTop);
    connect(itembottom, &QAbstractButton::clicked, this, &TitleWidget::itemBottom);
    connect(itemleft, &QAbstractButton::clicked, this, &TitleWidget::itemLeft);
    connect(itemright, &QAbstractButton::clicked, this, &TitleWidget::itemRight);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
237

Laurent Montel's avatar
Laurent Montel committed
238
239
    connect(origin_x_left, &QAbstractButton::clicked, this, &TitleWidget::slotOriginXClicked);
    connect(origin_y_top, &QAbstractButton::clicked, this, &TitleWidget::slotOriginYClicked);
240

241
    connect(monitor, &Monitor::frameUpdated, this, &TitleWidget::slotGotBackground);
242
    connect(this, &TitleWidget::requestBackgroundFrame, monitor, &Monitor::slotGetCurrentImage);
Simon Eugster's avatar
Simon Eugster committed
243

244
    // Position and size
Vincent Pinon's avatar
Vincent Pinon committed
245
246
247
248
    connect(value_w, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [this](int){slotValueChanged(ValueWidth);});
    connect(value_h, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [this](int){slotValueChanged(ValueHeight);});
    connect(value_x, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [this](int){slotValueChanged(ValueX);});
    connect(value_y, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [this](int){slotValueChanged(ValueY);});
249

Laurent Montel's avatar
Laurent Montel committed
250
251
252
253
254
255
256
257
258
    connect(buttonFitZoom, &QAbstractButton::clicked, this, &TitleWidget::slotAdjustZoom);
    connect(buttonRealSize, &QAbstractButton::clicked, this, &TitleWidget::slotZoomOneToOne);
    connect(buttonItalic, &QAbstractButton::clicked, this, &TitleWidget::slotUpdateText);
    connect(buttonUnder, &QAbstractButton::clicked, this, &TitleWidget::slotUpdateText);
    connect(buttonAlignLeft, &QAbstractButton::clicked, this, &TitleWidget::slotUpdateText);
    connect(buttonAlignRight, &QAbstractButton::clicked, this, &TitleWidget::slotUpdateText);
    connect(buttonAlignCenter, &QAbstractButton::clicked, this, &TitleWidget::slotUpdateText);
    connect(edit_gradient, &QAbstractButton::clicked, this, &TitleWidget::slotEditGradient);
    connect(edit_rect_gradient, &QAbstractButton::clicked, this, &TitleWidget::slotEditGradient);
Vincent Pinon's avatar
Vincent Pinon committed
259
    connect(preserveAspectRatio, static_cast<void (QCheckBox::*)(int)>(&QCheckBox::stateChanged), this, [&] () {
260
261
        slotValueChanged(ValueWidth);
    });
262
263

    displayBg->setChecked(KdenliveSettings::titlerShowbg());
Vincent Pinon's avatar
Vincent Pinon committed
264
    connect(displayBg, static_cast<void (QCheckBox::*)(int)>(&QCheckBox::stateChanged), this, [&] (int state) {
265
266
267
        KdenliveSettings::setTitlerShowbg(state == Qt::Checked);
        displayBackgroundFrame();
    });
268

Laurent Montel's avatar
Laurent Montel committed
269
    connect(m_unicodeDialog, &UnicodeDialog::charSelected, this, &TitleWidget::slotInsertUnicodeString);
Simon Eugster's avatar
Simon Eugster committed
270

271
    // mbd
Laurent Montel's avatar
Laurent Montel committed
272
    connect(this, &QDialog::accepted, this, &TitleWidget::slotAccepted);
Mads Bondo Dydensborg's avatar
Mads Bondo Dydensborg committed
273

Simon Eugster's avatar
Titler:    
Simon Eugster committed
274
275
276
277
278
279
280
281
282
283
    font_weight_box->blockSignals(true);
    font_weight_box->addItem(i18nc("Font style", "Light"), QFont::Light);
    font_weight_box->addItem(i18nc("Font style", "Normal"), QFont::Normal);
    font_weight_box->addItem(i18nc("Font style", "Demi-Bold"), QFont::DemiBold);
    font_weight_box->addItem(i18nc("Font style", "Bold"), QFont::Bold);
    font_weight_box->addItem(i18nc("Font style", "Black"), QFont::Black);
    font_weight_box->setToolTip(i18n("Font weight"));
    font_weight_box->setCurrentIndex(1);
    font_weight_box->blockSignals(false);

284
285
286
287
288
289
290
    buttonFitZoom->setIconSize(iconSize);
    buttonRealSize->setIconSize(iconSize);
    buttonItalic->setIconSize(iconSize);
    buttonUnder->setIconSize(iconSize);
    buttonAlignCenter->setIconSize(iconSize);
    buttonAlignLeft->setIconSize(iconSize);
    buttonAlignRight->setIconSize(iconSize);
291
292
293
294
295
296
297
298
299
    buttonFitZoom->setIcon(QIcon::fromTheme(QStringLiteral("zoom-fit-best")));
    buttonRealSize->setIcon(QIcon::fromTheme(QStringLiteral("zoom-original")));
    buttonItalic->setIcon(QIcon::fromTheme(QStringLiteral("format-text-italic")));
    buttonUnder->setIcon(QIcon::fromTheme(QStringLiteral("format-text-underline")));
    buttonAlignCenter->setIcon(QIcon::fromTheme(QStringLiteral("format-justify-center")));
    buttonAlignLeft->setIcon(QIcon::fromTheme(QStringLiteral("format-justify-left")));
    buttonAlignRight->setIcon(QIcon::fromTheme(QStringLiteral("format-justify-right")));
    edit_gradient->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
    edit_rect_gradient->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
300

301
302
303
    buttonAlignRight->setToolTip(i18n("Align right"));
    buttonAlignLeft->setToolTip(i18n("Align left"));
    buttonAlignCenter->setToolTip(i18n("Align center"));
304
305
306
307
308
    if (qApp->isLeftToRight()) {
        buttonAlignRight->setChecked(true);
    } else {
        buttonAlignLeft->setChecked(true);
    }
309

310
    m_unicodeAction = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-insert-unicode")), QString(), this);
311
    m_unicodeAction->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_U);
312
    m_unicodeAction->setToolTip(getTooltipWithShortcut(i18n("Insert Unicode character"), m_unicodeAction));
Laurent Montel's avatar
Laurent Montel committed
313
    connect(m_unicodeAction, &QAction::triggered, this, &TitleWidget::slotInsertUnicode);
314
    buttonInsertUnicode->setDefaultAction(m_unicodeAction);
315

316
    m_zUp = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-up")), QString(), this);
Simon Eugster's avatar
Simon Eugster committed
317
318
    m_zUp->setShortcut(Qt::Key_PageUp);
    m_zUp->setToolTip(i18n("Raise object"));
Laurent Montel's avatar
Laurent Montel committed
319
    connect(m_zUp, &QAction::triggered, this, &TitleWidget::slotZIndexUp);
Simon Eugster's avatar
Simon Eugster committed
320
    zUp->setDefaultAction(m_zUp);
321

322
    m_zDown = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-down")), QString(), this);
Simon Eugster's avatar
Simon Eugster committed
323
324
    m_zDown->setShortcut(Qt::Key_PageDown);
    m_zDown->setToolTip(i18n("Lower object"));
Laurent Montel's avatar
Laurent Montel committed
325
    connect(m_zDown, &QAction::triggered, this, &TitleWidget::slotZIndexDown);
Simon Eugster's avatar
Simon Eugster committed
326
    zDown->setDefaultAction(m_zDown);
327

328
    m_zTop = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-top")), QString(), this);
Alberto Villa's avatar
Alberto Villa committed
329
    // TODO mbt 1414: Shortcut should change z index only if
330
    // cursor is NOT in a text field ...
Nicolas Carion's avatar
Nicolas Carion committed
331
    // m_zTop->setShortcut(Qt::Key_Home);
Simon Eugster's avatar
Simon Eugster committed
332
    m_zTop->setToolTip(i18n("Raise object to top"));
Laurent Montel's avatar
Laurent Montel committed
333
    connect(m_zTop, &QAction::triggered, this, &TitleWidget::slotZIndexTop);
Simon Eugster's avatar
Simon Eugster committed
334
    zTop->setDefaultAction(m_zTop);
335

336
    m_zBottom = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-bottom")), QString(), this);
337
    // TODO mbt 1414
Nicolas Carion's avatar
Nicolas Carion committed
338
    // m_zBottom->setShortcut(Qt::Key_End);
Simon Eugster's avatar
Simon Eugster committed
339
    m_zBottom->setToolTip(i18n("Lower object to bottom"));
Laurent Montel's avatar
Laurent Montel committed
340
    connect(m_zBottom, &QAction::triggered, this, &TitleWidget::slotZIndexBottom);
Simon Eugster's avatar
Simon Eugster committed
341
    zBottom->setDefaultAction(m_zBottom);
342

343
    m_selectAll = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-all")), QString(), this);
344
    m_selectAll->setShortcut(Qt::CTRL + Qt::Key_A);
Laurent Montel's avatar
Laurent Montel committed
345
    connect(m_selectAll, &QAction::triggered, this, &TitleWidget::slotSelectAll);
346
    buttonSelectAll->setDefaultAction(m_selectAll);
347

348
    m_selectText = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-texts")), QString(), this);
349
    m_selectText->setShortcut(Qt::CTRL + Qt::Key_T);
Laurent Montel's avatar
Laurent Montel committed
350
    connect(m_selectText, &QAction::triggered, this, &TitleWidget::slotSelectText);
351
    buttonSelectText->setDefaultAction(m_selectText);
352
353
    buttonSelectText->setEnabled(false);

354
    m_selectRects = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-rects")), QString(), this);
355
    m_selectRects->setShortcut(Qt::CTRL + Qt::Key_R);
Laurent Montel's avatar
Laurent Montel committed
356
    connect(m_selectRects, &QAction::triggered, this, &TitleWidget::slotSelectRects);
357
    buttonSelectRects->setDefaultAction(m_selectRects);
358
359
    buttonSelectRects->setEnabled(false);

360
    m_selectImages = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-images")), QString(), this);
361
    m_selectImages->setShortcut(Qt::CTRL + Qt::Key_I);
Laurent Montel's avatar
Laurent Montel committed
362
    connect(m_selectImages, &QAction::triggered, this, &TitleWidget::slotSelectImages);
363
    buttonSelectImages->setDefaultAction(m_selectImages);
364
365
    buttonSelectImages->setEnabled(false);

366
    m_unselectAll = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-unselect-all")), QString(), this);
367
    m_unselectAll->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_A);
Laurent Montel's avatar
Laurent Montel committed
368
    connect(m_unselectAll, &QAction::triggered, this, &TitleWidget::slotSelectNone);
369
    buttonUnselectAll->setDefaultAction(m_unselectAll);
370
    buttonUnselectAll->setEnabled(false);
371

372
373
374
    zDown->setIconSize(iconSize);
    zTop->setIconSize(iconSize);
    zBottom->setIconSize(iconSize);
375
376
377
    zDown->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-down")));
    zTop->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-top")));
    zBottom->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-bottom")));
Laurent Montel's avatar
Laurent Montel committed
378
379
380
    connect(zDown, &QAbstractButton::clicked, this, &TitleWidget::slotZIndexDown);
    connect(zTop, &QAbstractButton::clicked, this, &TitleWidget::slotZIndexTop);
    connect(zBottom, &QAbstractButton::clicked, this, &TitleWidget::slotZIndexBottom);
381

Alberto Villa's avatar
Alberto Villa committed
382
383
384
385
386
387
388
    origin_x_left->setToolTip(i18n("Invert x axis and change 0 point"));
    origin_y_top->setToolTip(i18n("Invert y axis and change 0 point"));
    rectBColor->setToolTip(i18n("Select fill color"));
    rectFColor->setToolTip(i18n("Select border color"));
    zoom_slider->setToolTip(i18n("Zoom"));
    buttonRealSize->setToolTip(i18n("Original size (1:1)"));
    buttonFitZoom->setToolTip(i18n("Fit zoom"));
389
    backgroundColor->setToolTip(i18n("Select background color"));
Simon Eugster's avatar
Simon Eugster committed
390
    backgroundAlpha->setToolTip(i18n("Background opacity"));
391
392
393
394
395
    buttonSelectAll->setToolTip(getTooltipWithShortcut(i18n("Select all"), m_selectAll));
    buttonSelectText->setToolTip(getTooltipWithShortcut(i18n("Select text items in current selection"), m_selectText));
    buttonSelectRects->setToolTip(getTooltipWithShortcut(i18n("Select rect items in current selection"), m_selectRects));
    buttonSelectImages->setToolTip(getTooltipWithShortcut(i18n("Select image items in current selection"), m_selectImages));
    buttonUnselectAll->setToolTip(getTooltipWithShortcut(i18n("Unselect all"), m_unselectAll));
396

397
398
399
400
401
402
    itemhcenter->setIconSize(iconSize);
    itemvcenter->setIconSize(iconSize);
    itemtop->setIconSize(iconSize);
    itembottom->setIconSize(iconSize);
    itemright->setIconSize(iconSize);
    itemleft->setIconSize(iconSize);
403

404
    itemhcenter->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-align-hor")));
405
    itemhcenter->setToolTip(i18n("Align item horizontally"));
406
    itemvcenter->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-align-vert")));
407
    itemvcenter->setToolTip(i18n("Align item vertically"));
408
    itemtop->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-align-top")));
409
    itemtop->setToolTip(i18n("Align item to top"));
410
    itembottom->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-align-bottom")));
411
    itembottom->setToolTip(i18n("Align item to bottom"));
412
    itemright->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-align-right")));
413
    itemright->setToolTip(i18n("Align item to right"));
414
    itemleft->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-align-left")));
415
    itemleft->setToolTip(i18n("Align item to left"));
416

Nicolas Carion's avatar
Nicolas Carion committed
417
    auto *layout = new QHBoxLayout;
418
    frame_toolbar->setLayout(layout);
419
    layout->setContentsMargins(0, 0, 0, 0);
420
    QToolBar *m_toolbar = new QToolBar(QStringLiteral("titleToolBar"), this);
421
    m_toolbar->setIconSize(iconSize);
422

423
    m_buttonCursor = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("transform-move")), i18n("Selection Tool"));
424
425
    m_buttonCursor->setCheckable(true);
    m_buttonCursor->setShortcut(Qt::ALT + Qt::Key_S);
Laurent Montel's avatar
Laurent Montel committed
426
    m_buttonCursor->setToolTip(i18n("Selection Tool") + QLatin1Char(' ') + m_buttonCursor->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
427
    connect(m_buttonCursor, &QAction::triggered, this, &TitleWidget::slotSelectTool);
428

429
    m_buttonText = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("insert-text")), i18n("Add Text"));
430
    m_buttonText->setCheckable(true);
Alberto Villa's avatar
Alberto Villa committed
431
    m_buttonText->setShortcut(Qt::ALT + Qt::Key_T);
Laurent Montel's avatar
Laurent Montel committed
432
    m_buttonText->setToolTip(i18n("Add Text") + QLatin1Char(' ') + m_buttonText->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
433
    connect(m_buttonText, &QAction::triggered, this, &TitleWidget::slotTextTool);
434

435
    m_buttonRect = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("kdenlive-insert-rect")), i18n("Add Rectangle"));
436
437
    m_buttonRect->setCheckable(true);
    m_buttonRect->setShortcut(Qt::ALT + Qt::Key_R);
Laurent Montel's avatar
Laurent Montel committed
438
    m_buttonRect->setToolTip(i18n("Add Rectangle") + QLatin1Char(' ') + m_buttonRect->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
439
    connect(m_buttonRect, &QAction::triggered, this, &TitleWidget::slotRectTool);
440

441
    m_buttonImage = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("insert-image")), i18n("Add Image"));
442
    m_buttonImage->setCheckable(false);
Alberto Villa's avatar
Alberto Villa committed
443
    m_buttonImage->setShortcut(Qt::ALT + Qt::Key_I);
Laurent Montel's avatar
Laurent Montel committed
444
    m_buttonImage->setToolTip(i18n("Add Image") + QLatin1Char(' ') + m_buttonImage->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
445
    connect(m_buttonImage, &QAction::triggered, this, &TitleWidget::slotImageTool);
446

Simon Eugster's avatar
Simon Eugster committed
447
    m_toolbar->addSeparator();
448

449
    m_buttonLoad = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("document-open")), i18n("Open Document"));
450
    m_buttonLoad->setCheckable(false);
Alberto Villa's avatar
Alberto Villa committed
451
    m_buttonLoad->setShortcut(Qt::CTRL + Qt::Key_O);
Laurent Montel's avatar
Laurent Montel committed
452
    m_buttonLoad->setToolTip(i18n("Open Document") + QLatin1Char(' ') + m_buttonLoad->shortcut().toString());
453
454
    connect(m_buttonLoad, SIGNAL(triggered()), this, SLOT(loadTitle()));

455
    m_buttonSave = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("document-save-as")), i18n("Save As"));
456
    m_buttonSave->setCheckable(false);
Alberto Villa's avatar
Alberto Villa committed
457
    m_buttonSave->setShortcut(Qt::CTRL + Qt::Key_S);
Laurent Montel's avatar
Laurent Montel committed
458
    m_buttonSave->setToolTip(i18n("Save As") + QLatin1Char(' ') + m_buttonSave->shortcut().toString());
459
460
    connect(m_buttonSave, SIGNAL(triggered()), this, SLOT(saveTitle()));

461
462
463
464
465
466
    m_buttonDownload = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("edit-download")), i18n("Download New Title Templates..."));
    m_buttonDownload->setCheckable(false);
    m_buttonDownload->setShortcut(Qt::ALT + Qt::Key_D);
    m_buttonDownload->setToolTip(i18n("Download New Title Templates...") + QLatin1Char(' ') + m_buttonDownload->shortcut().toString());
    connect(m_buttonDownload, &QAction::triggered, this, &TitleWidget::downloadTitleTemplates);

467
    layout->addWidget(m_toolbar);
468

469
    // initialize graphic scene
470
    m_scene = new GraphicsSceneRectMove(this);
471
    graphicsView->setScene(m_scene);
472
    graphicsView->setMouseTracking(true);
473
    graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
474
475
    graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
    graphicsView->setRubberBandSelectionMode(Qt::ContainsItemBoundingRect);
476
    m_titledocument.setScene(m_scene, m_frameWidth, m_frameHeight);
Laurent Montel's avatar
Laurent Montel committed
477
    connect(m_scene, &QGraphicsScene::changed, this, &TitleWidget::slotChanged);
478
    connect(font_size, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), m_scene, &GraphicsSceneRectMove::slotUpdateFontSize);
Laurent Montel's avatar
Laurent Montel committed
479
    connect(use_grid, &QAbstractButton::toggled, m_scene, &GraphicsSceneRectMove::slotUseGrid);
480

481
482
    // Video frame rect
    QPen framepen;
483
484
485
    framepen.setColor(Qt::red);
    m_frameBorder = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
    m_frameBorder->setPen(framepen);
486
    m_frameBorder->setZValue(1000);
487
    m_frameBorder->setBrush(Qt::transparent);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
488
    m_frameBorder->setData(-1, -1);
489
    graphicsView->scene()->addItem(m_frameBorder);
490

491
    // Guides
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
492
493
    connect(show_guides, &QCheckBox::stateChanged, this, &TitleWidget::showGuides);
    show_guides->setChecked(KdenliveSettings::titlerShowGuides());
494
495
    hguides->setValue(KdenliveSettings::titlerHGuides());
    vguides->setValue(KdenliveSettings::titlerVGuides());
496
497
    guideColor->setColor(KdenliveSettings::titleGuideColor());
    connect(guideColor, &KColorButton::changed, this, &TitleWidget::guideColorChanged);
498
499
500
    connect(hguides, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::updateGuides);
    connect(vguides, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::updateGuides);
    updateGuides(0);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
501

502
    // semi transparent safe zones
503
    framepen.setColor(QColor(255, 0, 0, 100));
504
505
506
    QGraphicsRectItem *safe1 = new QGraphicsRectItem(QRectF(m_frameWidth * 0.05, m_frameHeight * 0.05, m_frameWidth * 0.9, m_frameHeight * 0.9), m_frameBorder);
    safe1->setBrush(Qt::transparent);
    safe1->setPen(framepen);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
507
    safe1->setData(-1, -1);
508
509
510
    QGraphicsRectItem *safe2 = new QGraphicsRectItem(QRectF(m_frameWidth * 0.1, m_frameHeight * 0.1, m_frameWidth * 0.8, m_frameHeight * 0.8), m_frameBorder);
    safe2->setBrush(Qt::transparent);
    safe2->setPen(framepen);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
511
    safe2->setData(-1, -1);
512
513
514
515
516
517

    m_frameBackground = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
    m_frameBackground->setZValue(-1100);
    m_frameBackground->setBrush(Qt::transparent);
    graphicsView->scene()->addItem(m_frameBackground);

518
519
520
521
522
523
524
525
    m_frameImage = new QGraphicsPixmapItem();
    QTransform qtrans;
    qtrans.scale(2.0, 2.0);
    m_frameImage->setTransform(qtrans);
    m_frameImage->setZValue(-1200);
    displayBackgroundFrame();
    graphicsView->scene()->addItem(m_frameImage);

526
    bgBox->setCurrentIndex(KdenliveSettings::titlerbg());
Vincent Pinon's avatar
Vincent Pinon committed
527
    connect(bgBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [&] (int ix) {
528
529
530
531
        KdenliveSettings::setTitlerbg(ix);
        displayBackgroundFrame();
    });

Laurent Montel's avatar
Laurent Montel committed
532
533
534
535
536
537
538
    connect(m_scene, &QGraphicsScene::selectionChanged, this, &TitleWidget::selectionChanged);
    connect(m_scene, &GraphicsSceneRectMove::itemMoved, this, &TitleWidget::selectionChanged);
    connect(m_scene, &GraphicsSceneRectMove::sceneZoom, this, &TitleWidget::slotZoom);
    connect(m_scene, &GraphicsSceneRectMove::actionFinished, this, &TitleWidget::slotSelectTool);
    connect(m_scene, &GraphicsSceneRectMove::newRect, this, &TitleWidget::slotNewRect);
    connect(m_scene, &GraphicsSceneRectMove::newText, this, &TitleWidget::slotNewText);
    connect(zoom_slider, &QAbstractSlider::valueChanged, this, &TitleWidget::slotUpdateZoom);
539
    connect(zoom_spin, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateZoom);
540

541
    // mbd: load saved settings
542
    loadGradients();
543
    readChoices();
Mads Bondo Dydensborg's avatar
Mads Bondo Dydensborg committed
544

545
546
    graphicsView->show();
    graphicsView->setInteractive(true);
Nicolas Carion's avatar
Nicolas Carion committed
547
    // qCDebug(KDENLIVE_LOG) << "// TITLE WIDGWT: " << graphicsView->viewport()->width() << 'x' << graphicsView->viewport()->height();
548
    m_startViewport = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
549
550
    // Setting data at -1 so that the item is recognized as undeletable by graphicsscenerectmove
    m_startViewport->setData(-1, -1);
551
    m_endViewport = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
552
    m_endViewport->setData(-1, -1);
553
554
555
556
    m_startViewport->setData(0, m_frameWidth);
    m_startViewport->setData(1, m_frameHeight);
    m_endViewport->setData(0, m_frameWidth);
    m_endViewport->setData(1, m_frameHeight);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
557

558
559
    // scale the view so that the title widget is not too big at startup
    graphicsView->scale(.5, .5);
560
    if (url.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
561
562
        loadTitle(url);
    } else {
Laurent Montel's avatar
Laurent Montel committed
563
        prepareTools(nullptr);
Laurent Montel's avatar
Laurent Montel committed
564
        slotTextTool();
Laurent Montel's avatar
Laurent Montel committed
565
        QTimer::singleShot(200, this, &TitleWidget::slotAdjustZoom);
566
    }
567
    initAnimation();
568
569
570
571
    QColor color = backgroundColor->color();
    m_scene->setBackgroundBrush(QBrush(color));
    color.setAlpha(backgroundAlpha->value());
    m_frameBackground->setBrush(color);
Laurent Montel's avatar
Laurent Montel committed
572
573
    connect(anim_start, &QAbstractButton::toggled, this, &TitleWidget::slotAnimStart);
    connect(anim_end, &QAbstractButton::toggled, this, &TitleWidget::slotAnimEnd);
574
    connect(templateBox, SIGNAL(currentIndexChanged(int)), this, SLOT(templateIndexChanged(int)));
575

576
577
578
579
580
    createButton->setEnabled(KdenliveSettings::hastitleproducer());
    QMenu *addMenu = new QMenu(this);
    addMenu->addAction(i18n("Save and add to project"));
    m_createTitleAction = new QAction(i18n("Create Title"), this);
    createButton->setMenu(addMenu);
Vincent Pinon's avatar
Vincent Pinon committed
581
    connect(addMenu, &QMenu::triggered, this, [this]() {
582
583
584
585
586
587
588
        const QUrl url = saveTitle();
        if (!url.isEmpty()) {
            pCore->bin()->slotAddClipToProject(url);
            done(QDialog::Rejected);
        }
    });
    createButton->setDefaultAction(m_createTitleAction);
Vincent Pinon's avatar
Vincent Pinon committed
589
    connect(m_createTitleAction, &QAction::triggered, this, [this]() {
590
591
        done(QDialog::Accepted);
    });
Vincent Pinon's avatar
Vincent Pinon committed
592
    connect(cancelButton, &QPushButton::clicked, this, [this]() {
593
594
        done(QDialog::Rejected);
    });
595
596
    refreshTitleTemplates(m_projectTitlePath);

597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
    // patterns

    m_patternsModel = new PatternsModel(this);
    m_patternsModel->setBackgroundPixmap(m_frameImage);
    connect(this, &TitleWidget::updatePatternsBackgroundFrame, m_patternsModel, &PatternsModel::repaintScenes);

    connect(scaleSlider, &QSlider::valueChanged, this, &TitleWidget::slotPatternsTileWidth);
    connect(patternsList, &QListView::doubleClicked, this, &TitleWidget::slotPatternDblClicked);

    connect(btn_add, &QToolButton::clicked, this, &TitleWidget::slotPatternBtnAddClicked);
    connect(btn_remove, &QToolButton::clicked, this, &TitleWidget::slotPatternBtnRemoveClicked);
    connect(btn_removeAll, &QToolButton::clicked, this, 
            [&] () {
                m_patternsModel->removeAll();
                btn_remove->setEnabled(false);
                btn_removeAll->setEnabled(false);
            });

    scaleSlider->setRange(6, 16);
    patternsList->setModel(m_patternsModel);
    connect(patternsList->selectionModel(), &QItemSelectionModel::currentChanged, this, [&] (const QModelIndex& cur, const QModelIndex& prev) {
        btn_remove->setEnabled(cur != prev && cur.isValid());
    });

    btn_add->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
    btn_remove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
    btn_removeAll->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));

    btn_add->setToolTip(i18n("Add pattern"));
    btn_remove->setToolTip(i18n("Delete pattern"));
    btn_removeAll->setToolTip(i18n("Delete all patterns"));

    btn_add->setEnabled(false);
    btn_remove->setEnabled(false);

    readPatterns();

Nicolas Carion's avatar
Nicolas Carion committed
634
    // templateBox->setIconSize(QSize(60,60));
635
    refreshTemplateBoxContents();
Nicolas Carion's avatar
Nicolas Carion committed
636
    m_lastDocumentHash = QCryptographicHash::hash(xml().toString().toLatin1(), QCryptographicHash::Md5).toHex();
Marco Gittler's avatar
Marco Gittler committed
637
}
638

639
640
TitleWidget::~TitleWidget()
{
641
642
643
    writePatterns();
    delete m_patternsModel;

644
    m_scene->blockSignals(true);
645
646
647
648
649
650
    delete m_buttonRect;
    delete m_buttonText;
    delete m_buttonImage;
    delete m_buttonCursor;
    delete m_buttonSave;
    delete m_buttonLoad;
651
    delete m_unicodeAction;
Simon Eugster's avatar
Simon Eugster committed
652
653
654
655
    delete m_zUp;
    delete m_zDown;
    delete m_zTop;
    delete m_zBottom;
656
657
658
659
660
    delete m_selectAll;
    delete m_selectText;
    delete m_selectRects;
    delete m_selectImages;
    delete m_unselectAll;
661

Alberto Villa's avatar
Alberto Villa committed
662
    delete m_unicodeDialog;
663
664
    delete m_frameBorder;
    delete m_frameImage;
665
666
    delete m_startViewport;
    delete m_endViewport;
667
668
669
    delete m_scene;
}

670
// static
Laurent Montel's avatar
Laurent Montel committed
671
QStringList TitleWidget::extractImageList(const QString &xml)
672
673
{
    QStringList result;
Laurent Montel's avatar
Laurent Montel committed
674
675
676
    if (xml.isEmpty()) {
        return result;
    }
677
678
    QDomDocument doc;
    doc.setContent(xml);
679
    QDomNodeList images = doc.elementsByTagName(QStringLiteral("content"));
680
    for (int i = 0; i < images.count(); ++i) {
Laurent Montel's avatar
Laurent Montel committed
681
        if (images.at(i).toElement().hasAttribute(QStringLiteral("url"))) {
682
            result.append(images.at(i).toElement().attribute(QStringLiteral("url")));
Laurent Montel's avatar
Laurent Montel committed
683
        }
684
685
686
687
    }
    return result;
}

688
// static
Laurent Montel's avatar
Laurent Montel committed
689
QStringList TitleWidget::extractFontList(const QString &xml)
690
691
{
    QStringList result;
Laurent Montel's avatar
Laurent Montel committed
692
693
694
    if (xml.isEmpty()) {
        return result;
    }
695
696
    QDomDocument doc;
    doc.setContent(xml);
697
    QDomNodeList images = doc.elementsByTagName(QStringLiteral("content"));
698
    for (int i = 0; i < images.count(); ++i) {
Laurent Montel's avatar
Laurent Montel committed
699
        if (images.at(i).toElement().hasAttribute(QStringLiteral("font"))) {
700
            result.append(images.at(i).toElement().attribute(QStringLiteral("font")));
Laurent Montel's avatar
Laurent Montel committed
701
        }
702
703
704
    }
    return result;
}
Nicolas Carion's avatar
Nicolas Carion committed
705
// static
706
void TitleWidget::refreshTitleTemplates(const QString &projectPath)
707
{
Laurent Montel's avatar
Laurent Montel committed
708
    QStringList filters = QStringList() << QStringLiteral("*.kdenlivetitle");
709
    titletemplates.clear();
710
711
712
713

    // project templates
    QDir dir(projectPath);
    QStringList templateFiles = dir.entryList(filters, QDir::Files);
Vincent Pinon's avatar
Vincent Pinon committed
714
    for (const QString &fname : qAsConst(templateFiles)) {
715
        TitleTemplate t;
Laurent Montel's avatar
Laurent Montel committed
716
717
        t.name = fname;
        t.file = dir.absoluteFilePath(fname);
718
        t.icon = QIcon(KThumb::getImage(QUrl::fromLocalFile(t.file), 0, 60, -1));
Laurent Montel's avatar
Laurent Montel committed
719
        titletemplates.append(t);
720
721
722
    }

    // system templates
723
    QStringList titleTemplates = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("titles/"), QStandardPaths::LocateDirectory);
724
725
726
727
728
#ifdef Q_OS_WIN
    // Windows: downloaded templatates are saved in AppLocalDataLocation
    titleTemplates.append(QStandardPaths::locateAll(QStandardPaths::AppLocalDataLocation, QStringLiteral("titles/"), QStandardPaths::LocateDirectory));
#endif
    titleTemplates.removeDuplicates();
Vincent Pinon's avatar
Vincent Pinon committed
729
    for (const QString &folderpath : qAsConst(titleTemplates)) {
730
        QDir folder(folderpath);
731
        QStringList filesnames = folder.entryList(filters, QDir::Files);
Vincent Pinon's avatar
Vincent Pinon committed
732
        for (const QString &fname : qAsConst(filesnames)) {
733
734
            TitleTemplate t;
            t.name = fname;
735
            t.file = folder.absoluteFilePath(fname);
736
            t.icon = QIcon(KThumb::getImage(QUrl::fromLocalFile(t.file), 0, 60, -1));
737
            titletemplates.append(t);
738
739
740
        }
    }
}
Laurent Montel's avatar
Laurent Montel committed
741

742
void TitleWidget::templateIndexChanged(int index)
743
{
744
    QString item = templateBox->itemData(index).toString();
745
    if (!item.isEmpty()) {
Nicolas Carion's avatar
Nicolas Carion committed
746
        if (m_lastDocumentHash != QCryptographicHash::hash(xml().toString().toLatin1(), QCryptographicHash::Md5).toHex()) {
Laurent Montel's avatar
Laurent Montel committed
747
            if (KMessageBox::questionYesNo(this, i18n("Do you really want to load a new template? Changes in this title will be lost!")) == KMessageBox::No) {
Laurent Montel's avatar
Laurent Montel committed
748
                return;
Laurent Montel's avatar
Laurent Montel committed
749
            }
750
        }
751
        loadTitle(QUrl::fromLocalFile(item));
752
753
754
755

        // mbt 1607: Add property to distinguish between unchanged template titles and user titles.
        // Text of unchanged template titles should be selected when clicked.
        QList<QGraphicsItem *> list = graphicsView->scene()->items();
Vincent Pinon's avatar
Vincent Pinon committed
756
        for (QGraphicsItem *qgItem : qAsConst(list)) {
757
            if (qgItem->type() == TEXTITEM) {
Nicolas Carion's avatar
Nicolas Carion committed
758
                auto *i = static_cast<MyTextItem *>(qgItem);
759
760
761
762
                i->setProperty("isTemplate", "true");
                i->setProperty("templateText", i->toHtml());
            }
        }
Nicolas Carion's avatar
Nicolas Carion committed
763
        m_lastDocumentHash = QCryptographicHash::hash(xml().toString().toLatin1(), QCryptographicHash::Md5).toHex();
764
    }
765
}
Nicolas Carion's avatar
Nicolas Carion committed
766
// virtual
767
768
void TitleWidget::resizeEvent(QResizeEvent * /*event*/)
{
Nicolas Carion's avatar
Nicolas Carion committed
769
    // slotAdjustZoom();
770
}
Nicolas Carion's avatar
Nicolas Carion committed
771
// virtual
Laurent Montel's avatar
Laurent Montel committed
772
773
void TitleWidget::keyPressEvent(QKeyEvent *e)
{
Laurent Montel's avatar
Laurent Montel committed
774
775
776
    if (e->key() != Qt::Key_Escape && e->key() != Qt::Key_Return && e->key() != Qt::Key_Enter) {
        QDialog::keyPressEvent(e);
    }
777
}
Laurent Montel's avatar
Laurent Montel committed
778

779
780
void TitleWidget::slotTextTool()
{
781
    m_scene->setTool(TITLE_TEXT);
Simon Eugster's avatar
Simon Eugster committed
782
    showToolbars(TITLE_TEXT);
Simon Eugster's avatar
Simon Eugster committed
783
    checkButton(TITLE_TEXT);
784
785
}

786
787
void TitleWidget::slotRectTool()
{
788
    m_scene->setTool(TITLE_RECTANGLE);