titlewidget.cpp 131 KB
Newer Older
1
/*
Camille Moulin's avatar
Camille Moulin committed
2
3
4
    SPDX-FileCopyrightText: 2008 Marco Gittler <g.marco@freenet.de>
    SPDX-FileCopyrightText: Rafał Lalik

Camille Moulin's avatar
Camille Moulin committed
5
    SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
6
*/
7

8
/*
9
10
11
12
 *                                                                         *
 *   Modifications by Rafał Lalik to implement Patterns mechanism          *
 *                                                                         *
 ***************************************************************************/
13

14
#include "titlewidget.h"
15
#include "bin/bin.h"
16
#include "core.h"
Nicolas Carion's avatar
Nicolas Carion committed
17
#include "doc/kthumb.h"
18
#include "gradientwidget.h"
19
#include "kdenlivesettings.h"
20
#include "mainwindow.h"
21
#include "monitor/monitor.h"
22
#include "profiles/profilemodel.hpp"
23
24
#include "timecodedisplay.h"
#include "titler/patternsmodel.h"
25

Simon Eugster's avatar
Simon Eugster committed
26
27
#include <cmath>

28
#include <KMessageBox>
29
#include <KMessageWidget>
30
#include <KRecentDirs>
Nicolas Carion's avatar
Nicolas Carion committed
31
#include <klocalizedstring.h>
32

Laurent Montel's avatar
Laurent Montel committed
33
#include "kdenlive_debug.h"
34
#include <QButtonGroup>
Nicolas Carion's avatar
Nicolas Carion committed
35
#include <QCryptographicHash>
36
#include <QDomDocument>
Nicolas Carion's avatar
Nicolas Carion committed
37
38
#include <QFileDialog>
#include <QFontDatabase>
39
40
41
#include <QGraphicsBlurEffect>
#include <QGraphicsDropShadowEffect>
#include <QGraphicsEffect>
Marco Gittler's avatar
Marco Gittler committed
42
#include <QGraphicsItem>
43
#include <QGraphicsSvgItem>
Nicolas Carion's avatar
Nicolas Carion committed
44
45
#include <QImageReader>
#include <QKeyEvent>
46
#include <QMenu>
47
#include <QSignalMapper>
48
#include <QSpinBox>
49
50
#include <QTextBlockFormat>
#include <QTextCursor>
Nicolas Carion's avatar
Nicolas Carion committed
51
52
#include <QTimer>
#include <QToolBar>
53

54
#include <QStandardPaths>
Nicolas Carion's avatar
Nicolas Carion committed
55
#include <iostream>
56
#include <mlt++/MltProfile.h>
Nicolas Carion's avatar
Nicolas Carion committed
57
#include <utility>
58

59
60
static QList<TitleTemplate> titleTemplates;

61
// TODO What exactly is this variable good for?
Nicolas Carion's avatar
Nicolas Carion committed
62
int settingUp = 0;
63

64
const int IMAGEITEM = 7;
65
66
67
const int RECTITEM = QGraphicsRectItem::Type;
const int TEXTITEM = QGraphicsTextItem::Type;
const int ELLIPSEITEM = QGraphicsEllipseItem::Type;
68

Vincent Pinon's avatar
Vincent Pinon committed
69
/*
70
71
72
73
const int NOEFFECT = 0;
const int BLUREFFECT = 1;
const int SHADOWEFFECT = 2;
const int TYPEWRITEREFFECT = 3;
Vincent Pinon's avatar
Vincent Pinon committed
74
*/
75

76
77
78
79
void TitleWidget::refreshTemplateBoxContents()
{
    templateBox->clear();
    templateBox->addItem(QString());
80
    for (const TitleTemplate &t : qAsConst(titleTemplates)) {
81
82
83
84
        templateBox->addItem(t.icon, t.name, t.file);
    }
}

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

105
106
107
108
    rectBColor->setAlphaChannelEnabled(true);
    rectFColor->setAlphaChannelEnabled(true);
    fontColorButton->setAlphaChannelEnabled(true);
    textOutlineColor->setAlphaChannelEnabled(true);
109
    shadowColor->setAlphaChannelEnabled(true);
110

Nicolas Carion's avatar
Nicolas Carion committed
111
    auto *colorGroup = new QButtonGroup(this);
112
113
114
    colorGroup->addButton(gradient_color);
    colorGroup->addButton(plain_color);

Nicolas Carion's avatar
Nicolas Carion committed
115
    auto *alignGroup = new QButtonGroup(this);
116
117
118
119
    alignGroup->addButton(buttonAlignLeft);
    alignGroup->addButton(buttonAlignCenter);
    alignGroup->addButton(buttonAlignRight);

120
121
    textOutline->setMinimum(0);
    textOutline->setMaximum(200);
Nicolas Carion's avatar
Nicolas Carion committed
122
    // textOutline->setDecimals(0);
123
124
    textOutline->setValue(0);
    textOutline->setToolTip(i18n("Outline width"));
125
126
127

    backgroundAlpha->setMinimum(0);
    backgroundAlpha->setMaximum(255);
128
129
    bgAlphaSlider->setMinimum(0);
    bgAlphaSlider->setMaximum(255);
130
131
132
    backgroundAlpha->setValue(0);
    backgroundAlpha->setToolTip(i18n("Background color opacity"));

133
134
    itemrotatex->setMinimum(-360);
    itemrotatex->setMaximum(360);
Nicolas Carion's avatar
Nicolas Carion committed
135
    // itemrotatex->setDecimals(0);
136
137
138
139
140
    itemrotatex->setValue(0);
    itemrotatex->setToolTip(i18n("Rotation around the X axis"));

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

    itemrotatez->setMinimum(-360);
    itemrotatez->setMaximum(360);
Nicolas Carion's avatar
Nicolas Carion committed
147
    // itemrotatez->setDecimals(0);
148
149
    itemrotatez->setValue(0);
    itemrotatez->setToolTip(i18n("Rotation around the Z axis"));
150
151

    rectLineWidth->setMinimum(0);
152
    rectLineWidth->setMaximum(500);
Nicolas Carion's avatar
Nicolas Carion committed
153
    // rectLineWidth->setDecimals(0);
154
155
156
    rectLineWidth->setValue(0);
    rectLineWidth->setToolTip(i18n("Border width"));

157
    itemzoom->setSuffix(i18n("%"));
158
    QSize profileSize = pCore->getCurrentFrameSize();
Vincent Pinon's avatar
Vincent Pinon committed
159
    m_frameWidth = int(profileSize.height() * pCore->getCurrentDar() + 0.5);
160
    m_frameHeight = profileSize.height();
161
    showToolbars(TITLE_SELECT);
162

163
164
    splitter->setStretchFactor(0, 20);

165
166
167
168
169
    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);
170

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

Laurent Montel's avatar
Laurent Montel committed
174
175
    connect(shadowBox, &QGroupBox::toggled, this, &TitleWidget::slotUpdateShadow);
    connect(shadowColor, &KColorButton::changed, this, &TitleWidget::slotUpdateShadow);
176
177
178
    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);
179

180
181
182
183
184
185
186
187
188
189
    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);

Laurent Montel's avatar
Laurent Montel committed
190
191
192
    connect(fontColorButton, &KColorButton::changed, this, &TitleWidget::slotUpdateText);
    connect(plain_color, &QAbstractButton::clicked, this, &TitleWidget::slotUpdateText);
    connect(gradient_color, &QAbstractButton::clicked, this, &TitleWidget::slotUpdateText);
193
    connect(gradients_combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &TitleWidget::slotUpdateText);
194

Laurent Montel's avatar
Laurent Montel committed
195
196
    connect(textOutlineColor, &KColorButton::changed, this, &TitleWidget::slotUpdateText);
    connect(font_family, &QFontComboBox::currentFontChanged, this, &TitleWidget::slotUpdateText);
197
198
199
200
    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);
201
    connect(font_weight_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &TitleWidget::slotUpdateText);
202

Laurent Montel's avatar
Laurent Montel committed
203
204
205
206
    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);
207
    connect(gradients_rect_combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &TitleWidget::rectChanged);
208
    connect(rectLineWidth, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::rectChanged);
209

210
211
212
213
214
    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
215
216
217
218
219
220
    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
221

Laurent Montel's avatar
Laurent Montel committed
222
223
    connect(origin_x_left, &QAbstractButton::clicked, this, &TitleWidget::slotOriginXClicked);
    connect(origin_y_top, &QAbstractButton::clicked, this, &TitleWidget::slotOriginYClicked);
224

225
    connect(monitor, &Monitor::frameUpdated, this, &TitleWidget::slotGotBackground);
226
    connect(this, &TitleWidget::requestBackgroundFrame, monitor, &Monitor::slotGetCurrentImage);
Simon Eugster's avatar
Simon Eugster committed
227

228
    // Position and size
Vincent Pinon's avatar
Vincent Pinon committed
229
230
231
232
    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);});
233

Laurent Montel's avatar
Laurent Montel committed
234
235
236
237
238
239
240
241
242
    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
243
    connect(preserveAspectRatio, static_cast<void (QCheckBox::*)(int)>(&QCheckBox::stateChanged), this, [&] () {
244
245
        slotValueChanged(ValueWidth);
    });
246
247

    displayBg->setChecked(KdenliveSettings::titlerShowbg());
Vincent Pinon's avatar
Vincent Pinon committed
248
    connect(displayBg, static_cast<void (QCheckBox::*)(int)>(&QCheckBox::stateChanged), this, [&] (int state) {
249
250
251
        KdenliveSettings::setTitlerShowbg(state == Qt::Checked);
        displayBackgroundFrame();
    });
252

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

255
    // mbd
Laurent Montel's avatar
Laurent Montel committed
256
    connect(this, &QDialog::accepted, this, &TitleWidget::slotAccepted);
Mads Bondo Dydensborg's avatar
Mads Bondo Dydensborg committed
257

Simon Eugster's avatar
Titler:    
Simon Eugster committed
258
259
260
261
262
263
264
265
266
267
    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);

268
269
270
271
272
273
274
    buttonFitZoom->setIconSize(iconSize);
    buttonRealSize->setIconSize(iconSize);
    buttonItalic->setIconSize(iconSize);
    buttonUnder->setIconSize(iconSize);
    buttonAlignCenter->setIconSize(iconSize);
    buttonAlignLeft->setIconSize(iconSize);
    buttonAlignRight->setIconSize(iconSize);
275

276
277
278
279
280
    if (qApp->isLeftToRight()) {
        buttonAlignRight->setChecked(true);
    } else {
        buttonAlignLeft->setChecked(true);
    }
281

282
    m_unicodeAction = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-insert-unicode")), QString(), this);
283
    m_unicodeAction->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_U);
284
    m_unicodeAction->setToolTip(getTooltipWithShortcut(i18n("Insert Unicode character"), m_unicodeAction));
Laurent Montel's avatar
Laurent Montel committed
285
    connect(m_unicodeAction, &QAction::triggered, this, &TitleWidget::slotInsertUnicode);
286
    buttonInsertUnicode->setDefaultAction(m_unicodeAction);
287

288
    m_zUp = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-up")), QString(), this);
Simon Eugster's avatar
Simon Eugster committed
289
290
    m_zUp->setShortcut(Qt::Key_PageUp);
    m_zUp->setToolTip(i18n("Raise object"));
Laurent Montel's avatar
Laurent Montel committed
291
    connect(m_zUp, &QAction::triggered, this, &TitleWidget::slotZIndexUp);
Simon Eugster's avatar
Simon Eugster committed
292
    zUp->setDefaultAction(m_zUp);
293

294
    m_zDown = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-down")), QString(), this);
Simon Eugster's avatar
Simon Eugster committed
295
296
    m_zDown->setShortcut(Qt::Key_PageDown);
    m_zDown->setToolTip(i18n("Lower object"));
Laurent Montel's avatar
Laurent Montel committed
297
    connect(m_zDown, &QAction::triggered, this, &TitleWidget::slotZIndexDown);
Simon Eugster's avatar
Simon Eugster committed
298
    zDown->setDefaultAction(m_zDown);
299

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

308
    m_zBottom = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-zindex-bottom")), QString(), this);
309
    // TODO mbt 1414
Nicolas Carion's avatar
Nicolas Carion committed
310
    // m_zBottom->setShortcut(Qt::Key_End);
Simon Eugster's avatar
Simon Eugster committed
311
    m_zBottom->setToolTip(i18n("Lower object to bottom"));
Laurent Montel's avatar
Laurent Montel committed
312
    connect(m_zBottom, &QAction::triggered, this, &TitleWidget::slotZIndexBottom);
Simon Eugster's avatar
Simon Eugster committed
313
    zBottom->setDefaultAction(m_zBottom);
314

315
    m_selectAll = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-all")), QString(), this);
316
    m_selectAll->setShortcut(Qt::CTRL + Qt::Key_A);
317
    m_selectAll->setToolTip(i18n("Select All"));
Laurent Montel's avatar
Laurent Montel committed
318
    connect(m_selectAll, &QAction::triggered, this, &TitleWidget::slotSelectAll);
319
    buttonSelectAll->setDefaultAction(m_selectAll);
320

321
    m_selectText = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-texts")), QString(), this);
322
    m_selectText->setShortcut(Qt::CTRL + Qt::Key_T);
323
    m_selectText->setToolTip(i18n("Keep only text items selected"));
Laurent Montel's avatar
Laurent Montel committed
324
    connect(m_selectText, &QAction::triggered, this, &TitleWidget::slotSelectText);
325
    buttonSelectText->setDefaultAction(m_selectText);
326
327
    buttonSelectText->setEnabled(false);

328
    m_selectRects = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-rects")), QString(), this);
329
    m_selectRects->setShortcut(Qt::CTRL + Qt::Key_R);
330
    m_selectRects->setToolTip(i18n("Keep only rect items selected"));
Laurent Montel's avatar
Laurent Montel committed
331
    connect(m_selectRects, &QAction::triggered, this, &TitleWidget::slotSelectRects);
332
    buttonSelectRects->setDefaultAction(m_selectRects);
333
334
    buttonSelectRects->setEnabled(false);

335
    m_selectImages = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-select-images")), QString(), this);
336
    m_selectImages->setShortcut(Qt::CTRL + Qt::Key_I);
337
    m_selectImages->setToolTip(i18n("Keep only image items selected"));
Laurent Montel's avatar
Laurent Montel committed
338
    connect(m_selectImages, &QAction::triggered, this, &TitleWidget::slotSelectImages);
339
    buttonSelectImages->setDefaultAction(m_selectImages);
340
341
    buttonSelectImages->setEnabled(false);

342
    m_unselectAll = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-unselect-all")), QString(), this);
343
    m_unselectAll->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_A);
344
    m_unselectAll->setToolTip(i18n("Deselect"));
Laurent Montel's avatar
Laurent Montel committed
345
    connect(m_unselectAll, &QAction::triggered, this, &TitleWidget::slotSelectNone);
346
    buttonUnselectAll->setDefaultAction(m_unselectAll);
347
    buttonUnselectAll->setEnabled(false);
348

Alberto Villa's avatar
Alberto Villa committed
349
350
351
352
353
354
355
    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"));
356
    backgroundColor->setToolTip(i18n("Select background color"));
Simon Eugster's avatar
Simon Eugster committed
357
    backgroundAlpha->setToolTip(i18n("Background opacity"));
358
359
360
361
362
    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));
363

364
365
366
367
368
369
    itemhcenter->setIconSize(iconSize);
    itemvcenter->setIconSize(iconSize);
    itemtop->setIconSize(iconSize);
    itembottom->setIconSize(iconSize);
    itemright->setIconSize(iconSize);
    itemleft->setIconSize(iconSize);
370

Nicolas Carion's avatar
Nicolas Carion committed
371
    auto *layout = new QHBoxLayout;
372
    frame_toolbar->setLayout(layout);
373
    layout->setContentsMargins(0, 0, 0, 0);
374
    QToolBar *m_toolbar = new QToolBar(QStringLiteral("titleToolBar"), this);
375
    m_toolbar->setIconSize(iconSize);
376

377
    m_buttonCursor = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("transform-move")), i18n("Selection Tool"));
378
379
    m_buttonCursor->setCheckable(true);
    m_buttonCursor->setShortcut(Qt::ALT + Qt::Key_S);
Laurent Montel's avatar
Laurent Montel committed
380
    m_buttonCursor->setToolTip(i18n("Selection Tool") + QLatin1Char(' ') + m_buttonCursor->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
381
    connect(m_buttonCursor, &QAction::triggered, this, &TitleWidget::slotSelectTool);
382

383
    m_buttonText = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("insert-text")), i18n("Add Text"));
384
    m_buttonText->setCheckable(true);
Alberto Villa's avatar
Alberto Villa committed
385
    m_buttonText->setShortcut(Qt::ALT + Qt::Key_T);
Laurent Montel's avatar
Laurent Montel committed
386
    m_buttonText->setToolTip(i18n("Add Text") + QLatin1Char(' ') + m_buttonText->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
387
    connect(m_buttonText, &QAction::triggered, this, &TitleWidget::slotTextTool);
388

389
    m_buttonRect = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("kdenlive-insert-rect")), i18n("Add Rectangle"));
390
391
    m_buttonRect->setCheckable(true);
    m_buttonRect->setShortcut(Qt::ALT + Qt::Key_R);
Laurent Montel's avatar
Laurent Montel committed
392
    m_buttonRect->setToolTip(i18n("Add Rectangle") + QLatin1Char(' ') + m_buttonRect->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
393
    connect(m_buttonRect, &QAction::triggered, this, &TitleWidget::slotRectTool);
394

Julius Künzel's avatar
Julius Künzel committed
395
396
397
398
399
400
    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);

401
    m_buttonImage = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("insert-image")), i18n("Add Image"));
402
    m_buttonImage->setCheckable(false);
Alberto Villa's avatar
Alberto Villa committed
403
    m_buttonImage->setShortcut(Qt::ALT + Qt::Key_I);
Laurent Montel's avatar
Laurent Montel committed
404
    m_buttonImage->setToolTip(i18n("Add Image") + QLatin1Char(' ') + m_buttonImage->shortcut().toString());
Laurent Montel's avatar
Laurent Montel committed
405
    connect(m_buttonImage, &QAction::triggered, this, &TitleWidget::slotImageTool);
406

Simon Eugster's avatar
Simon Eugster committed
407
    m_toolbar->addSeparator();
408

409
    m_buttonLoad = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("document-open")), i18n("Open Document"));
410
    m_buttonLoad->setCheckable(false);
Alberto Villa's avatar
Alberto Villa committed
411
    m_buttonLoad->setShortcut(Qt::CTRL + Qt::Key_O);
Laurent Montel's avatar
Laurent Montel committed
412
    m_buttonLoad->setToolTip(i18n("Open Document") + QLatin1Char(' ') + m_buttonLoad->shortcut().toString());
413
    connect(m_buttonLoad, SIGNAL(triggered()), this, SLOT(loadTitle()));    
414

415
    m_buttonSave = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("document-save-as")), i18n("Save As"));
416
    m_buttonSave->setCheckable(false);
Alberto Villa's avatar
Alberto Villa committed
417
    m_buttonSave->setShortcut(Qt::CTRL + Qt::Key_S);
Laurent Montel's avatar
Laurent Montel committed
418
    m_buttonSave->setToolTip(i18n("Save As") + QLatin1Char(' ') + m_buttonSave->shortcut().toString());
419
420
    connect(m_buttonSave, SIGNAL(triggered()), this, SLOT(saveTitle()));

421
422
423
424
425
426
    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);

427
    layout->addWidget(m_toolbar);
428

429
    // initialize graphic scene
430
    m_scene = new GraphicsSceneRectMove(this);
431
    graphicsView->setScene(m_scene);
432
    graphicsView->setMouseTracking(true);
433
    graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
434
435
    graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
    graphicsView->setRubberBandSelectionMode(Qt::ContainsItemBoundingRect);
436
    m_titledocument.setScene(m_scene, m_frameWidth, m_frameHeight);
Laurent Montel's avatar
Laurent Montel committed
437
    connect(m_scene, &QGraphicsScene::changed, this, &TitleWidget::slotChanged);
438
    connect(font_size, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), m_scene, &GraphicsSceneRectMove::slotUpdateFontSize);
Laurent Montel's avatar
Laurent Montel committed
439
    connect(use_grid, &QAbstractButton::toggled, m_scene, &GraphicsSceneRectMove::slotUseGrid);
440

441
442
    // Video frame rect
    QPen framepen;
443
444
445
    framepen.setColor(Qt::red);
    m_frameBorder = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
    m_frameBorder->setPen(framepen);
446
    m_frameBorder->setZValue(1000);
447
    m_frameBorder->setBrush(Qt::transparent);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
448
    m_frameBorder->setData(-1, -1);
449
    graphicsView->scene()->addItem(m_frameBorder);
450

451
    // Guides
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
452
453
    connect(show_guides, &QCheckBox::stateChanged, this, &TitleWidget::showGuides);
    show_guides->setChecked(KdenliveSettings::titlerShowGuides());
454
455
    hguides->setValue(KdenliveSettings::titlerHGuides());
    vguides->setValue(KdenliveSettings::titlerVGuides());
456
457
    guideColor->setColor(KdenliveSettings::titleGuideColor());
    connect(guideColor, &KColorButton::changed, this, &TitleWidget::guideColorChanged);
458
459
460
    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
461

462
    // semi transparent safe zones
463
    framepen.setColor(QColor(255, 0, 0, 100));
464
465
466
    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
467
    safe1->setData(-1, -1);
468
469
470
    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
471
    safe2->setData(-1, -1);
472
473
474
475
476
477

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

478
479
480
481
482
483
484
485
    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);

486
    bgBox->setCurrentIndex(KdenliveSettings::titlerbg());
Vincent Pinon's avatar
Vincent Pinon committed
487
    connect(bgBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [&] (int ix) {
488
489
490
491
        KdenliveSettings::setTitlerbg(ix);
        displayBackgroundFrame();
    });

Laurent Montel's avatar
Laurent Montel committed
492
493
494
495
496
    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
497
    connect(m_scene, &GraphicsSceneRectMove::newEllipse, this, &TitleWidget::slotNewEllipse);
Laurent Montel's avatar
Laurent Montel committed
498
499
    connect(m_scene, &GraphicsSceneRectMove::newText, this, &TitleWidget::slotNewText);
    connect(zoom_slider, &QAbstractSlider::valueChanged, this, &TitleWidget::slotUpdateZoom);
500
    connect(zoom_spin, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TitleWidget::slotUpdateZoom);
501

502
    // mbd: load saved settings
503
    loadGradients();
504
    readChoices();
Mads Bondo Dydensborg's avatar
Mads Bondo Dydensborg committed
505

506
507
    graphicsView->show();
    graphicsView->setInteractive(true);
Nicolas Carion's avatar
Nicolas Carion committed
508
    // qCDebug(KDENLIVE_LOG) << "// TITLE WIDGWT: " << graphicsView->viewport()->width() << 'x' << graphicsView->viewport()->height();
509
    m_startViewport = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
510
511
    // Setting data at -1 so that the item is recognized as undeletable by graphicsscenerectmove
    m_startViewport->setData(-1, -1);
512
    m_endViewport = new QGraphicsRectItem(QRectF(0, 0, m_frameWidth, m_frameHeight));
513
    m_endViewport->setData(-1, -1);
514
515
516
517
    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
518

519
520
    // scale the view so that the title widget is not too big at startup
    graphicsView->scale(.5, .5);
521
    if (url.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
522
523
        loadTitle(url);
    } else {
Laurent Montel's avatar
Laurent Montel committed
524
        prepareTools(nullptr);
Laurent Montel's avatar
Laurent Montel committed
525
        slotTextTool();
Laurent Montel's avatar
Laurent Montel committed
526
        QTimer::singleShot(200, this, &TitleWidget::slotAdjustZoom);
527
    }
528
    initAnimation();
529
530
531
532
    QColor color = backgroundColor->color();
    m_scene->setBackgroundBrush(QBrush(color));
    color.setAlpha(backgroundAlpha->value());
    m_frameBackground->setBrush(color);
Laurent Montel's avatar
Laurent Montel committed
533
534
    connect(anim_start, &QAbstractButton::toggled, this, &TitleWidget::slotAnimStart);
    connect(anim_end, &QAbstractButton::toggled, this, &TitleWidget::slotAnimEnd);
535
    connect(templateBox, SIGNAL(currentIndexChanged(int)), this, SLOT(templateIndexChanged(int)));
536

537
    createButton->setEnabled(KdenliveSettings::hastitleproducer());
538
    auto *addMenu = new QMenu(this);
539
540
541
    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
542
    connect(addMenu, &QMenu::triggered, this, [this]() {
543
544
545
546
547
548
549
        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
550
    connect(m_createTitleAction, &QAction::triggered, this, [this]() {
551
552
        done(QDialog::Accepted);
    });
Vincent Pinon's avatar
Vincent Pinon committed
553
    connect(cancelButton, &QPushButton::clicked, this, [this]() {
554
555
        done(QDialog::Rejected);
    });
556
557
    refreshTitleTemplates(m_projectTitlePath);

558
559
560
561
562
563
564
565
566
567
568
    // 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
569
    connect(btn_removeAll, &QToolButton::clicked, this,
570
            [&] () {
Julius Künzel's avatar
Julius Künzel committed
571
572
573
574
        m_patternsModel->removeAll();
        btn_remove->setEnabled(false);
        btn_removeAll->setEnabled(false);
    });
575
576
577
578
579
580
581
582
583

    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
584
    // templateBox->setIconSize(QSize(60,60));
585
    refreshTemplateBoxContents();
Nicolas Carion's avatar
Nicolas Carion committed
586
    m_lastDocumentHash = QCryptographicHash::hash(xml().toString().toLatin1(), QCryptographicHash::Md5).toHex();
Marco Gittler's avatar
Marco Gittler committed
587
}
588

589
590
TitleWidget::~TitleWidget()
{
591
592
593
    writePatterns();
    delete m_patternsModel;

594
    m_scene->blockSignals(true);
595
    delete m_buttonRect;
Julius Künzel's avatar
Julius Künzel committed
596
    delete m_buttonEllipse;
597
598
599
600
601
    delete m_buttonText;
    delete m_buttonImage;
    delete m_buttonCursor;
    delete m_buttonSave;
    delete m_buttonLoad;
602
    delete m_unicodeAction;
Simon Eugster's avatar
Simon Eugster committed
603
604
605
606
    delete m_zUp;
    delete m_zDown;
    delete m_zTop;
    delete m_zBottom;
607
608
609
610
611
    delete m_selectAll;
    delete m_selectText;
    delete m_selectRects;
    delete m_selectImages;
    delete m_unselectAll;
612

Alberto Villa's avatar
Alberto Villa committed
613
    delete m_unicodeDialog;
614
615
    delete m_frameBorder;
    delete m_frameImage;
616
617
    delete m_startViewport;
    delete m_endViewport;
618
619
620
    delete m_scene;
}

621
// static
Laurent Montel's avatar
Laurent Montel committed
622
QStringList TitleWidget::extractImageList(const QString &xml)
623
624
{
    QStringList result;
Laurent Montel's avatar
Laurent Montel committed
625
626
627
    if (xml.isEmpty()) {
        return result;
    }
628
629
    QDomDocument doc;
    doc.setContent(xml);
630
    QDomNodeList images = doc.elementsByTagName(QStringLiteral("content"));
631
    for (int i = 0; i < images.count(); ++i) {
Laurent Montel's avatar
Laurent Montel committed
632
        if (images.at(i).toElement().hasAttribute(QStringLiteral("url"))) {
633
            result.append(images.at(i).toElement().attribute(QStringLiteral("url")));
Laurent Montel's avatar
Laurent Montel committed
634
        }
635
636
637
638
    }
    return result;
}

639
// static
Laurent Montel's avatar
Laurent Montel committed
640
QStringList TitleWidget::extractFontList(const QString &xml)
641
642
{
    QStringList result;
Laurent Montel's avatar
Laurent Montel committed
643
644
645
    if (xml.isEmpty()) {
        return result;
    }
646
647
    QDomDocument doc;
    doc.setContent(xml);
648
    QDomNodeList images = doc.elementsByTagName(QStringLiteral("content"));
649
    for (int i = 0; i < images.count(); ++i) {
Laurent Montel's avatar
Laurent Montel committed
650
        if (images.at(i).toElement().hasAttribute(QStringLiteral("font"))) {
651
            result.append(images.at(i).toElement().attribute(QStringLiteral("font")));
Laurent Montel's avatar
Laurent Montel committed
652
        }
653
654
655
    }
    return result;
}
Nicolas Carion's avatar
Nicolas Carion committed
656
// static
657
void TitleWidget::refreshTitleTemplates(const QString &projectPath)
658
{
Laurent Montel's avatar
Laurent Montel committed
659
    QStringList filters = QStringList() << QStringLiteral("*.kdenlivetitle");
660
    titleTemplates.clear();
661
662
663
664

    // project templates
    QDir dir(projectPath);
    QStringList templateFiles = dir.entryList(filters, QDir::Files);
Vincent Pinon's avatar
Vincent Pinon committed
665
    for (const QString &fname : qAsConst(templateFiles)) {
666
        TitleTemplate t;
Laurent Montel's avatar
Laurent Montel committed
667
668
        t.name = fname;
        t.file = dir.absoluteFilePath(fname);
669
        t.icon = QIcon(KThumb::getImage(QUrl::fromLocalFile(t.file), 0, 60, -1));
670
        titleTemplates.append(t);
671
672
673
    }

    // system templates
674
675
676
    QStringList currentTitleTemplates = QStandardPaths::locateAll(QStandardPaths::AppLocalDataLocation, QStringLiteral("titles/"), QStandardPaths::LocateDirectory);
    currentTitleTemplates.removeDuplicates();
    for (const QString &folderpath : qAsConst(currentTitleTemplates)) {
677
        QDir folder(folderpath);
678
        QStringList filesnames = folder.entryList(filters, QDir::Files);
Vincent Pinon's avatar
Vincent Pinon committed
679
        for (const QString &fname : qAsConst(filesnames)) {
680
681
            TitleTemplate t;
            t.name = fname;
682
            t.file = folder.absoluteFilePath(fname);
683
            t.icon = QIcon(KThumb::getImage(QUrl::fromLocalFile(t.file), 0, 60, -1));
684
            titleTemplates.append(t);
685
686
687
        }
    }
}
Laurent Montel's avatar
Laurent Montel committed
688

689
void TitleWidget::templateIndexChanged(int index)
690
{
691
    QString item = templateBox->itemData(index).toString();
692
    if (!item.isEmpty()) {
Nicolas Carion's avatar
Nicolas Carion committed
693
        if (m_lastDocumentHash != QCryptographicHash::hash(xml().toString().toLatin1(), QCryptographicHash::Md5).toHex()) {
Laurent Montel's avatar
Laurent Montel committed
694
            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
695
                return;
Laurent Montel's avatar
Laurent Montel committed
696
            }
697
        }
698
        loadTitle(QUrl::fromLocalFile(item));
699
700
701
702

        // 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
703
        for (QGraphicsItem *qgItem : qAsConst(list)) {
704
            if (qgItem->type() == TEXTITEM) {
Nicolas Carion's avatar
Nicolas Carion committed
705
                auto *i = static_cast<MyTextItem *>(qgItem);
706
707
708
709
                i->setProperty("isTemplate", "true");
                i->setProperty("templateText", i->toHtml());
            }
        }
Nicolas Carion's avatar
Nicolas Carion committed
710
        m_lastDocumentHash = QCryptographicHash::hash(xml().toString().toLatin1(), QCryptographicHash::Md5).toHex();
711
    }
712
}
Nicolas Carion's avatar
Nicolas Carion committed
713
// virtual
714
715
void TitleWidget::resizeEvent(QResizeEvent * /*event*/)
{
Nicolas Carion's avatar
Nicolas Carion committed
716
    // slotAdjustZoom();
717
}
Nicolas Carion's avatar
Nicolas Carion committed
718
// virtual
Laurent Montel's avatar
Laurent Montel committed
719
720
void TitleWidget::keyPressEvent(QKeyEvent *e)
{
Laurent Montel's avatar
Laurent Montel committed
721
722
723
    if (e->key() != Qt::Key_Escape && e->key() != Qt::Key_Return && e->key() != Qt::Key_Enter) {
        QDialog::keyPressEvent(e);
    }
724
}
Laurent Montel's avatar
Laurent Montel committed
725

726
727
void TitleWidget::slotTextTool()
{
728
    m_scene->setTool(TITLE_TEXT);
Simon Eugster's avatar
Simon Eugster committed
729
    showToolbars(TITLE_TEXT);
Simon Eugster's avatar
Simon Eugster committed