1
// SPDX-License-Identifier: LGPL-2.1-or-later
3
/***************************************************************************
4
* Copyright (c) 2023 Werner Mayer <wmayer[at]users.sourceforge.net> *
6
* This file is part of FreeCAD. *
8
* FreeCAD is free software: you can redistribute it and/or modify it *
9
* under the terms of the GNU Lesser General Public License as *
10
* published by the Free Software Foundation, either version 2.1 of the *
11
* License, or (at your option) any later version. *
13
* FreeCAD is distributed in the hope that it will be useful, but *
14
* WITHOUT ANY WARRANTY; without even the implied warranty of *
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16
* Lesser General Public License for more details. *
18
* You should have received a copy of the GNU Lesser General Public *
19
* License along with FreeCAD. If not, see *
20
* <https://www.gnu.org/licenses/>. *
22
**************************************************************************/
24
#include "PreCompiled.h"
27
# include <QApplication>
28
# include <QContextMenuEvent>
32
# include <QImageReader>
35
# include <QMessageBox>
39
# include <QPrintDialog>
41
# include <QScrollArea>
46
#include "BitmapFactory.h"
50
ImageView::ImageView(QWidget* parent)
51
: MDIView(nullptr, parent)
52
, imageLabel(new QLabel)
53
, scrollArea(new QScrollArea)
57
imageLabel->setBackgroundRole(QPalette::Base);
58
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
59
imageLabel->setScaledContents(true);
61
scrollArea->setBackgroundRole(QPalette::Dark);
62
scrollArea->setWidget(imageLabel);
63
scrollArea->setVisible(false);
64
setCentralWidget(scrollArea);
66
setWindowIcon(Gui::BitmapFactory().pixmap("colors"));
69
bool ImageView::loadFile(const QString& fileName)
71
QImageReader reader(fileName);
72
reader.setAutoTransform(true);
73
QImage image = reader.read();
75
QMessageBox::information(this, tr("Failed to load image file"),
76
tr("Cannot load file %1: %2")
77
.arg(fileName, reader.errorString()));
82
setWindowFilePath(fileName);
87
void ImageView::setImage(const QImage& image)
90
imageLabel->setPixmap(QPixmap::fromImage(image));
91
imageLabel->adjustSize();
92
scrollArea->setVisible(true);
96
void ImageView::scaleImage(double factor)
98
scaleFactor *= factor;
99
#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
100
imageLabel->resize(scaleFactor * imageLabel->pixmap(Qt::ReturnByValue).size());
102
imageLabel->resize(scaleFactor * imageLabel->pixmap()->size());
105
adjustScrollBar(scrollArea->horizontalScrollBar(), factor);
106
adjustScrollBar(scrollArea->verticalScrollBar(), factor);
109
void ImageView::adjustScrollBar(QScrollBar *scrollBar, double factor)
111
scrollBar->setValue(int(factor * scrollBar->value()
112
+ ((factor - 1) * scrollBar->pageStep()/2)));
115
bool ImageView::canZoomIn() const
118
return !isFitToWindow() && imageLabel->width() < maxWidth;
121
bool ImageView::canZoomOut() const
124
return !isFitToWindow() && imageLabel->width() > minWidth;
127
void ImageView::zoomIn()
133
void ImageView::zoomOut()
139
void ImageView::normalSize()
141
imageLabel->adjustSize();
145
void ImageView::fitToWindow(bool fitView)
147
scrollArea->setWidgetResizable(fitView);
153
bool ImageView::isFitToWindow() const
155
return scrollArea->widgetResizable();
158
bool ImageView::canDrag() const
160
return scrollArea->verticalScrollBar()->isVisible() ||
161
scrollArea->horizontalScrollBar()->isVisible();
164
void ImageView::startDrag()
169
void ImageView::stopDrag()
174
bool ImageView::isDragging() const
179
void ImageView::contextMenuEvent(QContextMenuEvent* event)
182
QAction* fitToWindowAct = menu.addAction(tr("Fit to window"));
183
fitToWindowAct->setCheckable(true);
184
fitToWindowAct->setChecked(isFitToWindow());
185
connect(fitToWindowAct, &QAction::toggled, this, &ImageView::fitToWindow);
187
QAction* zoomInAct = menu.addAction(tr("Zoom in"), this, &ImageView::zoomIn);
188
zoomInAct->setEnabled(canZoomIn());
190
QAction* zoomOutAct = menu.addAction(tr("Zoom out"), this, &ImageView::zoomOut);
191
zoomOutAct->setEnabled(canZoomOut());
193
menu.exec(event->globalPos());
196
void ImageView::mousePressEvent(QMouseEvent* event)
198
if (event->buttons().testFlag(Qt::MiddleButton)) {
200
setCursor(QCursor(Qt::ClosedHandCursor));
202
dragPos = event->pos();
207
void ImageView::mouseReleaseEvent(QMouseEvent* event)
209
if (!event->buttons().testFlag(Qt::MiddleButton)) {
217
void ImageView::mouseMoveEvent(QMouseEvent* event)
220
QScrollBar* hBar = scrollArea->horizontalScrollBar();
221
QScrollBar* vBar = scrollArea->verticalScrollBar();
222
QPoint delta = event->pos() - dragPos;
223
hBar->setValue(hBar->value() + (isRightToLeft() ? delta.x() : -delta.x()));
224
vBar->setValue(vBar->value() - delta.y());
225
dragPos = event->pos();
229
void ImageView::dropEvent(QDropEvent* event)
231
const QMimeData* data = event->mimeData();
232
if (data->hasUrls()) {
233
loadImageFromUrl(data->urls());
236
MDIView::dropEvent(event);
240
void ImageView::dragEnterEvent(QDragEnterEvent* event)
242
const QMimeData* data = event->mimeData();
243
if (data->hasUrls()) {
251
bool ImageView::isImageFormat(const QFileInfo& fileInfo)
253
QString ext = fileInfo.suffix().toLower();
254
QByteArray suffix = ext.toLatin1();
255
QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
256
auto it = std::find_if(supportedFormats.begin(), supportedFormats.end(), [suffix](const QByteArray& image) {
257
return (image == suffix);
260
return (it != supportedFormats.end());
263
void ImageView::loadImageFromUrl(const QList<QUrl>& urls)
265
if (urls.isEmpty()) {
269
const QUrl& url = urls.first();
270
const QFileInfo info(url.toLocalFile());
271
if (info.exists() && info.isFile()) {
272
if (isImageFormat(info)) {
273
loadFile(info.absoluteFilePath());
278
void ImageView::pasteImage()
280
QImage image = imageFromClipboard();
281
if (!image.isNull()) {
286
bool ImageView::canPasteImage() const
288
return !imageFromClipboard().isNull();
291
QImage ImageView::imageFromClipboard()
294
if (const QMimeData *mimeData = QApplication::clipboard()->mimeData()) {
295
if (mimeData->hasImage()) {
296
image = qvariant_cast<QImage>(mimeData->imageData());
303
void ImageView::print(QPrinter* printer)
305
QPainter painter(printer);
306
QPixmap pixmap = QPixmap::fromImage(rawImage);
307
QRect rect = painter.viewport();
308
QSize size = pixmap.size();
309
size.scale(rect.size(), Qt::KeepAspectRatio);
310
painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
311
painter.setWindow(pixmap.rect());
312
painter.drawPixmap(0, 0, pixmap);
315
bool ImageView::onMsg(const char* pMsg,const char** ppReturn)
318
if (strcmp("ViewFit", pMsg) == 0) {
322
if (strcmp("ZoomIn", pMsg) == 0) {
326
if (strcmp("ZoomOut", pMsg) == 0) {
330
if (strcmp("Paste", pMsg) == 0) {
334
if (strcmp("Print", pMsg) == 0) {
338
if (strcmp("PrintPreview", pMsg) == 0) {
342
if (strcmp("PrintPdf", pMsg) == 0) {
350
bool ImageView::onHasMsg(const char* pMsg) const
352
if (strcmp("ViewFit", pMsg) == 0) {
355
if (strcmp("ZoomIn", pMsg) == 0) {
358
if (strcmp("ZoomOut", pMsg) == 0) {
361
if (strcmp("Paste", pMsg) == 0) {
362
return canPasteImage();
364
if (strcmp("Print", pMsg) == 0) {
367
if (strcmp("PrintPreview", pMsg) == 0) {
370
if (strcmp("PrintPdf", pMsg) == 0) {
373
else if (strcmp("AllowsOverlayOnHover", pMsg) == 0) {
380
#include "moc_ImageView.cpp"