2 * This file is a part of QComicBook.
4 * Copyright (C) 2005-2006 Pawel Stolowski <yogin@linux.bydg.org>
6 * QComicBook is free software; you can redestribute it and/or modify it
7 * under terms of GNU General Public License by Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY. See GPL for more details.
15 #include "imlibimage.h"
16 #include <qpopupmenu.h>
23 using namespace QComicBook;
25 const int ComicImageView::EXTRA_WHEEL_SPIN = 2;
27 ComicImageView::ComicImageView(QWidget *parent, Size size, const QColor &color): QScrollView(parent), isize(size), iangle(0), xoff(0), yoff(0), lx(-1), wheelupcnt(0), wheeldowncnt(0), smallcursor(NULL)
29 context_menu = new QPopupMenu(this);
30 viewport()->setPaletteBackgroundColor(color);
31 setFocusPolicy(QWidget::StrongFocus);
34 ComicImageView::~ComicImageView()
40 void ComicImageView::drawContents(QPainter *p, int clipx, int clipy, int clipw, int cliph)
42 if (orgimage[0].isEmpty())
45 ImlibImage *image1, *image2;
48 if (iangle > 1 && !orgimage[1].isEmpty()) //switch image pointers to reflect rotation angle
50 image1 = orgimage[1].current();
51 image2 = orgimage[0].current();
55 image1 = orgimage[0].current();
56 image2 = orgimage[1].current();
59 int px = clipx - xoff;
60 int py = clipy - yoff;
62 if (py < 0 ) //clear strip on the top
64 p->eraseRect(clipx, clipy, clipw, -py);
67 if (px < 0) //clear strip on the left
69 p->eraseRect(clipx, yoff, -px, cliph);
73 if (clipx + clipw < xoff || clipy + cliph < yoff)
76 const double img1w = static_cast<double>(image1->width());
77 const double img1h = static_cast<double>(image1->height());
79 double sx = w_asp * px;
80 double sy = h_asp * py;
82 double sw = ceil(w_asp*clipw); //round up, so it's never 0
83 double sh = ceil(h_asp*cliph);
85 double dx = std::max(xoff, clipx) - contentsX();
86 double dy = std::max(yoff, clipy) - contentsY();
88 image1->draw(p->device(), static_cast<int>(sx), static_cast<int>(sy), static_cast<int>(sw), static_cast<int>(sh), static_cast<int>(dx), static_cast<int>(dy), clipw, cliph);
91 // number of painted pixels
92 double painted_w = std::min(static_cast<double>(clipw), (img1w - sx)/w_asp);
93 double painted_h = std::min(static_cast<double>(cliph), (img1h - sy)/h_asp);
103 if ((painted_w < clipw) && (iangle & 1) == 0) //angle is 0 or 180 - left-right orientation
106 if (sx > img1w) //1st image was not drawn, part of 2nd image need to be painted only
108 sx = (static_cast<double>(clipx - xoff) - (img1w/w_asp))*w_asp;;
109 dx = std::max(static_cast<double>(xoff), static_cast<double>(clipx) - painted_w) - contentsX();
111 else //whole 2nd image to be painted
117 else if ((painted_h < cliph) && (iangle & 1)) //angle is 90 or 270 - top-bottom orientation
120 if (sy > img1h) //1st image was not drawn, part of 2nd image need to be painted only
122 sy = (static_cast<double>(clipy - yoff) - (img1h/h_asp))*h_asp;;
123 dy = std::max(static_cast<double>(yoff), static_cast<double>(clipy) - painted_h) - contentsY();
125 else //whole 2nd image to be painted
132 image2->draw(p->device(), static_cast<int>(sx), static_cast<int>(sy), static_cast<int>(sw), static_cast<int>(sh), static_cast<int>(dx), static_cast<int>(dy), clipw, cliph);
136 QPopupMenu *ComicImageView::contextMenu() const
141 bool ComicImageView::onTop()
143 return contentsY() == 0;
146 bool ComicImageView::onBottom()
148 return contentsY() + viewport()->height() >= contentsHeight();
151 void ComicImageView::contentsContextMenuEvent(QContextMenuEvent *e)
153 if (!orgimage[0].isEmpty())
154 context_menu->popup(e->globalPos());
157 void ComicImageView::setImage(ImlibImage *img, bool preserveangle)
164 orgimage[0].append(img);
166 if (iangle != 0 && !orgimage[0].isEmpty())
167 orgimage[0].current()->rotate(iangle);
172 repaintContents(0, 0 , viewport()->width(), viewport()->height());
175 void ComicImageView::setImage(ImlibImage *img1, ImlibImage *img2, bool preserveangle)
183 orgimage[0].append(img1);
184 orgimage[1].append(img2);
188 if (!orgimage[0].isEmpty())
189 orgimage[0].current()->rotate(iangle);
190 if (!orgimage[1].isEmpty())
191 orgimage[1].current()->rotate(iangle);
197 repaintContents(0, 0 , viewport()->width(), viewport()->height());
200 void ComicImageView::resizeEvent(QResizeEvent *e)
202 QScrollView::resizeEvent(e);
206 void ComicImageView::contentsWheelEvent(QWheelEvent *e)
209 if (e->delta() > 0) //scrolling up
211 if (contentsHeight()<=viewport()->height() || (onTop() && ++wheelupcnt > EXTRA_WHEEL_SPIN))
218 scrollBy(0, -3*spdy);
219 wheeldowncnt = 0; //reset opposite direction counter
222 else //scrolling down
224 if (contentsHeight()<=viewport()->height() || (onBottom() && ++wheeldowncnt > EXTRA_WHEEL_SPIN))
226 emit bottomReached();
232 wheelupcnt = 0; //reset opposite direction counter
237 void ComicImageView::contentsMouseMoveEvent(QMouseEvent *e)
241 const int dx = lx - e->x();
242 const int dy = ly - e->y();
244 lx = e->x() + dx; //need to add delta because e->x() is the old position
254 void ComicImageView::contentsMousePressEvent(QMouseEvent *e)
257 setCursor(Qt::PointingHandCursor);
260 void ComicImageView::contentsMouseReleaseEvent(QMouseEvent *e)
264 setCursor(Qt::ArrowCursor);
268 void ComicImageView::contentsMouseDoubleClickEvent(QMouseEvent *e)
273 void ComicImageView::updateImageSize()
275 if (orgimage[0].isEmpty())
277 if (orgimage[0].current()->width() * orgimage[0].current()->height() == 0)
283 // calculate iw, ih - the size of total image(s) area without scaling;
284 // roatation angle of 2nd image is taken into account
285 double iw = orgimage[0].current()->width();
286 double ih = orgimage[0].current()->height();
288 if (!orgimage[1].isEmpty())
292 ih += orgimage[1].current()->height();
293 if (orgimage[1].current()->width() > iw)
294 iw = orgimage[1].current()->width();
298 iw += orgimage[1].current()->width();
299 if (orgimage[1].current()->height() > ih)
300 ih = orgimage[1].current()->height();
324 w_asp = h_asp = 1.0f;
325 if (size == Original)
327 dw = static_cast<int>(iw);
328 dh = static_cast<int>(ih);
332 asp = (double)iw / ih;
334 if (size == FitWidth)
336 w_asp = iw / viewport()->width();
340 else if (size == FitHeight)
342 h_asp = ih / viewport()->height();
345 else if (size == WholePage)
347 w_asp = iw / viewport()->width();
348 h_asp = ih / viewport()->height();
355 dw = static_cast<int>(iw / w_asp);
356 dh = static_cast<int>(ih / h_asp);
363 // calculate offsets for image centering
364 if ((d = viewport()->width() - dw) > 0)
366 if ((d = viewport()->height() - dh) > 0)
369 resizeContents(dw + xoff, dh + yoff);
372 // update scrolling speeds
377 /*void ComicImageView::setScaling(Scaling s)
382 void ComicImageView::setRotation(Rotation r)
384 if (r == QComicBook::Right)
386 else if (r == QComicBook::Left)
390 for (int i=0; i<2; i++)
391 if (!orgimage[i].isEmpty())
393 if (r == QComicBook::Right)
394 orgimage[i].current()->rotate(1);
395 else if (r == QComicBook::Left)
396 orgimage[i].current()->rotate(3);
397 else if (r == QComicBook::None && iangle != 0)
399 orgimage[i].current()->rotate(4-iangle);
405 repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height(), true);
408 void ComicImageView::setSize(Size s)
412 repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height(), true);
415 void ComicImageView::setSizeOriginal()
420 void ComicImageView::setSizeFitWidth()
425 void ComicImageView::setSizeFitHeight()
430 void ComicImageView::setSizeWholePage()
435 void ComicImageView::setSizeBestFit()
440 void ComicImageView::scrollToTop()
445 void ComicImageView::scrollToBottom()
447 ensureVisible(1, contentsHeight());
450 void ComicImageView::scrollRight()
455 void ComicImageView::scrollLeft()
460 void ComicImageView::scrollRightFast()
465 void ComicImageView::scrollLeftFast()
467 scrollBy(-3*spdx, 0);
470 void ComicImageView::scrollUp()
474 wheelupcnt = wheeldowncnt = 0;
481 void ComicImageView::scrollDown()
485 wheelupcnt = wheeldowncnt = 0;
486 emit bottomReached();
492 void ComicImageView::scrollUpFast()
497 scrollBy(0, -3*spdy);
500 void ComicImageView::scrollDownFast()
503 emit bottomReached();
508 void ComicImageView::rotateRight()
510 setRotation(QComicBook::Right);
513 void ComicImageView::rotateLeft()
515 setRotation(QComicBook::Left);
518 void ComicImageView::resetRotation()
523 void ComicImageView::jumpUp()
528 scrollBy(0, -viewport()->height());
531 void ComicImageView::jumpDown()
534 emit bottomReached();
536 scrollBy(0, viewport()->height());
539 void ComicImageView::enableScrollbars(bool f)
541 ScrollBarMode s = f ? Auto : AlwaysOff;
542 setVScrollBarMode(s);
543 setHScrollBarMode(s);
546 void ComicImageView::setBackground(const QColor &color)
548 viewport()->setPaletteBackgroundColor(color);
551 void ComicImageView::setSmallCursor(bool f)
555 static unsigned char bmp_bits[4*32];
556 static unsigned char msk_bits[4*32];
561 for (int i=0; i<4*32; i++)
562 bmp_bits[i] = msk_bits[i] = 0;
563 bmp_bits[0] = msk_bits[0] = 0xe0;
566 bmp_bits[8] = msk_bits[8] = 0xe0;
567 const QBitmap bmp(32, 32, bmp_bits, false);
568 const QBitmap msk(32, 32, msk_bits, false);
569 smallcursor = new QCursor(bmp, msk, 0, 0);
570 setCursor(*smallcursor);
577 setCursor(Qt::ArrowCursor);
581 void ComicImageView::clear()
585 resizeContents(0, 0);
588 Size ComicImageView::getSize() const
593 int ComicImageView::imageWidth() const
595 if (!orgimage[0].isEmpty())
596 return orgimage[0].current()->width();