1 /*
2  * Copyright (C) 2015 by Stephen Allewell
3  * steve.allewell@gmail.com
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  */
10 
11 
12 /** @file
13  * This file defines an extension to a QLabel that scales the associated QPixmap
14  * to maintain the aspect ratio when scaling to fill the extents of the QLabel
15  * area.
16  */
17 
18 
19 // Class include
20 #include "ScaledPixmapLabel.h"
21 
22 // Qt includes
23 #include <QMouseEvent>
24 #include <QPainter>
25 #include <QStyleOptionRubberBand>
26 
27 
ScaledPixmapLabel(QWidget * parent)28 ScaledPixmapLabel::ScaledPixmapLabel(QWidget *parent)
29     : QLabel(parent),
30       m_cropping(false)
31 {
32     setMinimumSize(1,1);
33     setAlignment(Qt::AlignCenter);
34     setMouseTracking(true);
35 }
36 
37 
setPixmap(const QPixmap & pixmap)38 void ScaledPixmapLabel::setPixmap(const QPixmap &pixmap)
39 {
40     m_pixmap = pixmap;
41     m_crop = QRect();
42     QLabel::setPixmap(m_pixmap.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
43 }
44 
45 
setCropping(bool checked)46 void ScaledPixmapLabel::setCropping(bool checked)
47 {
48     m_cropping = checked;
49     m_crop = QRect();
50     update();
51 }
52 
53 
heightForWidth(int width) const54 int ScaledPixmapLabel::heightForWidth(int width) const
55 {
56     return ((qreal)m_pixmap.height() * width) / m_pixmap.width();
57 }
58 
59 
sizeHint() const60 QSize ScaledPixmapLabel::sizeHint() const
61 {
62     int w = width();
63     return QSize(w, heightForWidth(w));
64 }
65 
66 
pixmapRect() const67 QRect ScaledPixmapLabel::pixmapRect() const
68 {
69     QSize previewSize = size();
70     QSize pixmapSize  = pixmap()->size();
71 
72     int dx = (previewSize.width()  - pixmapSize.width())  / 2;
73     int dy = (previewSize.height() - pixmapSize.height()) / 2;
74 
75     return QRect(dx, dy, pixmapSize.width(), pixmapSize.height());
76 }
77 
78 
resizeEvent(QResizeEvent * event)79 void ScaledPixmapLabel::resizeEvent(QResizeEvent *event)
80 {
81     Q_UNUSED(event);
82 
83     QLabel::setPixmap(m_pixmap.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
84 }
85 
86 
paintEvent(QPaintEvent * event)87 void ScaledPixmapLabel::paintEvent(QPaintEvent *event)
88 {
89     QLabel::paintEvent(event);
90 
91     QPainter painter(this);
92     painter.setRenderHint(QPainter::Qt4CompatiblePainting, true);
93 
94     if (m_crop.isValid()) {
95 
96         QStyleOptionRubberBand opt;
97         opt.initFrom(this);
98         opt.shape = QRubberBand::Rectangle;
99         opt.opaque = false;
100         opt.rect = m_crop.adjusted(0, 0, 1, 1);
101 
102         style()->drawControl(QStyle::CE_RubberBand, &opt, &painter);
103     } else {
104         if (m_cropping && underMouse() && (children().count() == 0)) {
105             // draw guides
106             QPoint cursor = mapFromGlobal(QCursor::pos());
107             painter.drawLine(cursor.x(),0,cursor.x(),size().height());
108             painter.drawLine(0,cursor.y(),size().width(),cursor.y());
109         }
110     }
111 }
112 
113 
mousePressEvent(QMouseEvent * event)114 void ScaledPixmapLabel::mousePressEvent(QMouseEvent *event)
115 {
116     if (m_cropping) {
117         m_start = event->pos();
118         m_crop = QRect();
119         update();
120     }
121 }
122 
123 
mouseMoveEvent(QMouseEvent * event)124 void ScaledPixmapLabel::mouseMoveEvent(QMouseEvent *event)
125 {
126     if (m_cropping && (event->buttons() & Qt::LeftButton)) {
127         m_end = event->pos();
128         m_crop = pixmapRect().intersected(QRect(m_start, m_end).normalized());
129     }
130 
131     update();
132 }
133 
134 
mouseReleaseEvent(QMouseEvent * event)135 void ScaledPixmapLabel::mouseReleaseEvent(QMouseEvent *event)
136 {
137     if (m_cropping) {
138         m_end = event->pos();
139         m_crop = pixmapRect().intersected(QRect(m_start, m_end).normalized());
140         update();
141 
142         double scale = (double)m_pixmap.size().width()/(double)pixmap()->size().width();
143         m_crop.translate(-pixmapRect().topLeft());
144         QRectF cropF(scale*m_crop.x(), scale*m_crop.y(), scale*m_crop.width(), scale*m_crop.height());
145 
146         emit imageCropped(cropF);
147 
148         m_crop = QRect();
149     }
150 }
151 
leaveEvent(QEvent * event)152 void ScaledPixmapLabel::leaveEvent(QEvent *event)
153 {
154     update();
155     QLabel::leaveEvent(event);
156 }
157