zimageview.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <cmath>
00018 #include <QPainter>
00019 #include <QMouseEvent>
00020
00021 #include "zimageview.h"
00022
00023 #if QT_VERSION >= 0x040200
00024 #define CURSOR_NORMAL QCursor(Qt::OpenHandCursor)
00025 #define CURSOR_MOUSE_PRESS QCursor(Qt::ClosedHandCursor)
00026 #else
00027 #define CURSOR_NORMAL QCursor(Qt::CrossCursor)
00028 #define CURSOR_MOUSE_PRESS QCursor(Qt::SizeAllCursor)
00029 #endif
00030
00031
00032
00033 ZImageView::ZImageView(QWidget *parent)
00034 : QWidget(parent)
00035 {
00036
00037 _zoom = 0.0;
00038 _desiredX = 0.0;
00039 _desiredY = 0.0;
00040 _maxZoomFactor = 2.0;
00041 _padding = 60;
00042
00043 setCursor(CURSOR_NORMAL);
00044 updateViewport();
00045 resetZoomPoint();
00046 repaint();
00047 }
00048
00049
00050 void
00051 ZImageView::setImage(QImage& img)
00052 {
00053 _image = img.copy();
00054 updateViewport();
00055 resetZoomPoint();
00056
00057 if (isVisible()) {
00058 repaint();
00059 }
00060 }
00061
00062
00063 void
00064 ZImageView::drawScaledImage()
00065 {
00066 if (!isVisible()) {
00067 return;
00068 }
00069
00070 QBrush background(QColor("#fdfdfd"));
00071 if (_image.isNull()) {
00072 QPainter p(this);
00073 p.fillRect(rect(), background);
00074 return;
00075 }
00076
00077 QRect sRect = rect();
00078 QRect iRect = _image.rect();
00079 QRect r = _view;
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 double scaleFactor = double(sRect.width()) / double(_view.width());
00095
00096
00097 if (r.top() < 0) {
00098 r.setTop(0);
00099 }
00100 if (iRect.bottom() < r.bottom()) {
00101 r.setBottom(iRect.bottom());
00102 }
00103 if (r.left() < 0) {
00104 r.setLeft(0);
00105 }
00106 if (iRect.right() < r.right()) {
00107 r.setRight(iRect.right());
00108 }
00109
00110
00111 QSize scaleTo(int(double(r.width()) * scaleFactor),
00112 int(double(r.height()) * scaleFactor));
00113
00114
00115 QImage i = _image.copy();
00116
00117
00118
00119 QPainter painter;
00120 painter.begin(&i);
00121 paintImage(&painter);
00122 painter.end();
00123
00124
00125 i = i.copy(r).scaled(scaleTo,
00126 Qt::KeepAspectRatioByExpanding,
00127 Qt::SmoothTransformation);
00128
00129 int extraWidth = int(double(sRect.width() - i.width()) / 2.0);
00130 int extraHeight = int(double(sRect.height() - i.height()) / 2.0);
00131
00132
00133
00134
00135
00136 QPainter p(this);
00137 if (extraWidth > 0) {
00138 p.fillRect(0, 0, extraWidth, sRect.height(), background);
00139 p.fillRect(sRect.width() - extraWidth, 0,
00140 sRect.width(), sRect.height(), background);
00141 }
00142
00143 if (extraHeight > 0) {
00144 p.fillRect(0, 0, sRect.width(), extraHeight, background);
00145 p.fillRect(0, sRect.height() - extraHeight,
00146 sRect.width(), sRect.height(), background);
00147 }
00148
00149
00150 p.drawImage(extraWidth, extraHeight, i);
00151 }
00152
00153
00154 void
00155 ZImageView::updateViewport(int screendx, int screendy)
00156 {
00157
00158
00159
00160
00161
00162 QRect sRect = rect();
00163 QRect iRect = _image.rect();
00164
00165 float sw = float(sRect.width());
00166 float sh = float(sRect.height());
00167 float iw = float(iRect.width());
00168 float ih = float(iRect.height());
00169
00170
00171
00172
00173 float maxw = float(std::max<int>(sRect.width(), iRect.width())) + _padding;
00174 float maxh = float(std::max<int>(sRect.height(), iRect.height())) + _padding;
00175 float minw = std::ceil(float(sRect.width()) / _maxZoomFactor);
00176 float minh = std::ceil(float(sRect.height()) / _maxZoomFactor);
00177
00178
00179
00180 float aspect = sw / sh;
00181
00182
00183 float newmaxh = maxh;
00184 float newmaxw = aspect * newmaxh;
00185 if (newmaxw < maxw) {
00186 newmaxw = maxw;
00187 newmaxh = maxw / aspect;
00188 }
00189
00190
00191 float newminh = minh;
00192 float newminw = aspect * newminh;
00193 if (minw < newminw) {
00194 newminw = minw;
00195 newminh = newminw / aspect;
00196 }
00197
00198
00199 float vw = (1.0f - _zoom) * (newmaxw - newminw) + newminw;
00200 float vh = (1.0f - _zoom) * (newmaxh - newminh) + newminh;
00201
00202 _view.setWidth(int(vw));
00203 _view.setHeight(int(vh));
00204
00205
00206
00207
00208 float vdx = vw * (float(screendx) / sw);
00209 float vdy = vh * (float(screendy) / sh);
00210
00211
00212 _desiredX = qBound(0.0f, _desiredX + vdx, iw);
00213 _desiredY = qBound(0.0f, _desiredY + vdy, ih);
00214 _view.moveCenter(QPoint(int(_desiredX), int(_desiredY)));
00215
00216 QPoint viewCenter = _view.center();
00217 float vx = viewCenter.x();
00218 float vy = viewCenter.y();
00219
00220
00221
00222
00223
00224
00225
00226 vdx = 0;
00227 vdy = 0;
00228
00229 if (iw <= vw) {
00230 vdx = (iw / 2.0f) - vx;
00231 } else {
00232
00233 float vl = float(_view.left());
00234 float vr = float(_view.right());
00235 if (vl < 0) {
00236 vdx = -vl;
00237 } else if (vr > iw) {
00238 vdx = iw - vr;
00239 }
00240 }
00241
00242 if (ih <= vh) {
00243 vdy = (ih / 2.0f) - vy;
00244 } else {
00245
00246 float vt = float(_view.top());
00247 float vb = float(_view.bottom());
00248 if (vt < 0) {
00249 vdy = -vt;
00250 } else if (vb > ih) {
00251 vdy = ih - vb;
00252 }
00253 }
00254
00255 _view.translate(int(vdx), int(vdy));
00256 }
00257
00258
00259 void
00260 ZImageView::resetZoomPoint()
00261 {
00262 QPoint viewCenter = _view.center();
00263 _desiredX = viewCenter.x();
00264 _desiredY = viewCenter.y();
00265 }
00266
00267
00268
00269 void
00270 ZImageView::paintEvent(QPaintEvent*)
00271 {
00272 updateViewport();
00273 drawScaledImage();
00274 }
00275
00276
00277
00278 void
00279 ZImageView::zoom(QPoint zoomAt, float pct)
00280 {
00281 _desiredX = zoomAt.x();
00282 _desiredY = zoomAt.y();
00283 zoom(pct);
00284 }
00285
00286
00287 void
00288 ZImageView::zoom(float pct)
00289 {
00290 _zoom = qBound(0.0f, pct, 1.0f);
00291 repaint();
00292 }
00293
00294
00295 void
00296 ZImageView::zoomIn()
00297 {
00298 zoom(_zoom + .1);
00299 }
00300
00301
00302 void
00303 ZImageView::zoomOut()
00304 {
00305 zoom(_zoom - .1);
00306 }
00307
00308
00309 void
00310 ZImageView::mousePressEvent(QMouseEvent *e)
00311 {
00312 e->accept();
00313 setCursor(CURSOR_MOUSE_PRESS);
00314 _mouseX = e->x();
00315 _mouseY = e->y();
00316 }
00317
00318
00319 void
00320 ZImageView::mouseReleaseEvent(QMouseEvent *e)
00321 {
00322 e->accept();
00323 setCursor(CURSOR_NORMAL);
00324 updateViewport();
00325 resetZoomPoint();
00326 }
00327
00328
00329
00330
00331 void
00332 ZImageView::mouseDoubleClickEvent(QMouseEvent *e)
00333 {
00334 e->accept();
00335
00336 QPoint center = rect().center();
00337 int dx = e->x() - center.x();
00338 int dy = e->y() - center.y();
00339 updateViewport(dx, dy);
00340 resetZoomPoint();
00341
00342 Qt::MouseButton btn = e->button();
00343 if (btn == Qt::LeftButton)
00344 zoomIn();
00345 else if (btn == Qt::RightButton)
00346 zoomOut();
00347 }
00348
00349
00350 void
00351 ZImageView::mouseMoveEvent(QMouseEvent *e)
00352 {
00353 e->accept();
00354 int dx = _mouseX - e->x();
00355 int dy = _mouseY - e->y();
00356 _mouseX = e->x();
00357 _mouseY = e->y();
00358
00359 updateViewport(dx, dy);
00360 if (0.001 <= _zoom) {
00361 repaint();
00362 }
00363 }
00364
00365 void
00366 ZImageView::wheelEvent(QWheelEvent *e)
00367 {
00368 if (e->delta() > 0) {
00369 zoomIn();
00370 } else {
00371 zoomOut();
00372 }
00373 }