1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "contextpanewidgetimage.h"
27
28 #include "ui_contextpanewidgetimage.h"
29 #include "ui_contextpanewidgetborderimage.h"
30 #include <qmljs/qmljspropertyreader.h>
31 #include <QFile>
32 #include <QFileInfo>
33 #include <QDir>
34 #include <QPixmap>
35 #include <QPainter>
36 #include <QGraphicsEffect>
37 #include <QMouseEvent>
38 #include <QScrollArea>
39 #include <QSlider>
40 #include <QStyle>
41 #include <QToolButton>
42 #include <QDebug>
43
44 namespace QmlEditorWidgets {
45
eventFilter(QObject * obj,QEvent * event)46 bool LabelFilter::eventFilter(QObject *obj, QEvent *event)
47 {
48 if (event->type() == QEvent::MouseButtonDblClick) {
49 emit doubleClicked();
50 event->accept();
51 return true;
52 }
53 return QObject::eventFilter(obj, event);
54 }
55
eventFilter(QObject * obj,QEvent * event)56 bool WheelFilter::eventFilter(QObject *obj, QEvent *event)
57 {
58 if (event->type() == QEvent::Wheel) {
59 if (obj
60 && obj->isWidgetType()
61 && obj != m_target) {
62 QApplication::sendEvent(m_target, event);
63 return true;
64 }
65 }
66 return QObject::eventFilter(obj, event);
67 }
68
ContextPaneWidgetImage(QWidget * parent,bool borderImage)69 ContextPaneWidgetImage::ContextPaneWidgetImage(QWidget *parent, bool borderImage) :
70 QWidget(parent),
71 ui(nullptr), uiBorderImage(nullptr), previewWasVisible(false)
72 {
73 LabelFilter *labelFilter = new LabelFilter(this);
74
75 m_borderImage = borderImage;
76
77 if (m_borderImage) {
78 uiBorderImage = new Ui::ContextPaneWidgetBorderImage;
79 uiBorderImage->setupUi(this);
80 m_fileWidget = uiBorderImage->fileWidget;
81 m_sizeLabel = uiBorderImage->sizeLabel;
82 uiBorderImage->label->setToolTip(tr("Double click for preview."));
83 uiBorderImage->label->installEventFilter(labelFilter);
84
85
86 connect(uiBorderImage->verticalTileRadioButton, &QRadioButton::toggled,
87 this, &ContextPaneWidgetImage::onVerticalStretchChanged);
88 connect(uiBorderImage->verticalStretchRadioButton, &QRadioButton::toggled,
89 this, &ContextPaneWidgetImage::onVerticalStretchChanged);
90 connect(uiBorderImage->verticalTileRadioButtonNoCrop, &QRadioButton::toggled,
91 this, &ContextPaneWidgetImage::onVerticalStretchChanged);
92
93 connect(uiBorderImage->horizontalTileRadioButton, &QRadioButton::toggled,
94 this, &ContextPaneWidgetImage::onHorizontalStretchChanged);
95 connect(uiBorderImage->horizontalStretchRadioButton, &QRadioButton::toggled,
96 this, &ContextPaneWidgetImage::onHorizontalStretchChanged);
97 connect(uiBorderImage->horizontalTileRadioButtonNoCrop, &QRadioButton::toggled,
98 this, &ContextPaneWidgetImage::onHorizontalStretchChanged);
99 PreviewLabel *previewLabel = previewDialog()->previewLabel();
100 connect(previewLabel, &PreviewLabel::leftMarginChanged,
101 this, &ContextPaneWidgetImage::onLeftMarginsChanged);
102 connect(previewLabel, &PreviewLabel::rightMarginChanged,
103 this, &ContextPaneWidgetImage::onRightMarginsChanged);
104 connect(previewLabel, &PreviewLabel::topMarginChanged,
105 this, &ContextPaneWidgetImage::onTopMarginsChanged);
106 connect(previewLabel, &PreviewLabel::bottomMarginChanged,
107 this, &ContextPaneWidgetImage::onBottomMarginsChanged);
108
109 } else {
110 ui = new Ui::ContextPaneWidgetImage;
111 ui->setupUi(this);
112 ui->label->setToolTip(tr("Double click for preview."));
113 ui->label->installEventFilter(labelFilter);
114 m_fileWidget = ui->fileWidget;
115 m_sizeLabel = ui->sizeLabel;
116
117 connect(ui->stretchRadioButton, &QRadioButton::toggled,
118 this, &ContextPaneWidgetImage::onStretchChanged);
119 connect(ui->tileRadioButton, &QRadioButton::toggled,
120 this, &ContextPaneWidgetImage::onStretchChanged);
121 connect(ui->horizontalStretchRadioButton, &QRadioButton::toggled,
122 this, &ContextPaneWidgetImage::onStretchChanged);
123 connect(ui->verticalStretchRadioButton, &QRadioButton::toggled,
124 this, &ContextPaneWidgetImage::onStretchChanged);
125 connect(ui->preserveAspectFitRadioButton, &QRadioButton::toggled,
126 this, &ContextPaneWidgetImage::onStretchChanged);
127 connect(ui->cropAspectFitRadioButton, &QRadioButton::toggled,
128 this, &ContextPaneWidgetImage::onStretchChanged);
129 }
130 previewDialog();
131 m_fileWidget->setShowComboBox(true);
132 m_fileWidget->setFilter(QLatin1String("*.png *.gif *.jpg"));
133
134 connect(m_fileWidget, &FileWidget::fileNameChanged,
135 this, &ContextPaneWidgetImage::onFileNameChanged);
136 connect(labelFilter, &LabelFilter::doubleClicked,
137 this, &ContextPaneWidgetImage::onPixmapDoubleClicked);
138
139 }
140
~ContextPaneWidgetImage()141 ContextPaneWidgetImage::~ContextPaneWidgetImage()
142 {
143 if (ui)
144 delete ui;
145 if (uiBorderImage)
146 delete uiBorderImage;
147 }
148
setProperties(QmlJS::PropertyReader * propertyReader)149 void ContextPaneWidgetImage::setProperties(QmlJS::PropertyReader *propertyReader)
150 {
151 if (m_borderImage) {
152
153 int leftBorder = 0;
154 int rightBorder = 0;
155 int topBorder = 0;
156 int bottomBorder = 0;
157
158 if (propertyReader->hasProperty(QLatin1String("border.left")))
159 leftBorder =propertyReader->readProperty(QLatin1String("border.left")).toInt();
160 if (propertyReader->hasProperty(QLatin1String("border.right")))
161 rightBorder =propertyReader->readProperty(QLatin1String("border.right")).toInt();
162 if (propertyReader->hasProperty(QLatin1String("border.top")))
163 topBorder =propertyReader->readProperty(QLatin1String("border.top")).toInt();
164 if (propertyReader->hasProperty(QLatin1String("border.bottom")))
165 bottomBorder =propertyReader->readProperty(QLatin1String("border.bottom")).toInt();
166 previewDialog()->previewLabel()->setMargins(leftBorder, topBorder, rightBorder, bottomBorder);
167
168 if (propertyReader->hasProperty(QLatin1String("horizontalTileMode"))) {
169 QString fillMode = propertyReader->readProperty(QLatin1String("horizontalTileMode")).toString();
170 if (fillMode.contains(QLatin1String("BorderImage.")))
171 fillMode.remove(QLatin1String("BorderImage."));
172
173 uiBorderImage->horizontalStretchRadioButton->setChecked(true);
174
175 if (fillMode == QLatin1String("Stretch"))
176 uiBorderImage->horizontalStretchRadioButton->setChecked(true);
177 if (fillMode == QLatin1String("Repeat"))
178 uiBorderImage->horizontalTileRadioButton->setChecked(true);
179 if (fillMode == QLatin1String("Round"))
180 uiBorderImage->horizontalTileRadioButtonNoCrop->setChecked(true);
181 } else {
182 //uiBorderImage
183 uiBorderImage->horizontalStretchRadioButton->setChecked(true);
184 }
185 if (propertyReader->hasProperty(QLatin1String("verticalTileMode"))) {
186 QString fillMode = propertyReader->readProperty(QLatin1String("verticalTileMode")).toString();
187 if (fillMode.contains(QLatin1String("BorderImage.")))
188 fillMode.remove(QLatin1String("BorderImage."));
189
190 uiBorderImage->verticalStretchRadioButton->setChecked(true);
191
192 if (fillMode == QLatin1String("Stretch"))
193 uiBorderImage->verticalStretchRadioButton->setChecked(true);
194 if (fillMode == QLatin1String("Repeat"))
195 uiBorderImage->verticalTileRadioButton->setChecked(true);
196 if (fillMode == QLatin1String("Round"))
197 uiBorderImage->verticalTileRadioButtonNoCrop->setChecked(true);
198 } else {
199 //uiBorderImage
200 uiBorderImage->verticalStretchRadioButton->setChecked(true);
201 }
202 } else {
203 if (propertyReader->hasProperty(QLatin1String("fillMode"))) {
204 QString fillMode = propertyReader->readProperty(QLatin1String("fillMode")).toString();
205 if (fillMode.contains(QLatin1String("Image.")))
206 fillMode.remove(QLatin1String("Image."));
207
208 ui->stretchRadioButton->setChecked(true);
209
210 if (fillMode == QLatin1String("Image.Tile") || fillMode == QLatin1String("Tile"))
211 ui->tileRadioButton->setChecked(true);
212 if (fillMode == QLatin1String("Image.TileVertically") || fillMode == QLatin1String("TileVertically"))
213 ui->horizontalStretchRadioButton->setChecked(true);
214 if (fillMode == QLatin1String("Image.TileHorizontally") || fillMode == QLatin1String("TileHorizontally"))
215 ui->verticalStretchRadioButton->setChecked(true);
216 if (fillMode == QLatin1String("Image.PreserveAspectFit") || fillMode == QLatin1String("PreserveAspectFit"))
217 ui->preserveAspectFitRadioButton->setChecked(true);
218 if (fillMode == QLatin1String("Image.PreserveAspectCrop") || fillMode == QLatin1String("PreserveAspectCrop"))
219 ui->cropAspectFitRadioButton->setChecked(true);
220 } else {
221 ui->stretchRadioButton->setChecked(true);
222 }
223 }
224 if (propertyReader->hasProperty(QLatin1String("source"))) {
225 QString source = propertyReader->readProperty(QLatin1String("source")).toString();
226 m_fileWidget->setFileName(source);
227 if (QFile::exists(m_path + QLatin1Char('/') + source))
228 setPixmap(m_path + QLatin1Char('/') + source);
229 else
230 setPixmap(source);
231 } else {
232 m_sizeLabel->clear();
233 m_fileWidget->setFileName(QUrl());
234 setPixmap(QString());
235 }
236 }
237
setPath(const QString & path)238 void ContextPaneWidgetImage::setPath(const QString& path)
239 {
240 m_path = path;
241 m_fileWidget->setPath(QUrl::fromLocalFile(m_path));
242 }
243
setZoom(int z)244 void PreviewDialog::setZoom(int z)
245 {
246 m_zoom = z;
247 m_label->setZoom(z);
248 switch (m_zoom) {
249 case 1:
250 m_zoomLabel->setText(QLatin1String("100%"));
251 m_slider->setValue(1);
252 break;
253 case 2:
254 m_zoomLabel->setText(QLatin1String("200%"));
255 m_slider->setValue(2);
256 break;
257 case 4:
258 m_zoomLabel->setText(QLatin1String("400%"));
259 m_slider->setValue(3);
260 break;
261 case 6:
262 m_zoomLabel->setText(QLatin1String("600%"));
263 m_slider->setValue(4);
264 break;
265 case 8:
266 m_zoomLabel->setText(QLatin1String("800%"));
267 m_slider->setValue(5);
268 break;
269 case 10:
270 m_zoomLabel->setText(QLatin1String("1000%"));
271 m_slider->setValue(6);
272 break;
273 default: break;
274 }
275 setPixmap(m_pixmap, m_zoom);
276 }
277
setIsBorderImage(bool b)278 void PreviewDialog::setIsBorderImage(bool b)
279 {
280 m_borderImage = b;
281 m_label->setIsBorderImage(b);
282 }
283
previewLabel() const284 PreviewLabel *PreviewDialog::previewLabel() const
285 {
286 return m_label;
287 }
288
onStretchChanged()289 void ContextPaneWidgetImage::onStretchChanged()
290 {
291 QString stretch;
292 if (ui->stretchRadioButton->isChecked())
293 stretch = QLatin1String("Image.Stretch");
294 else if (ui->tileRadioButton->isChecked())
295 stretch = QLatin1String("Image.Tile");
296 else if (ui->horizontalStretchRadioButton->isChecked())
297 stretch = QLatin1String("Image.TileVertically");
298 else if (ui->verticalStretchRadioButton->isChecked())
299 stretch = QLatin1String("Image.TileHorizontally");
300 else if (ui->preserveAspectFitRadioButton->isChecked())
301 stretch = QLatin1String("Image.PreserveAspectFit");
302 else if (ui->cropAspectFitRadioButton->isChecked())
303 stretch = QLatin1String("Image.PreserveAspectCrop");
304
305 if (stretch == QLatin1String("Image.Stretch"))
306 emit removeProperty(QLatin1String("fillMode"));
307 else
308 emit propertyChanged(QLatin1String("fillMode"), stretch);
309 }
310
onHorizontalStretchChanged()311 void ContextPaneWidgetImage::onHorizontalStretchChanged()
312 {
313 QString stretch;
314 if (uiBorderImage->horizontalStretchRadioButton->isChecked())
315 stretch = QLatin1String("BorderImage.Stretch");
316 if (uiBorderImage->horizontalTileRadioButton->isChecked())
317 stretch = QLatin1String("BorderImage.Repeat");
318 if (uiBorderImage->horizontalTileRadioButtonNoCrop->isChecked())
319 stretch = QLatin1String("BorderImage.Round");
320
321 if (stretch == QLatin1String("BorderImage.Stretch"))
322 emit removeProperty(QLatin1String("horizontalTileMode"));
323 else
324 emit propertyChanged(QLatin1String("horizontalTileMode"), stretch);
325 }
326
onVerticalStretchChanged()327 void ContextPaneWidgetImage::onVerticalStretchChanged()
328 {
329 QString stretch;
330 if (uiBorderImage->verticalStretchRadioButton->isChecked())
331 stretch = QLatin1String("BorderImage.Stretch");
332 if (uiBorderImage->verticalTileRadioButton->isChecked())
333 stretch = QLatin1String("BorderImage.Repeat");
334 if (uiBorderImage->verticalTileRadioButtonNoCrop->isChecked())
335 stretch = QLatin1String("BorderImage.Round");
336
337 if (stretch == QLatin1String("BorderImage.Stretch"))
338 emit removeProperty(QLatin1String("verticalTileMode"));
339 else
340 emit propertyChanged(QLatin1String("verticalTileMode"), stretch);
341
342 }
343
onFileNameChanged()344 void ContextPaneWidgetImage::onFileNameChanged()
345 {
346 if (m_fileWidget->fileName().isNull())
347 emit removeProperty(QLatin1String("source"));
348 else
349 emit propertyChanged(QLatin1String("source"), QString(QLatin1Char('\"') + m_fileWidget->fileName() + QLatin1Char('\"')));
350 }
351
onPixmapDoubleClicked()352 void ContextPaneWidgetImage::onPixmapDoubleClicked()
353 {
354 previewDialog()->setParent(parentWidget()->parentWidget());
355 previewDialog()->setMaximumSize(previewDialog()->parentWidget()->size() - QSize(150, 100));
356 if (m_borderImage)
357 previewDialog()->setZoom(4);
358 previewDialog()->setIsBorderImage(m_borderImage);
359
360 QPoint p = parentWidget()->pos();
361 p = p + QPoint(-2, -2);
362 previewDialog()->show();
363 previewDialog()->update();
364 previewDialog()->move(p);
365 //previewDialog()->adjustSize();
366 if ((previewDialog()->pos().x() + previewDialog()->width()) > previewDialog()->parentWidget()->width())
367 previewDialog()->move(previewDialog()->parentWidget()->width() - (previewDialog()->width()) - 40, p.y());
368
369 if ((previewDialog()->pos().y() + previewDialog()->height()) > previewDialog()->parentWidget()->height())
370 previewDialog()->move(previewDialog()->pos().x(), previewDialog()->parentWidget()->height() - (previewDialog()->height()) - 40);
371
372 if (previewDialog()->pos().x() < 0)
373 previewDialog()->move(0, previewDialog()->pos().y());
374 if (previewDialog()->pos().y() < 0)
375 previewDialog()->move(previewDialog()->pos().x(), 0);
376
377 previewDialog()->raise();
378 }
379
onLeftMarginsChanged()380 void ContextPaneWidgetImage::onLeftMarginsChanged()
381 {
382 if (previewDialog()->previewLabel()->leftMarging())
383 emit propertyChanged("border.left", previewDialog()->previewLabel()->leftMarging());
384 else
385 emit removeProperty(QLatin1String("border.left"));
386 }
387
onRightMarginsChanged()388 void ContextPaneWidgetImage::onRightMarginsChanged()
389 {
390 if (previewDialog()->previewLabel()->rightMarging())
391 emit propertyChanged("border.right", previewDialog()->previewLabel()->rightMarging());
392 else
393 emit removeProperty(QLatin1String("border.right"));
394
395
396 }
397
onTopMarginsChanged()398 void ContextPaneWidgetImage::onTopMarginsChanged()
399 {
400 if (previewDialog()->previewLabel()->topMarging())
401 emit propertyChanged("border.top", previewDialog()->previewLabel()->topMarging());
402 else
403 emit removeProperty(QLatin1String("border.top"));
404 }
405
onBottomMarginsChanged()406 void ContextPaneWidgetImage::onBottomMarginsChanged()
407 {
408 if (previewDialog()->previewLabel()->bottomMarging())
409 emit propertyChanged("border.bottom", previewDialog()->previewLabel()->bottomMarging());
410 else
411 emit removeProperty(QLatin1String("border.bottom"));
412
413 }
414
stringToRule(const QString & s)415 static inline Qt::TileRule stringToRule(const QString &s)
416 {
417 if (s == QLatin1String("Stretch"))
418 return Qt::StretchTile;
419 if (s == QLatin1String("Repeat"))
420 return Qt::RepeatTile;
421 if (s == QLatin1String("Round"))
422 return Qt::RoundTile;
423
424 qWarning("QDeclarativeGridScaledImage: Invalid tile rule specified. Using Stretch.");
425 return Qt::StretchTile;
426 }
427
parseSciFile(const QString & fileName,QString & pixmapFileName,int & left,int & right,int & top,int & bottom,Qt::TileRule & horizontalTileRule,Qt::TileRule & verticalTileRule)428 static inline bool parseSciFile(const QString &fileName, QString &pixmapFileName, int &left, int &right, int &top, int &bottom, Qt::TileRule &horizontalTileRule, Qt::TileRule &verticalTileRule)
429 {
430 int l = -1;
431 int r = -1;
432 int t = -1;
433 int b = -1;
434 QString imgFile;
435
436 QFile data(fileName);
437 if (!data.open(QIODevice::ReadOnly))
438 return false;
439
440 QByteArray raw;
441 while (raw = data.readLine(), !raw.isEmpty()) {
442 QString line = QString::fromUtf8(raw.trimmed());
443 if (line.isEmpty() || line.startsWith(QLatin1Char('#')))
444 continue;
445
446 QStringList list = line.split(QLatin1Char(':'));
447 if (list.count() != 2)
448 return false;
449
450 list[0] = list[0].trimmed();
451 list[1] = list[1].trimmed();
452
453 if (list[0] == QLatin1String("border.left"))
454 l = list[1].toInt();
455 else if (list[0] == QLatin1String("border.right"))
456 r = list[1].toInt();
457 else if (list[0] == QLatin1String("border.top"))
458 t = list[1].toInt();
459 else if (list[0] == QLatin1String("border.bottom"))
460 b = list[1].toInt();
461 else if (list[0] == QLatin1String("source"))
462 imgFile = list[1];
463 else if (list[0] == QLatin1String("horizontalTileRule"))
464 horizontalTileRule = stringToRule(list[1]);
465 else if (list[0] == QLatin1String("verticalTileRule"))
466 verticalTileRule = stringToRule(list[1]);
467 }
468
469 if (l < 0 || r < 0 || t < 0 || b < 0 || imgFile.isEmpty())
470 return false;
471
472 left = l; right = r; top = t; bottom = b;
473
474 pixmapFileName = imgFile;
475
476 return true;
477 }
478
setPixmap(const QString & fileName)479 void ContextPaneWidgetImage::setPixmap(const QString &fileName)
480 {
481 QPixmap pix(76,76);
482 pix.fill(Qt::black);
483
484 if (m_borderImage) {
485 QString localFileName(fileName);
486 if (QFileInfo::exists(fileName)) {
487 if (fileName.endsWith(QLatin1String("sci"))) {
488 QString pixmapFileName;
489 int left = 0;
490 int right = 0;
491 int top = 0;
492 int bottom = 0;
493
494 Qt::TileRule horizontalTileRule;
495 Qt::TileRule verticalTileRule;
496 if (parseSciFile(fileName, pixmapFileName, left, right, top, bottom, horizontalTileRule, verticalTileRule)) {
497 localFileName = QFileInfo(fileName).absoluteDir().absolutePath() + QLatin1Char('/') + pixmapFileName;
498 previewDialog()->previewLabel()->setMargins(left, top, right, bottom);
499 } else { // sci file not parsed correctly
500 uiBorderImage->sizeLabel->clear();
501 return;
502 }
503 }
504 QPixmap source(localFileName);
505 if (source.isNull())
506 source = pix;
507 previewDialog()->setPixmap(source, previewDialog()->zoom());
508 uiBorderImage->sizeLabel->setText(QString::number(source.width()) + QLatin1Char('x')
509 + QString::number(source.height()));
510 QPainter p(&pix);
511 Qt::TileRule horizontalTileMode = Qt::StretchTile;
512 Qt::TileRule verticalTileMode = Qt::StretchTile;
513 if (uiBorderImage->horizontalTileRadioButton->isChecked())
514 horizontalTileMode =Qt::RepeatTile;
515 if (uiBorderImage->horizontalTileRadioButtonNoCrop->isChecked())
516 horizontalTileMode =Qt::RoundTile;
517 if (uiBorderImage->verticalTileRadioButton->isChecked())
518 verticalTileMode =Qt::RepeatTile;
519 if (uiBorderImage->verticalTileRadioButtonNoCrop->isChecked())
520 verticalTileMode =Qt::RoundTile;
521 QTileRules rules(horizontalTileMode, verticalTileMode);
522 PreviewLabel *previewLabel = previewDialog()->previewLabel();
523 QMargins margins(previewLabel->leftMarging() ,previewLabel->topMarging() ,previewLabel->rightMarging(), previewLabel->bottomMarging());
524 qDrawBorderPixmap(&p, QRect(0, 0, 76, 76), margins, source, source.rect(), margins, rules);
525 //p.drawPixmap(0,0,76,76, source);
526 } else {
527 uiBorderImage->sizeLabel->clear();
528 }
529 uiBorderImage->label->setPixmap(pix);
530 } else {
531 if (QFileInfo::exists(fileName)) {
532 QPixmap source(fileName);
533 previewDialog()->setPixmap(source, 1);
534 ui->sizeLabel->setText(QString::number(source.width()) + QLatin1Char('x') + QString::number(source.height()));
535 QPainter p(&pix);
536 if (ui->stretchRadioButton->isChecked()) {
537 p.drawPixmap(0,0,76,76, source);
538 } else if (ui->tileRadioButton->isChecked()) {
539 QPixmap small = source.scaled(38,38);
540 p.drawTiledPixmap(0,0,76,76, small);
541 } else if (ui->horizontalStretchRadioButton->isChecked()) {
542 QPixmap small = source.scaled(38,38);
543 QPixmap half = pix.scaled(38, 76);
544 QPainter p2(&half);
545 p2.drawTiledPixmap(0,0,38,76, small);
546 p.drawPixmap(0,0,76,76, half);
547 } else if (ui->verticalStretchRadioButton->isChecked()) {
548 QPixmap small = source.scaled(38,38);
549 QPixmap half = pix.scaled(76, 38);
550 QPainter p2(&half);
551 p2.drawTiledPixmap(0,0,76,38, small);
552 p.drawPixmap(0,0,76,76, half);
553 } else if (ui->preserveAspectFitRadioButton->isChecked()) {
554 QPixmap preserved = source.scaledToWidth(76);
555 int offset = (76 - preserved.height()) / 2;
556 p.drawPixmap(0, offset, 76, preserved.height(), source);
557 } else if (ui->cropAspectFitRadioButton->isChecked()) {
558 QPixmap cropped = source.scaledToHeight(76);
559 int offset = (76 - cropped.width()) / 2;
560 p.drawPixmap(offset, 0, cropped.width(), 76, source);
561 }
562 } else {
563 ui->sizeLabel->clear();
564 }
565
566 ui->label->setPixmap(pix);
567
568 }
569 }
570
previewDialog()571 PreviewDialog* ContextPaneWidgetImage::previewDialog()
572 {
573 if (!m_previewDialog) {
574 m_previewDialog = new PreviewDialog(this);
575 m_previewDialog->hide();
576 }
577
578 return m_previewDialog.data();
579 }
580
changeEvent(QEvent * e)581 void ContextPaneWidgetImage::changeEvent(QEvent *e)
582 {
583 QWidget::changeEvent(e);
584 switch (e->type()) {
585 case QEvent::LanguageChange:
586 if (ui)
587 ui->retranslateUi(this);
588 if (uiBorderImage)
589 uiBorderImage->retranslateUi(this);
590 break;
591 default:
592 break;
593 }
594 }
595
596
hideEvent(QHideEvent * event)597 void ContextPaneWidgetImage::hideEvent(QHideEvent * event)
598 {
599 previewWasVisible = previewDialog()->isVisible();
600 previewDialog()->hide();
601 QWidget::hideEvent(event);
602 }
603
showEvent(QShowEvent * event)604 void ContextPaneWidgetImage::showEvent(QShowEvent* event)
605 {
606 if (previewWasVisible)
607 previewDialog()->show();
608 QWidget::showEvent(event);
609 }
610
PreviewLabel(QWidget * parent)611 PreviewLabel::PreviewLabel(QWidget *parent)
612 : QLabel(parent),
613 m_dragging_left(false), m_dragging_right(false),
614 m_dragging_top(false), m_dragging_bottom(false)
615
616 {
617 m_zoom = 1;
618 m_showBorders = false;
619 m_left = 2;
620 m_right = 2;
621 m_top = 2;
622 m_bottom = 2;
623 setMouseTracking(true);
624 setCursor(QCursor(Qt::ArrowCursor));
625 m_hooverInfo = new QLabel(parentWidget());
626 m_hooverInfo->hide();
627
628 m_hooverInfo->setFrameShape(QFrame::StyledPanel);
629 m_hooverInfo->setFrameShadow(QFrame::Sunken);
630 QGraphicsDropShadowEffect *dropShadowEffect = new QGraphicsDropShadowEffect;
631 dropShadowEffect->setBlurRadius(4);
632 dropShadowEffect->setOffset(2, 2);
633 m_hooverInfo->setGraphicsEffect(dropShadowEffect);
634 m_hooverInfo->setAutoFillBackground(true);
635 m_hooverInfo->raise();
636 }
637
setZoom(int z)638 void PreviewLabel::setZoom(int z)
639 {
640 m_zoom = z;
641 }
642
setIsBorderImage(bool b)643 void PreviewLabel::setIsBorderImage(bool b)
644 {
645 m_borderImage = b;
646 }
647
setMargins(int left,int top,int right,int bottom)648 void PreviewLabel::setMargins(int left, int top, int right, int bottom)
649 {
650 m_left = left;
651 m_top = top;
652 m_right = right;
653 m_bottom = bottom;
654 }
655
paintEvent(QPaintEvent * event)656 void PreviewLabel::paintEvent(QPaintEvent *event)
657 {
658 QLabel::paintEvent(event);
659 if (m_borderImage) {
660
661 QPainter p(this);
662
663 p.setOpacity(0.5);
664
665 p.setBackgroundMode(Qt::TransparentMode);
666 {
667 QPen pen(Qt::SolidLine);
668 pen.setColor(QColor(0xf0, 0xf0, 0xf0));
669 p.setPen(pen);
670
671 if (m_left >= 0)
672 p.drawLine(m_left * m_zoom, 4, m_left * m_zoom, height() - 4);
673 if (m_right >= 0)
674 p.drawLine(width() - m_right * m_zoom - 1, 4, width() - m_right * m_zoom - 1, height() - 4);
675 if (m_top >= 0)
676 p.drawLine(4, m_top * m_zoom, width() - 4, m_top * m_zoom);
677 if (m_bottom >= 0)
678 p.drawLine(4, height() - m_bottom * m_zoom - 1, width() - 4, height() - m_bottom * m_zoom - 1);
679 }
680
681 {
682 QBrush brush(Qt::Dense4Pattern);
683 brush.setColor(QColor(0x10, 0x10, 0x10));
684 QPen pen(brush, 1, Qt::DotLine);
685 pen.setColor(QColor(0x10, 0x10, 0x10));
686 p.setPen(pen);
687
688 if (m_left >= 0)
689 p.drawLine(m_left * m_zoom, 4, m_left * m_zoom, height() - 4);
690 if (m_right >= 0)
691 p.drawLine(width() - m_right * m_zoom - 1, 4, width() - m_right * m_zoom - 1, height() - 4);
692 if (m_top >= 0)
693 p.drawLine(4, m_top * m_zoom, width() - 4, m_top * m_zoom);
694 if (m_bottom >= 0)
695 p.drawLine(4, height() - m_bottom * m_zoom - 1, width() - 4, height() - m_bottom * m_zoom - 1);
696 }
697 }
698 }
699
rangeCheck(int target,int pos)700 static inline bool rangeCheck(int target, int pos)
701 {
702 return (target - 10 < pos) && (target + 10 > pos);
703 }
704
mousePressEvent(QMouseEvent * event)705 void PreviewLabel::mousePressEvent(QMouseEvent * event)
706 {
707 if (!m_borderImage) {
708 QLabel::mouseMoveEvent(event);
709 return;
710 }
711
712 bool bottom = false;
713
714 if (event->button() == Qt::LeftButton) {
715 if (QApplication::overrideCursor())
716 QApplication::restoreOverrideCursor();
717 if (rangeCheck(m_left * m_zoom, event->pos().x())) {
718 QApplication::setOverrideCursor(QCursor(Qt::SizeHorCursor));
719 m_dragging_left = true;
720 event->accept();
721 m_hooverInfo->setText(QLatin1String("Left ") + QString::number(m_left));
722 m_hooverInfo->show();
723 } else if (rangeCheck(m_top * m_zoom, event->pos().y())) {
724 QApplication::setOverrideCursor(QCursor(Qt::SizeVerCursor));
725 m_dragging_top = true;
726 event->accept();
727 m_hooverInfo->setText(QLatin1String("Top ") + QString::number(m_top));
728 m_hooverInfo->show();
729 } else if (rangeCheck(m_right * m_zoom, width() - event->pos().x())) {
730 QApplication::setOverrideCursor(QCursor(Qt::SizeHorCursor));
731 m_dragging_right = true;
732 event->accept();
733 m_hooverInfo->setText(QLatin1String("Right ") + QString::number(m_right));
734 m_hooverInfo->show();
735 } else if (rangeCheck(m_bottom * m_zoom, height() - event->pos().y())) {
736 QApplication::setOverrideCursor(QCursor(Qt::SizeVerCursor));
737 m_dragging_bottom = true;
738 event->accept();
739 m_hooverInfo->setText(QLatin1String("Bottom ") + QString::number(m_bottom));
740 m_hooverInfo->show();
741 bottom = true;
742 } else {
743 QLabel::mousePressEvent(event);
744 }
745 m_startPos = event->pos();
746 if (bottom)
747 m_hooverInfo->move(mapToParent(m_startPos) + QPoint(0, -10));
748 else
749 m_hooverInfo->move(mapToParent(m_startPos) + QPoint(0, 40));
750 m_hooverInfo->resize(m_hooverInfo->sizeHint());
751 m_hooverInfo->raise();
752 }
753 }
754
mouseReleaseEvent(QMouseEvent * event)755 void PreviewLabel::mouseReleaseEvent(QMouseEvent * event)
756 {
757 if (!m_borderImage)
758 return QLabel::mouseMoveEvent(event);
759
760 if (m_dragging_left || m_dragging_top || m_dragging_right|| m_dragging_bottom) {
761 m_hooverInfo->hide();
762 if (m_dragging_left)
763 emit leftMarginChanged();
764
765 if (m_dragging_top)
766 emit topMarginChanged();
767
768 if (m_dragging_bottom)
769 emit bottomMarginChanged();
770
771 if (m_dragging_right)
772 emit rightMarginChanged();
773
774 m_dragging_left = false;
775 m_dragging_top = false;
776 m_dragging_right = false;
777 m_dragging_bottom = false;
778 QApplication::restoreOverrideCursor();
779 event->accept();
780
781 } else {
782 QLabel::mouseReleaseEvent(event);
783 }
784 }
785
786
limitPositive(int i)787 static inline int limitPositive(int i)
788 {
789 if (i >= 0)
790 return i;
791 return 0;
792 }
793
mouseMoveEvent(QMouseEvent * event)794 void PreviewLabel::mouseMoveEvent(QMouseEvent * event)
795 {
796 if (!m_borderImage) {
797 QLabel::mouseMoveEvent(event);
798 return;
799 }
800
801 QPoint p = event->pos();
802 bool bottom = false;
803 if (m_dragging_left) {
804 m_left = p.x() / m_zoom;
805 m_left = limitPositive(m_left);
806 event->accept();
807 m_hooverInfo->setText(QLatin1String("Left ") + QString::number(m_left));
808 update();
809 } else if (m_dragging_top) {
810 m_top = p.y() / m_zoom;
811 m_top = limitPositive(m_top);
812 event->accept();
813 m_hooverInfo->setText(QLatin1String("Top ") + QString::number(m_top));
814 update();
815 } else if (m_dragging_right) {
816 m_right = (width() - p.x()) / m_zoom;
817 m_right = limitPositive(m_right);
818 event->accept();
819 m_hooverInfo->setText(QLatin1String("Right ") + QString::number(m_right));
820 update();
821 } else if (m_dragging_bottom) {
822 m_bottom = (height() - p.y()) / m_zoom;
823 m_bottom = limitPositive(m_bottom);
824 event->accept();
825 m_hooverInfo->setText(QLatin1String("Bottom ") + QString::number(m_bottom));
826 bottom = true;
827 update();
828 } else if (rangeCheck(m_left * m_zoom, p.x())) {
829 QApplication::setOverrideCursor(QCursor(Qt::SizeHorCursor));
830 event->accept();
831 m_hooverInfo->setText(QLatin1String("Left ") + QString::number(m_left));
832 m_hooverInfo->show();
833 } else if (rangeCheck(m_top * m_zoom, p.y())) {
834 QApplication::setOverrideCursor(QCursor(Qt::SizeVerCursor));
835 event->accept();
836 m_hooverInfo->setText(QLatin1String("Top ") + QString::number(m_top));
837 m_hooverInfo->show();
838 } else if (rangeCheck(m_right * m_zoom, width() - p.x())) {
839 QApplication::setOverrideCursor(QCursor(Qt::SizeHorCursor));
840 event->accept();
841 m_hooverInfo->setText(QLatin1String("Right ") + QString::number(m_right));
842 m_hooverInfo->show();
843 } else if (rangeCheck(m_bottom * m_zoom, height() - p.y())) {
844 QApplication::setOverrideCursor(QCursor(Qt::SizeVerCursor));
845 event->accept();
846 m_hooverInfo->setText(QLatin1String("Bottom ") + QString::number(m_bottom));
847 m_hooverInfo->show();
848 bottom = true;
849 } else {
850 if (QApplication::overrideCursor())
851 QApplication::restoreOverrideCursor();
852 QLabel::mouseMoveEvent(event);
853 m_hooverInfo->hide();
854 }
855 m_startPos = p;
856 if (bottom)
857 m_hooverInfo->move(mapToParent(p) + QPoint(0, -10));
858 else
859 m_hooverInfo->move(mapToParent(p) + QPoint(0, 40));
860 m_hooverInfo->resize(m_hooverInfo->sizeHint());
861 m_hooverInfo->raise();
862 }
863
leaveEvent(QEvent * event)864 void PreviewLabel::leaveEvent(QEvent* event )
865 {
866 while (QApplication::overrideCursor())
867 QApplication::restoreOverrideCursor();
868 m_hooverInfo->hide();
869 QLabel::leaveEvent(event);
870 }
871
PreviewDialog(QWidget * parent)872 PreviewDialog::PreviewDialog(QWidget *parent) : DragWidget(parent)
873 {
874 m_borderImage = false;
875 setAutoFillBackground(true);
876
877 m_label = new PreviewLabel(this);
878 m_slider = new QSlider(this);
879
880 m_zoomLabel = new QLabel(this);
881
882 setZoom(1);
883
884 QVBoxLayout *layout = new QVBoxLayout(this);
885 QHBoxLayout *horizontalLayout = new QHBoxLayout();
886 QHBoxLayout *horizontalLayout2 = new QHBoxLayout();
887 layout->setContentsMargins(2, 2, 2, 16);
888 layout->setSpacing(4);
889 QToolButton *toolButton = new QToolButton(this);
890 QIcon icon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton));
891 toolButton->setIcon(icon);
892 toolButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
893 toolButton->setFixedSize(icon.availableSizes().value(0) + QSize(4, 4));
894 connect(toolButton, &QToolButton::clicked, this, &PreviewDialog::onTogglePane);
895
896 QScrollArea *scrollArea = new QScrollArea(this);
897 WheelFilter *wheelFilter = new WheelFilter(scrollArea);
898 scrollArea->setWidget(m_label);
899 scrollArea->setFrameStyle(QFrame::NoFrame);
900 m_slider->setOrientation(Qt::Horizontal);
901 m_slider->setRange(1, 6);
902 m_slider->setFixedWidth(80);
903 m_zoomLabel->setFixedWidth(50);
904
905 horizontalLayout->addWidget(toolButton);
906 horizontalLayout->addSpacing(6);
907 horizontalLayout->addWidget(m_slider);
908 horizontalLayout->addSpacing(6);
909 horizontalLayout->addWidget(m_zoomLabel);
910 horizontalLayout->addStretch(1);
911
912 layout->addLayout(horizontalLayout);
913 horizontalLayout2->addSpacing(24);
914 horizontalLayout2->addWidget(scrollArea);
915 layout->addLayout(horizontalLayout2);
916
917 wheelFilter->setTarget(this);
918
919 connect(m_slider, &QSlider::valueChanged, this, &PreviewDialog::onSliderMoved);
920
921 foreach (QWidget *childWidget, findChildren<QWidget*>()) {
922 childWidget->installEventFilter(wheelFilter);
923 }
924 }
925
setPixmap(const QPixmap & p,int zoom)926 void PreviewDialog::setPixmap(const QPixmap &p, int zoom)
927 {
928 m_pixmap = p;
929 if (!p.isNull())
930 m_label->setPixmap(p.scaled(p.width() * zoom, p.height() * zoom));
931 else
932 m_label->setPixmap(QPixmap());
933 m_label->adjustSize();
934 m_zoom = zoom;
935 m_label->setZoom(m_zoom);
936 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
937 QSize size = m_label->pixmap().size() + QSize(54, 44);
938 #else
939 QSize size = m_label->pixmap()->size() + QSize(54, 44);
940 #endif
941 if (size.width() < 180)
942 size.setWidth(180);
943 resize(size);
944 }
945
wheelEvent(QWheelEvent * event)946 void PreviewDialog::wheelEvent(QWheelEvent* event)
947 {
948 const auto delta = event->angleDelta().y();
949 event->accept();
950 if (delta > 0) {
951 if (m_zoom == 1)
952 setZoom(2);
953 else if (m_zoom == 2)
954 setZoom(4);
955 else if (m_zoom == 4)
956 setZoom(6);
957 else if (m_zoom == 6)
958 setZoom(8);
959 else if (m_zoom == 8)
960 setZoom(10);
961 } else {
962 if (m_zoom == 10)
963 setZoom(8);
964 else if (m_zoom == 8)
965 setZoom(6);
966 else if (m_zoom == 6)
967 setZoom(4);
968 else if (m_zoom == 4)
969 setZoom(2);
970 else if (m_zoom == 2)
971 setZoom(1);
972 }
973 setPixmap(m_pixmap, m_zoom);
974 }
975
onTogglePane()976 void PreviewDialog::onTogglePane()
977 {
978 hide();
979 }
980
onSliderMoved(int value)981 void PreviewDialog::onSliderMoved(int value)
982 {
983 switch (value) {
984 case 1: setZoom(1); break;
985 case 2: setZoom(2); break;
986 case 3: setZoom(4); break;
987 case 4: setZoom(6); break;
988 case 5: setZoom(8); break;
989 case 6: setZoom(10); break;
990 default: break;
991 }
992 }
993
994 } //QmlDesigner
995