titlewidget.cpp 132 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 "timecodedisplay.h"
29
#include "kdenlivesettings.h"
30
#include "monitor/monitor.h"
31
32
#include "titler/patternsmodel.h"
#include "profiles/profilemodel.hpp"
33

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

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

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

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

68
69
static QList<TitleTemplate> titletemplates;

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

73
74
75
const int IMAGEITEM = 7;
const int RECTITEM = 3;
const int TEXTITEM = 8;
Julius Künzel's avatar
Julius Künzel committed
76
const int ELLIPSEITEM = 4;
77

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

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

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

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

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

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

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

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

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

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

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

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

166
    itemzoom->setSuffix(i18n("%"));
167
    QSize profileSize = pCore->getCurrentFrameSize();
Vincent Pinon's avatar
Vincent Pinon committed
168
    m_frameWidth = int(profileSize.height() * pCore->getCurrentDar() + 0.5);
169
    m_frameHeight = profileSize.height();
170
    showToolbars(TITLE_SELECT);
171

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

174
175
176
177
178
    m_duration = new TimecodeDisplay(pCore->timecode(), this);
    m_duration->setValue(KdenliveSettings::title_duration());
    duration_box->addWidget(m_duration);
    auto *spacer = new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
    duration_box->addSpacerItem(spacer);
179

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

Laurent Montel's avatar
Laurent Montel committed
183
184
    connect(shadowBox, &QGroupBox::toggled, this, &TitleWidget::slotUpdateShadow);
    connect(shadowColor, &KColorButton::changed, this, &TitleWidget::slotUpdateShadow);
185
186
187
    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);
188

189
190
191
192
193
194
195
196
197
    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);
198
    if (mlt_version_get_int() < 0x061900) {
199
200
        typewriterBox->setEnabled(false);

Julius Künzel's avatar
Julius Künzel committed
201
202
203
204
205
206
        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);
207
208
    }

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

Laurent Montel's avatar
Laurent Montel committed
214
215
    connect(textOutlineColor, &KColorButton::changed, this, &TitleWidget::slotUpdateText);
    connect(font_family, &QFontComboBox::currentFontChanged, this, &TitleWidget::slotUpdateText);
216
217
218
219
    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
220
    connect(font_weight_box, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateText()));
221

Laurent Montel's avatar
Laurent Montel committed
222
223
224
225
    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);
226
    connect(gradients_rect_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(rectChanged()));
227
    connect(rectLineWidth, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::rectChanged);
228

229
230
231
232
233
    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
234
235
236
237
238
239
    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
240

Laurent Montel's avatar
Laurent Montel committed
241
242
    connect(origin_x_left, &QAbstractButton::clicked, this, &TitleWidget::slotOriginXClicked);
    connect(origin_y_top, &QAbstractButton::clicked, this, &TitleWidget::slotOriginYClicked);
243

244
    connect(monitor, &Monitor::frameUpdated, this, &TitleWidget::slotGotBackground);
245
    connect(this, &TitleWidget::requestBackgroundFrame, monitor, &Monitor::slotGetCurrentImage);
Simon Eugster's avatar
Simon Eugster committed
246

247
    // Position and size
Vincent Pinon's avatar
Vincent Pinon committed
248
249
250
251
    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);});
252

Laurent Montel's avatar
Laurent Montel committed
253
254
255
256
257
258
259
260
261
    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
262
    connect(preserveAspectRatio, static_cast<void (QCheckBox::*)(int)>(&QCheckBox::stateChanged), this, [&] () {
263
264
        slotValueChanged(ValueWidth);
    });
265
266

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

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

274
    // mbd
Laurent Montel's avatar
Laurent Montel committed
275
    connect(this, &QDialog::accepted, this, &TitleWidget::slotAccepted);
Mads Bondo Dydensborg's avatar
Mads Bondo Dydensborg committed
276

Simon Eugster's avatar
Titler:    
Simon Eugster committed
277
278
279
280
281
282
283
284
285
286
    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);

287
288
289
290
291
292
293
    buttonFitZoom->setIconSize(iconSize);
    buttonRealSize->setIconSize(iconSize);
    buttonItalic->setIconSize(iconSize);
    buttonUnder->setIconSize(iconSize);
    buttonAlignCenter->setIconSize(iconSize);
    buttonAlignLeft->setIconSize(iconSize);
    buttonAlignRight->setIconSize(iconSize);
294

295
296
297
298
299
    if (qApp->isLeftToRight()) {
        buttonAlignRight->setChecked(true);
    } else {
        buttonAlignLeft->setChecked(true);
    }
300

301
    m_unicodeAction = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-insert-unicode")), QString(), this);
302
    m_unicodeAction->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_U);
303
    m_unicodeAction->setToolTip(getTooltipWithShortcut(i18n("Insert Unicode character"), m_unicodeAction));
Laurent Montel's avatar
Laurent Montel committed
304
    connect(m_unicodeAction, &QAction::triggered, this, &TitleWidget::slotInsertUnicode);
305
    buttonInsertUnicode->setDefaultAction(m_unicodeAction);
306

307
    m_zUp = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-up")), QString(), this);
Simon Eugster's avatar
Simon Eugster committed
308
309
    m_zUp->setShortcut(Qt::Key_PageUp);
    m_zUp->setToolTip(i18n("Raise object"));
Laurent Montel's avatar
Laurent Montel committed
310
    connect(m_zUp, &QAction::triggered, this, &TitleWidget::slotZIndexUp);
Simon Eugster's avatar
Simon Eugster committed
311
    zUp->setDefaultAction(m_zUp);
312

313
    m_zDown = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-down")), QString(), this);
Simon Eugster's avatar
Simon Eugster committed
314
315
    m_zDown->setShortcut(Qt::Key_PageDown);
    m_zDown->setToolTip(i18n("Lower object"));
Laurent Montel's avatar
Laurent Montel committed
316
    connect(m_zDown, &QAction::triggered, this, &TitleWidget::slotZIndexDown);
Simon Eugster's avatar
Simon Eugster committed
317
    zDown->setDefaultAction(m_zDown);
318

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

327
    m_zBottom = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-bottom")), QString(), this);
328
    // TODO mbt 1414
Nicolas Carion's avatar
Nicolas Carion committed
329
    // m_zBottom->setShortcut(Qt::Key_End);
Simon Eugster's avatar
Simon Eugster committed
330
    m_zBottom->setToolTip(i18n("Lower object to bottom"));
Laurent Montel's avatar
Laurent Montel committed
331
    connect(m_zBottom, &QAction::triggered, this, &TitleWidget::slotZIndexBottom);
Simon Eugster's avatar
Simon Eugster committed
332
    zBottom->setDefaultAction(m_zBottom);
333

334
    m_selectAll = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-all")), QString(), this);
335
    m_selectAll->setShortcut(Qt::CTRL + Qt::Key_A);
Laurent Montel's avatar
Laurent Montel committed
336
    connect(m_selectAll, &QAction::triggered, this, &TitleWidget::slotSelectAll);
337
    buttonSelectAll->setDefaultAction(m_selectAll);
338

339
    m_selectText = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-texts")), QString(), this);
340
    m_selectText->setShortcut(Qt::CTRL + Qt::Key_T);
Laurent Montel's avatar
Laurent Montel committed
341
    connect(m_selectText, &QAction::triggered, this, &TitleWidget::slotSelectText);
342
    buttonSelectText->setDefaultAction(m_selectText);
343
344
    buttonSelectText->setEnabled(false);

345
    m_selectRects = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-rects")), QString(), this);
346
    m_selectRects->setShortcut(Qt::CTRL + Qt::Key_R);
Laurent Montel's avatar
Laurent Montel committed
347
    connect(m_selectRects, &QAction::triggered, this, &TitleWidget::slotSelectRects);
348
    buttonSelectRects->setDefaultAction(m_selectRects);
349
350
    buttonSelectRects->setEnabled(false);

351
    m_selectImages = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-images")), QString(), this);
352
    m_selectImages->setShortcut(Qt::CTRL + Qt::Key_I);
Laurent Montel's avatar
Laurent Montel committed
353
    connect(m_selectImages, &QAction::triggered, this, &TitleWidget::slotSelectImages);
354
    buttonSelectImages->setDefaultAction(m_selectImages);
355
356
    buttonSelectImages->setEnabled(false);

357
    m_unselectAll = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-unselect-all")), QString(), this);
358
    m_unselectAll->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_A);
Laurent Montel's avatar
Laurent Montel committed
359
    connect(m_unselectAll, &QAction::triggered, this, &TitleWidget::slotSelectNone);
360
    buttonUnselectAll->setDefaultAction(m_unselectAll);
361
    buttonUnselectAll->setEnabled(false);
362

Alberto Villa's avatar
Alberto Villa committed
363
364
365
366
367
368
369
    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"));
370
    backgroundColor->setToolTip(i18n("Select background color"));
Simon Eugster's avatar
Simon Eugster committed
371
    backgroundAlpha->setToolTip(i18n("Background opacity"));
372
373
374
375
376
    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));
377

378
379
380
381
382
383
    itemhcenter->setIconSize(iconSize);
    itemvcenter->setIconSize(iconSize);
    itemtop->setIconSize(iconSize);
    itembottom->setIconSize(iconSize);
    itemright->setIconSize(iconSize);
    itemleft->setIconSize(iconSize);
384

Nicolas Carion's avatar
Nicolas Carion committed
385
    auto *layout = new QHBoxLayout;
386
    frame_toolbar->setLayout(layout);
387
    layout->setContentsMargins(0, 0, 0, 0);
388
    QToolBar *m_toolbar = new QToolBar(QStringLiteral("titleToolBar"), this);
389
    m_toolbar->setIconSize(iconSize);
390

391
    m_buttonCursor = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("transform-move")), i18n("Selection Tool"));
392
393
    m_buttonCursor->setCheckable(true);
    m_buttonCursor->setShortcut(Qt::ALT + Qt::Key_S);
Laurent Montel's avatar
Laurent Montel committed
394
    m_buttonCursor->setToolTip(i18n("Selection Tool") + QLatin1Char(' ') + m_buttonCursor->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
395
    connect(m_buttonCursor, &QAction::triggered, this, &TitleWidget::slotSelectTool);
396

397
    m_buttonText = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("insert-text")), i18n("Add Text"));
398
    m_buttonText->setCheckable(true);
Alberto Villa's avatar
Alberto Villa committed
399
    m_buttonText->setShortcut(Qt::ALT + Qt::Key_T);
Laurent Montel's avatar
Laurent Montel committed
400
    m_buttonText->setToolTip(i18n("Add Text") + QLatin1Char(' ') + m_buttonText->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
401
    connect(m_buttonText, &QAction::triggered, this, &TitleWidget::slotTextTool);
402

403
    m_buttonRect = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("kdenlive-insert-rect")), i18n("Add Rectangle"));
404
405
    m_buttonRect->setCheckable(true);
    m_buttonRect->setShortcut(Qt::ALT + Qt::Key_R);
Laurent Montel's avatar
Laurent Montel committed
406
    m_buttonRect->setToolTip(i18n("Add Rectangle") + QLatin1Char(' ') + m_buttonRect->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
407
    connect(m_buttonRect, &QAction::triggered, this, &TitleWidget::slotRectTool);
408

Julius Künzel's avatar
Julius Künzel committed
409
410
411
412
413
414
415
416
417
    m_buttonEllipse = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("draw-ellipse")), i18n("Add Ellipse"));
    m_buttonEllipse->setCheckable(true);
    m_buttonEllipse->setShortcut(Qt::ALT + Qt::Key_E);
    m_buttonEllipse->setToolTip(i18n("Add Ellipse") + QLatin1Char(' ') + m_buttonEllipse->shortcut().toString());
    connect(m_buttonEllipse, &QAction::triggered, this, &TitleWidget::slotEllipseTool);
    if (mlt_version_get_int() < 0x061900) {
        m_buttonEllipse->setVisible(false);
    }

418
    m_buttonImage = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("insert-image")), i18n("Add Image"));
419
    m_buttonImage->setCheckable(false);
Alberto Villa's avatar
Alberto Villa committed
420
    m_buttonImage->setShortcut(Qt::ALT + Qt::Key_I);
Laurent Montel's avatar
Laurent Montel committed
421
    m_buttonImage->setToolTip(i18n("Add Image") + QLatin1Char(' ') + m_buttonImage->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
422
    connect(m_buttonImage, &QAction::triggered, this, &TitleWidget::slotImageTool);
423

Simon Eugster's avatar
Simon Eugster committed
424
    m_toolbar->addSeparator();
425

426
    m_buttonLoad = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("document-open")), i18n("Open Document"));
427
    m_buttonLoad->setCheckable(false);
Alberto Villa's avatar
Alberto Villa committed
428
    m_buttonLoad->setShortcut(Qt::CTRL + Qt::Key_O);
Laurent Montel's avatar
Laurent Montel committed
429
    m_buttonLoad->setToolTip(i18n("Open Document") + QLatin1Char(' ') + m_buttonLoad->shortcut().toString());
430
431
    connect(m_buttonLoad, SIGNAL(triggered()), this, SLOT(loadTitle()));

432
    m_buttonSave = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("document-save-as")), i18n("Save As"));
433
    m_buttonSave->setCheckable(false);
Alberto Villa's avatar
Alberto Villa committed
434
    m_buttonSave->setShortcut(Qt::CTRL + Qt::Key_S);
Laurent Montel's avatar
Laurent Montel committed
435
    m_buttonSave->setToolTip(i18n("Save As") + QLatin1Char(' ') + m_buttonSave->shortcut().toString());
436
437
    connect(m_buttonSave, SIGNAL(triggered()), this, SLOT(saveTitle()));

438
439
440
441
442
443
    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);

444
    layout->addWidget(m_toolbar);
445

446
    // initialize graphic scene
447
    m_scene = new GraphicsSceneRectMove(this);
448
    graphicsView->setScene(m_scene);
449
    graphicsView->setMouseTracking(true);
450
    graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
451
452
    graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
    graphicsView->setRubberBandSelectionMode(Qt::ContainsItemBoundingRect);
453
    m_titledocument.setScene(m_scene, m_frameWidth, m_frameHeight);
Laurent Montel's avatar
Laurent Montel committed
454
    connect(m_scene, &QGraphicsScene::changed, this, &TitleWidget::slotChanged);
455
    connect(font_size, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), m_scene, &GraphicsSceneRectMove::slotUpdateFontSize);
Laurent Montel's avatar
Laurent Montel committed
456
    connect(use_grid, &QAbstractButton::toggled, m_scene, &GraphicsSceneRectMove::slotUseGrid);
457

458
459
    // Video frame rect
    QPen framepen;
460
461
462
    framepen.setColor(Qt::red);
    m_frameBorder = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
    m_frameBorder->setPen(framepen);
463
    m_frameBorder->setZValue(1000);
464
    m_frameBorder->setBrush(Qt::transparent);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
465
    m_frameBorder->setData(-1, -1);
466
    graphicsView->scene()->addItem(m_frameBorder);
467

468
    // Guides
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
469
470
    connect(show_guides, &QCheckBox::stateChanged, this, &TitleWidget::showGuides);
    show_guides->setChecked(KdenliveSettings::titlerShowGuides());
471
472
    hguides->setValue(KdenliveSettings::titlerHGuides());
    vguides->setValue(KdenliveSettings::titlerVGuides());
473
474
    guideColor->setColor(KdenliveSettings::titleGuideColor());
    connect(guideColor, &KColorButton::changed, this, &TitleWidget::guideColorChanged);
475
476
477
    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
478

479
    // semi transparent safe zones
480
    framepen.setColor(QColor(255, 0, 0, 100));
481
482
483
    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
484
    safe1->setData(-1, -1);
485
486
487
    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
488
    safe2->setData(-1, -1);
489
490
491
492
493
494

    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);

495
496
497
498
499
500
501
502
    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);

503
    bgBox->setCurrentIndex(KdenliveSettings::titlerbg());
Vincent Pinon's avatar
Vincent Pinon committed
504
    connect(bgBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [&] (int ix) {
505
506
507
508
        KdenliveSettings::setTitlerbg(ix);
        displayBackgroundFrame();
    });

Laurent Montel's avatar
Laurent Montel committed
509
510
511
512
513
    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);
Julius Künzel's avatar
Julius Künzel committed
514
    connect(m_scene, &GraphicsSceneRectMove::newEllipse, this, &TitleWidget::slotNewEllipse);
Laurent Montel's avatar
Laurent Montel committed
515
516
    connect(m_scene, &GraphicsSceneRectMove::newText, this, &TitleWidget::slotNewText);
    connect(zoom_slider, &QAbstractSlider::valueChanged, this, &TitleWidget::slotUpdateZoom);
517
    connect(zoom_spin, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateZoom);
518

519
    // mbd: load saved settings
520
    loadGradients();
521
    readChoices();
Mads Bondo Dydensborg's avatar
Mads Bondo Dydensborg committed
522

523
524
    graphicsView->show();
    graphicsView->setInteractive(true);
Nicolas Carion's avatar
Nicolas Carion committed
525
    // qCDebug(KDENLIVE_LOG) << "// TITLE WIDGWT: " << graphicsView->viewport()->width() << 'x' << graphicsView->viewport()->height();
526
    m_startViewport = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
527
528
    // Setting data at -1 so that the item is recognized as undeletable by graphicsscenerectmove
    m_startViewport->setData(-1, -1);
529
    m_endViewport = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
530
    m_endViewport->setData(-1, -1);
531
532
533
534
    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
535

536
537
    // scale the view so that the title widget is not too big at startup
    graphicsView->scale(.5, .5);
538
    if (url.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
539
540
        loadTitle(url);
    } else {
Laurent Montel's avatar
Laurent Montel committed
541
        prepareTools(nullptr);
Laurent Montel's avatar
Laurent Montel committed
542
        slotTextTool();
Laurent Montel's avatar
Laurent Montel committed
543
        QTimer::singleShot(200, this, &TitleWidget::slotAdjustZoom);
544
    }
545
    initAnimation();
546
547
548
549
    QColor color = backgroundColor->color();
    m_scene->setBackgroundBrush(QBrush(color));
    color.setAlpha(backgroundAlpha->value());
    m_frameBackground->setBrush(color);
Laurent Montel's avatar
Laurent Montel committed
550
551
    connect(anim_start, &QAbstractButton::toggled, this, &TitleWidget::slotAnimStart);
    connect(anim_end, &QAbstractButton::toggled, this, &TitleWidget::slotAnimEnd);
552
    connect(templateBox, SIGNAL(currentIndexChanged(int)), this, SLOT(templateIndexChanged(int)));
553

554
    createButton->setEnabled(KdenliveSettings::hastitleproducer());
555
    auto *addMenu = new QMenu(this);
556
557
558
    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
559
    connect(addMenu, &QMenu::triggered, this, [this]() {
560
561
562
563
564
565
566
        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
567
    connect(m_createTitleAction, &QAction::triggered, this, [this]() {
568
569
        done(QDialog::Accepted);
    });
Vincent Pinon's avatar
Vincent Pinon committed
570
    connect(cancelButton, &QPushButton::clicked, this, [this]() {
571
572
        done(QDialog::Rejected);
    });
573
574
    refreshTitleTemplates(m_projectTitlePath);

575
576
577
578
579
580
581
582
583
584
585
    // 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);
Julius Künzel's avatar
Julius Künzel committed
586
    connect(btn_removeAll, &QToolButton::clicked, this,
587
            [&] () {
Julius Künzel's avatar
Julius Künzel committed
588
589
590
591
        m_patternsModel->removeAll();
        btn_remove->setEnabled(false);
        btn_removeAll->setEnabled(false);
    });
592
593
594
595
596
597
598
599
600

    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());
    });

    readPatterns();

Nicolas Carion's avatar
Nicolas Carion committed
601
    // templateBox->setIconSize(QSize(60,60));
602
    refreshTemplateBoxContents();
Nicolas Carion's avatar
Nicolas Carion committed
603
    m_lastDocumentHash = QCryptographicHash::hash(xml().toString().toLatin1(), QCryptographicHash::Md5).toHex();
Marco Gittler's avatar
Marco Gittler committed
604
}
605

606
607
TitleWidget::~TitleWidget()
{
608
609
610
    writePatterns();
    delete m_patternsModel;

611
    m_scene->blockSignals(true);
612
    delete m_buttonRect;
Julius Künzel's avatar
Julius Künzel committed
613
    delete m_buttonEllipse;
614
615
616
617
618
    delete m_buttonText;
    delete m_buttonImage;
    delete m_buttonCursor;
    delete m_buttonSave;
    delete m_buttonLoad;
619
    delete m_unicodeAction;
Simon Eugster's avatar
Simon Eugster committed
620
621
622
623
    delete m_zUp;
    delete m_zDown;
    delete m_zTop;
    delete m_zBottom;
624
625
626
627
628
    delete m_selectAll;
    delete m_selectText;
    delete m_selectRects;
    delete m_selectImages;
    delete m_unselectAll;
629

Alberto Villa's avatar
Alberto Villa committed
630
    delete m_unicodeDialog;
631
632
    delete m_frameBorder;
    delete m_frameImage;
633
634
    delete m_startViewport;
    delete m_endViewport;
635
636
637
    delete m_scene;
}

638
// static
Laurent Montel's avatar
Laurent Montel committed
639
QStringList TitleWidget::extractImageList(const QString &xml)
640
641
{
    QStringList result;
Laurent Montel's avatar
Laurent Montel committed
642
643
644
    if (xml.isEmpty()) {
        return result;
    }
645
646
    QDomDocument doc;
    doc.setContent(xml);
647
    QDomNodeList images = doc.elementsByTagName(QStringLiteral("content"));
648
    for (int i = 0; i < images.count(); ++i) {
Laurent Montel's avatar
Laurent Montel committed
649
        if (images.at(i).toElement().hasAttribute(QStringLiteral("url"))) {
650
            result.append(images.at(i).toElement().attribute(QStringLiteral("url")));
Laurent Montel's avatar
Laurent Montel committed
651
        }
652
653
654
655
    }
    return result;
}

656
// static
Laurent Montel's avatar
Laurent Montel committed
657
QStringList TitleWidget::extractFontList(const QString &xml)
658
659
{
    QStringList result;
Laurent Montel's avatar
Laurent Montel committed
660
661
662
    if (xml.isEmpty()) {
        return result;
    }
663
664
    QDomDocument doc;
    doc.setContent(xml);
665
    QDomNodeList images = doc.elementsByTagName(QStringLiteral("content"));
666
    for (int i = 0; i < images.count(); ++i) {
Laurent Montel's avatar
Laurent Montel committed
667
        if (images.at(i).toElement().hasAttribute(QStringLiteral("font"))) {
668
            result.append(images.at(i).toElement().attribute(QStringLiteral("font")));
Laurent Montel's avatar
Laurent Montel committed
669
        }
670
671
672
    }
    return result;
}
Nicolas Carion's avatar
Nicolas Carion committed
673
// static
674
void TitleWidget::refreshTitleTemplates(const QString &projectPath)
675
{
Laurent Montel's avatar
Laurent Montel committed
676
    QStringList filters = QStringList() << QStringLiteral("*.kdenlivetitle");
677
    titletemplates.clear();
678
679
680
681

    // project templates
    QDir dir(projectPath);
    QStringList templateFiles = dir.entryList(filters, QDir::Files);
Vincent Pinon's avatar
Vincent Pinon committed
682
    for (const QString &fname : qAsConst(templateFiles)) {
683
        TitleTemplate t;
Laurent Montel's avatar
Laurent Montel committed
684
685
        t.name = fname;
        t.file = dir.absoluteFilePath(fname);
686
        t.icon = QIcon(KThumb::getImage(QUrl::fromLocalFile(t.file), 0, 60, -1));
Laurent Montel's avatar
Laurent Montel committed
687
        titletemplates.append(t);
688
689
690
    }

    // system templates
691
    QStringList titleTemplates = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("titles/"), QStandardPaths::LocateDirectory);
692
693
694
695
696
#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
697
    for (const QString &folderpath : qAsConst(titleTemplates)) {
698
        QDir folder(folderpath);
699
        QStringList filesnames = folder.entryList(filters, QDir::Files);
Vincent Pinon's avatar
Vincent Pinon committed
700
        for (const QString &fname : qAsConst(filesnames)) {
701
702
            TitleTemplate t;
            t.name = fname;
703
            t.file = folder.absoluteFilePath(fname);
704
            t.icon = QIcon(KThumb::getImage(QUrl::fromLocalFile(t.file), 0, 60, -1));
705
            titletemplates.append(t);
706
707
708
        }
    }
}
Laurent Montel's avatar
Laurent Montel committed
709

710
void TitleWidget::templateIndexChanged(int index)
711
{
712
    QString item = templateBox->itemData(index).toString();
713
    if (!item.isEmpty()) {
Nicolas Carion's avatar
Nicolas Carion committed
714
        if (m_lastDocumentHash != QCryptographicHash::hash(xml().toString().toLatin1(), QCryptographicHash::Md5).toHex()) {
Laurent Montel's avatar
Laurent Montel committed
715
            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
716
                return;
Laurent Montel's avatar
Laurent Montel committed
717
            }
718
        }
719
        loadTitle(QUrl::fromLocalFile(item));
720
721
722
723

        // 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
724
        for (QGraphicsItem *qgItem : qAsConst(list)) {
725
            if (qgItem->type() == TEXTITEM) {
Nicolas Carion's avatar
Nicolas Carion committed
726
                auto *i = static_cast<MyTextItem *>(qgItem);
727
728
729
730
                i->setProperty("isTemplate", "true");
                i->setProperty("templateText", i->toHtml());
            }
        }
Nicolas Carion's avatar
Nicolas Carion committed
731
        m_lastDocumentHash = QCryptographicHash::hash(xml().toString().toLatin1(), QCryptographicHash::Md5).toHex();
732
    }
733
}
Nicolas Carion's avatar
Nicolas Carion committed
734
// virtual
735
736
void TitleWidget::resizeEvent(QResizeEvent * /*event*/)
{
Nicolas Carion's avatar
Nicolas Carion committed
737
    // slotAdjustZoom();
738
}
Nicolas Carion's avatar
Nicolas Carion committed
739
// virtual
Laurent Montel's avatar
Laurent Montel committed
740
741
void TitleWidget::keyPressEvent(QKeyEvent *e)
{
Laurent Montel's avatar
Laurent Montel committed
742
743
744
    if (e->key() != Qt::Key_Escape && e->key() != Qt::Key_Return && e->key() != Qt::Key_Enter) {
        QDialog::keyPressEvent(e);
    }
745
}
Laurent Montel's avatar
Laurent Montel committed
746

747
748
void TitleWidget::slotTextTool()
{
749
    m_scene->setTool(TITLE_TEXT);
Simon Eugster's avatar
Simon Eugster committed
750
    showToolbars(TITLE_TEXT);
Simon Eugster's avatar
Simon Eugster committed
751
    checkButton(TITLE_TEXT);
752
753
}

754
755
void TitleWidget::slotRectTool()
{
756
    m_scene->setTool(TITLE_RECTANGLE);
Simon Eugster's avatar
Simon Eugster committed
757
    showToolbars(TITLE_RECTANGLE);
Simon Eugster's avatar
Simon Eugster committed
758
    checkButton(TITLE_RECTANGLE);
759

760
761
    // Disable dragging mode, would make dragging a rect impossible otherwise ;)
    graphicsView->setDragMode(QGraphicsView::NoDrag);
762
763
}

Julius Künzel's avatar
Julius Künzel committed
764
765
766
767
768
769
770
771
772
773
void TitleWidget::slotEllipseTool()
{
    m_scene->setTool(TITLE_ELLIPSE);
    showToolbars(TITLE_ELLIPSE);
    checkButton(TITLE_ELLIPSE);

    // Disable dragging mode, would make dragging a ellipse impossible otherwise ;)
    graphicsView->setDragMode(QGraphicsView::NoDrag);
}

774
775
void TitleWidget::slotSelectTool()
{
776
    m_scene->setTool(TITLE_SELECT);
777

778
779
    // Enable rubberband selecting mode.
    graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
Simon Eugster's avatar
Simon Eugster committed
780
781
782
783

    // Find out which toolbars need to be shown, depending on selected item
    TITLETOOL t = TITLE_SELECT;
    QList<QGraphicsItem *> l = graphicsView->scene()->selectedItems();
Laurent Montel's avatar
Laurent Montel committed
784
    if (!l.isEmpty()) {