FreeCAD

Форк
0
/
ImageView.cpp 
377 строк · 9.7 Кб
1
// SPDX-License-Identifier: LGPL-2.1-or-later
2

3
/***************************************************************************
4
 *   Copyright (c) 2023 Werner Mayer <wmayer[at]users.sourceforge.net>     *
5
 *                                                                         *
6
 *   This file is part of FreeCAD.                                         *
7
 *                                                                         *
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.                       *
12
 *                                                                         *
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.                       *
17
 *                                                                         *
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/>.                                      *
21
 *                                                                         *
22
 **************************************************************************/
23

24
#include "PreCompiled.h"
25
#ifndef _PreComp_
26
# include <QAction>
27
# include <QApplication>
28
# include <QContextMenuEvent>
29
# include <QClipboard>
30
# include <QCursor>
31
# include <QFileInfo>
32
# include <QImageReader>
33
# include <QLabel>
34
# include <QMenu>
35
# include <QMessageBox>
36
# include <QMimeData>
37
# include <QPainter>
38
# include <QPixmap>
39
# include <QPrintDialog>
40
# include <QPrinter>
41
# include <QScrollArea>
42
# include <QScrollBar>
43
#endif
44

45
#include "ImageView.h"
46
#include "BitmapFactory.h"
47

48
using namespace Gui;
49

50
ImageView::ImageView(QWidget* parent)
51
    : MDIView(nullptr, parent)
52
    , imageLabel(new QLabel)
53
    , scrollArea(new QScrollArea)
54
    , scaleFactor{1.0}
55
    , dragging{false}
56
{
57
    imageLabel->setBackgroundRole(QPalette::Base);
58
    imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
59
    imageLabel->setScaledContents(true);
60

61
    scrollArea->setBackgroundRole(QPalette::Dark);
62
    scrollArea->setWidget(imageLabel);
63
    scrollArea->setVisible(false);
64
    setCentralWidget(scrollArea);
65
    setAcceptDrops(true);
66
    setWindowIcon(Gui::BitmapFactory().pixmap("colors"));
67
}
68

69
bool ImageView::loadFile(const QString& fileName)
70
{
71
    QImageReader reader(fileName);
72
    reader.setAutoTransform(true);
73
    QImage image = reader.read();
74
    if (image.isNull()) {
75
        QMessageBox::information(this, tr("Failed to load image file"),
76
                                 tr("Cannot load file %1: %2")
77
                                 .arg(fileName, reader.errorString()));
78
        return false;
79
    }
80

81
    setImage(image);
82
    setWindowFilePath(fileName);
83

84
    return true;
85
}
86

87
void ImageView::setImage(const QImage& image)
88
{
89
    rawImage = image;
90
    imageLabel->setPixmap(QPixmap::fromImage(image));
91
    imageLabel->adjustSize();
92
    scrollArea->setVisible(true);
93
    scaleFactor = 1.0;
94
}
95

96
void ImageView::scaleImage(double factor)
97
{
98
    scaleFactor *= factor;
99
#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
100
    imageLabel->resize(scaleFactor * imageLabel->pixmap(Qt::ReturnByValue).size());
101
#else
102
    imageLabel->resize(scaleFactor * imageLabel->pixmap()->size());
103
#endif
104

105
    adjustScrollBar(scrollArea->horizontalScrollBar(), factor);
106
    adjustScrollBar(scrollArea->verticalScrollBar(), factor);
107
}
108

109
void ImageView::adjustScrollBar(QScrollBar *scrollBar, double factor)
110
{
111
    scrollBar->setValue(int(factor * scrollBar->value()
112
                            + ((factor - 1) * scrollBar->pageStep()/2)));
113
}
114

115
bool ImageView::canZoomIn() const
116
{
117
    int maxWidth{10000};
118
    return !isFitToWindow() && imageLabel->width() < maxWidth;
119
}
120

121
bool ImageView::canZoomOut() const
122
{
123
    int minWidth{200};
124
    return !isFitToWindow() && imageLabel->width() > minWidth;
125
}
126

127
void ImageView::zoomIn()
128
{
129
    double scale{1.25};
130
    scaleImage(scale);
131
}
132

133
void ImageView::zoomOut()
134
{
135
    double scale{0.8};
136
    scaleImage(scale);
137
}
138

139
void ImageView::normalSize()
140
{
141
    imageLabel->adjustSize();
142
    scaleFactor = 1.0;
143
}
144

145
void ImageView::fitToWindow(bool fitView)
146
{
147
    scrollArea->setWidgetResizable(fitView);
148
    if (!fitView) {
149
        normalSize();
150
    }
151
}
152

153
bool ImageView::isFitToWindow() const
154
{
155
    return scrollArea->widgetResizable();
156
}
157

158
bool ImageView::canDrag() const
159
{
160
    return scrollArea->verticalScrollBar()->isVisible() ||
161
           scrollArea->horizontalScrollBar()->isVisible();
162
}
163

164
void ImageView::startDrag()
165
{
166
    dragging = true;
167
}
168

169
void ImageView::stopDrag()
170
{
171
    dragging = false;
172
}
173

174
bool ImageView::isDragging() const
175
{
176
    return dragging;
177
}
178

179
void ImageView::contextMenuEvent(QContextMenuEvent* event)
180
{
181
    QMenu menu;
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);
186

187
    QAction* zoomInAct = menu.addAction(tr("Zoom in"), this, &ImageView::zoomIn);
188
    zoomInAct->setEnabled(canZoomIn());
189

190
    QAction* zoomOutAct = menu.addAction(tr("Zoom out"), this, &ImageView::zoomOut);
191
    zoomOutAct->setEnabled(canZoomOut());
192

193
    menu.exec(event->globalPos());
194
}
195

196
void ImageView::mousePressEvent(QMouseEvent* event)
197
{
198
    if (event->buttons().testFlag(Qt::MiddleButton)) {
199
        if (canDrag()) {
200
            setCursor(QCursor(Qt::ClosedHandCursor));
201
            startDrag();
202
            dragPos = event->pos();
203
        }
204
    }
205
}
206

207
void ImageView::mouseReleaseEvent(QMouseEvent* event)
208
{
209
    if (!event->buttons().testFlag(Qt::MiddleButton)) {
210
        if (isDragging()) {
211
            stopDrag();
212
            unsetCursor();
213
        }
214
    }
215
}
216

217
void ImageView::mouseMoveEvent(QMouseEvent* event)
218
{
219
    if (isDragging()) {
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();
226
    }
227
}
228

229
void ImageView::dropEvent(QDropEvent* event)
230
{
231
    const QMimeData* data = event->mimeData();
232
    if (data->hasUrls()) {
233
        loadImageFromUrl(data->urls());
234
    }
235
    else {
236
        MDIView::dropEvent(event);
237
    }
238
}
239

240
void ImageView::dragEnterEvent(QDragEnterEvent* event)
241
{
242
    const QMimeData* data = event->mimeData();
243
    if (data->hasUrls()) {
244
        event->accept();
245
    }
246
    else {
247
        event->ignore();
248
    }
249
}
250

251
bool ImageView::isImageFormat(const QFileInfo& fileInfo)
252
{
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);
258
    });
259

260
    return (it != supportedFormats.end());
261
}
262

263
void ImageView::loadImageFromUrl(const QList<QUrl>& urls)
264
{
265
    if (urls.isEmpty()) {
266
        return;
267
    }
268

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());
274
        }
275
    }
276
}
277

278
void ImageView::pasteImage()
279
{
280
    QImage image = imageFromClipboard();
281
    if (!image.isNull()) {
282
        setImage(image);
283
    }
284
}
285

286
bool ImageView::canPasteImage() const
287
{
288
    return !imageFromClipboard().isNull();
289
}
290

291
QImage ImageView::imageFromClipboard()
292
{
293
    QImage image;
294
    if (const QMimeData *mimeData = QApplication::clipboard()->mimeData()) {
295
        if (mimeData->hasImage()) {
296
            image = qvariant_cast<QImage>(mimeData->imageData());
297
        }
298
    }
299

300
    return image;
301
}
302

303
void ImageView::print(QPrinter* printer)
304
{
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);
313
}
314

315
bool ImageView::onMsg(const char* pMsg,const char** ppReturn)
316
{
317
    Q_UNUSED(ppReturn)
318
    if (strcmp("ViewFit", pMsg) == 0) {
319
        fitToWindow(true);
320
        return true;
321
    }
322
    if (strcmp("ZoomIn", pMsg) == 0) {
323
        zoomIn();
324
        return true;
325
    }
326
    if (strcmp("ZoomOut", pMsg) == 0) {
327
        zoomOut();
328
        return true;
329
    }
330
    if (strcmp("Paste", pMsg) == 0) {
331
        pasteImage();
332
        return true;
333
    }
334
    if (strcmp("Print", pMsg) == 0) {
335
        print();
336
        return true;
337
    }
338
    if (strcmp("PrintPreview", pMsg) == 0) {
339
        printPreview();
340
        return true;
341
    }
342
    if (strcmp("PrintPdf", pMsg) == 0) {
343
        printPdf();
344
        return true;
345
    }
346

347
    return false;
348
}
349

350
bool ImageView::onHasMsg(const char* pMsg) const
351
{
352
    if (strcmp("ViewFit", pMsg) == 0) {
353
        return true;
354
    }
355
    if (strcmp("ZoomIn", pMsg) == 0) {
356
        return canZoomIn();
357
    }
358
    if (strcmp("ZoomOut", pMsg) == 0) {
359
        return canZoomOut();
360
    }
361
    if (strcmp("Paste", pMsg) == 0) {
362
        return canPasteImage();
363
    }
364
    if (strcmp("Print", pMsg) == 0) {
365
        return true;
366
    }
367
    if (strcmp("PrintPreview", pMsg) == 0) {
368
        return true;
369
    }
370
    if (strcmp("PrintPdf", pMsg) == 0) {
371
        return true;
372
    }
373

374
    return false;
375
}
376

377
#include "moc_ImageView.cpp"
378

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.