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);
32 orgimage[0].setAutoDelete(true);
33 orgimage[1].setAutoDelete(true);
34 w[0] = h[0] = w[1] = h[1] = 0;
37 ComicImageView::~ComicImageView()
43 void ComicImageView::drawContents(QPainter *p, int clipx, int clipy, int clipw, int cliph)
45 if (orgimage[0].isEmpty())
48 ImlibImage *image1, *image2;
51 if (iangle > 1 && !orgimage[1].isEmpty()) //switch image pointers to reflect rotation angle
53 image1 = orgimage[1].getFirst();
54 image2 = orgimage[0].getFirst();
58 image1 = orgimage[0].getFirst();
59 image2 = orgimage[1].getFirst();
62 int px = clipx - xoff;
63 int py = clipy - yoff;
65 if (py < 0 ) //clear strip on the top
67 p->eraseRect(clipx, clipy, clipw, -py);
70 if (px < 0) //clear strip on the left
72 p->eraseRect(clipx, yoff, -px, cliph);
76 if (clipx + clipw < xoff || clipy + cliph < yoff)
79 const double img1w = static_cast<double>(image1->width());
80 const double img1h = static_cast<double>(image1->height());
82 double sx = w_asp * px;
83 double sy = h_asp * py;
85 double sw = ceil(w_asp*clipw); //round up, so it's never 0
86 double sh = ceil(h_asp*cliph);
88 double dx = std::max(xoff, clipx) - contentsX();
89 double dy = std::max(yoff, clipy) - contentsY();
91 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);
94 // number of painted pixels
95 double painted_w = std::min(static_cast<double>(clipw), (img1w - sx)/w_asp);
96 double painted_h = std::min(static_cast<double>(cliph), (img1h - sy)/h_asp);
106 if ((painted_w < clipw) && (iangle & 1) == 0) //angle is 0 or 180 - left-right orientation
109 if (sx > img1w) //1st image was not drawn, part of 2nd image need to be painted only
111 sx = (static_cast<double>(clipx - xoff) - (img1w/w_asp))*w_asp;;
112 dx = std::max(static_cast<double>(xoff), static_cast<double>(clipx) - painted_w) - contentsX();
114 else //whole 2nd image to be painted
120 else if ((painted_h < cliph) && (iangle & 1)) //angle is 90 or 270 - top-bottom orientation
123 if (sy > img1h) //1st image was not drawn, part of 2nd image need to be painted only
125 sy = (static_cast<double>(clipy - yoff) - (img1h/h_asp))*h_asp;;
126 dy = std::max(static_cast<double>(yoff), static_cast<double>(clipy) - painted_h) - contentsY();
128 else //whole 2nd image to be painted
135 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);
139 QPopupMenu *ComicImageView::contextMenu() const
144 bool ComicImageView::onTop()
146 return contentsY() == 0;
149 bool ComicImageView::onBottom()
151 return contentsY() + viewport()->height() >= contentsHeight();
154 void ComicImageView::contentsContextMenuEvent(QContextMenuEvent *e)
156 if (!orgimage[0].isEmpty())
157 context_menu->popup(e->globalPos());
160 void ComicImageView::setImage(ImlibImage *img, bool preserveangle)
167 orgimage[0].append(img);
169 if (iangle != 0 && !orgimage[0].isEmpty())
170 orgimage[0].getFirst()->rotate(iangle);
176 repaintContents(0, 0 , viewport()->width(), viewport()->height());
179 void ComicImageView::setImage(ImlibImageList &imglist, bool preserveangle)
187 orgimage[0] = imglist;
189 if (iangle != 0 && !orgimage[0].isEmpty())
190 orgimage[0].getFirst()->rotate(iangle);
196 repaintContents(0, 0 , viewport()->width(), viewport()->height());
199 void ComicImageView::setImage(ImlibImage *img1, ImlibImage *img2, bool preserveangle)
207 orgimage[0].append(img1);
208 orgimage[1].append(img2);
212 if (!orgimage[0].isEmpty())
213 orgimage[0].getFirst()->rotate(iangle);
214 if (!orgimage[1].isEmpty())
215 orgimage[1].getFirst()->rotate(iangle);
222 repaintContents(0, 0 , viewport()->width(), viewport()->height());
225 void ComicImageView::setImage(ImlibImageList &imglist1, ImlibImageList &imglist2, bool preserveangle)
233 orgimage[0] = imglist1;
234 orgimage[1] = imglist2;
238 if (!orgimage[0].isEmpty())
239 orgimage[0].getFirst()->rotate(iangle);
240 if (!orgimage[1].isEmpty())
241 orgimage[1].getFirst()->rotate(iangle);
248 repaintContents(0, 0 , viewport()->width(), viewport()->height());
251 void ComicImageView::resizeEvent(QResizeEvent *e)
253 QScrollView::resizeEvent(e);
257 void ComicImageView::contentsWheelEvent(QWheelEvent *e)
260 if (e->delta() > 0) //scrolling up
262 if (contentsHeight()<=viewport()->height() || (onTop() && ++wheelupcnt > EXTRA_WHEEL_SPIN))
269 scrollBy(0, -3*spdy);
270 wheeldowncnt = 0; //reset opposite direction counter
273 else //scrolling down
275 if (contentsHeight()<=viewport()->height() || (onBottom() && ++wheeldowncnt > EXTRA_WHEEL_SPIN))
277 emit bottomReached();
283 wheelupcnt = 0; //reset opposite direction counter
288 void ComicImageView::contentsMouseMoveEvent(QMouseEvent *e)
292 const int dx = lx - e->x();
293 const int dy = ly - e->y();
295 lx = e->x() + dx; //need to add delta because e->x() is the old position
305 void ComicImageView::contentsMousePressEvent(QMouseEvent *e)
308 setCursor(Qt::PointingHandCursor);
311 void ComicImageView::contentsMouseReleaseEvent(QMouseEvent *e)
315 setCursor(Qt::ArrowCursor);
319 void ComicImageView::contentsMouseDoubleClickEvent(QMouseEvent *e)
324 void ComicImageView::calcStripeSize()
328 for (int i = 0 ; i < 2; ++i)
332 if (!orgimage[i].isEmpty())
334 for (img = orgimage[i].first(); img != NULL; img = orgimage[i].next())
336 if (img->width() > w[i])
342 for (img = orgimage[i].first(); img != NULL; img = orgimage[i].next())
344 if (img->width() > 0)
345 h[i] += img->height()*w[i]/img->width();
352 void ComicImageView::updateImageSize()
354 if (orgimage[0].isEmpty())
360 // calculate iw, ih - the size of total image(s) area without scaling;
361 // roatation angle of 2nd image is taken into account
362 // Total area is initially the same as the left area
363 double iw(w[0]), ih(h[0]);
365 if (!orgimage[1].isEmpty())
401 w_asp = h_asp = 1.0f;
402 if (size == Original)
404 dw = static_cast<int>(iw);
405 dh = static_cast<int>(ih);
409 asp = (double)iw / ih;
411 if (size == FitWidth)
413 w_asp = iw / viewport()->width();
417 else if (size == FitHeight)
419 h_asp = ih / viewport()->height();
422 else if (size == WholePage)
424 w_asp = iw / viewport()->width();
425 h_asp = ih / viewport()->height();
432 dw = static_cast<int>(iw / w_asp);
433 dh = static_cast<int>(ih / h_asp);
440 // calculate offsets for image centering
441 if ((d = viewport()->width() - dw) > 0)
443 if ((d = viewport()->height() - dh) > 0)
446 resizeContents(dw + xoff, dh + yoff);
449 // update scrolling speeds
454 /*void ComicImageView::setScaling(Scaling s)
459 void ComicImageView::setRotation(Rotation r)
461 if (r == QComicBook::Right)
463 else if (r == QComicBook::Left)
467 for (int i=0; i<2; i++)
468 if (!orgimage[i].isEmpty())
470 if (r == QComicBook::Right)
471 orgimage[i].getFirst()->rotate(1);
472 else if (r == QComicBook::Left)
473 orgimage[i].getFirst()->rotate(3);
474 else if (r == QComicBook::None && iangle != 0)
476 orgimage[i].getFirst()->rotate(4-iangle);
482 repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height(), true);
485 void ComicImageView::setSize(Size s)
489 repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height(), true);
492 void ComicImageView::setSizeOriginal()
497 void ComicImageView::setSizeFitWidth()
502 void ComicImageView::setSizeFitHeight()
507 void ComicImageView::setSizeWholePage()
512 void ComicImageView::setSizeBestFit()
517 void ComicImageView::scrollToTop()
522 void ComicImageView::scrollToBottom()
524 ensureVisible(1, contentsHeight());
527 void ComicImageView::scrollRight()
532 void ComicImageView::scrollLeft()
537 void ComicImageView::scrollRightFast()
542 void ComicImageView::scrollLeftFast()
544 scrollBy(-3*spdx, 0);
547 void ComicImageView::scrollUp()
551 wheelupcnt = wheeldowncnt = 0;
558 void ComicImageView::scrollDown()
562 wheelupcnt = wheeldowncnt = 0;
563 emit bottomReached();
569 void ComicImageView::scrollUpFast()
574 scrollBy(0, -3*spdy);
577 void ComicImageView::scrollDownFast()
580 emit bottomReached();
585 void ComicImageView::rotateRight()
587 setRotation(QComicBook::Right);
590 void ComicImageView::rotateLeft()
592 setRotation(QComicBook::Left);
595 void ComicImageView::resetRotation()
600 void ComicImageView::jumpUp()
605 scrollBy(0, -viewport()->height());
608 void ComicImageView::jumpDown()
611 emit bottomReached();
613 scrollBy(0, viewport()->height());
616 void ComicImageView::enableScrollbars(bool f)
618 ScrollBarMode s = f ? Auto : AlwaysOff;
619 setVScrollBarMode(s);
620 setHScrollBarMode(s);
623 void ComicImageView::setBackground(const QColor &color)
625 viewport()->setPaletteBackgroundColor(color);
628 void ComicImageView::setSmallCursor(bool f)
632 static unsigned char bmp_bits[4*32];
633 static unsigned char msk_bits[4*32];
638 for (int i=0; i<4*32; i++)
639 bmp_bits[i] = msk_bits[i] = 0;
640 bmp_bits[0] = msk_bits[0] = 0xe0;
643 bmp_bits[8] = msk_bits[8] = 0xe0;
644 const QBitmap bmp(32, 32, bmp_bits, false);
645 const QBitmap msk(32, 32, msk_bits, false);
646 smallcursor = new QCursor(bmp, msk, 0, 0);
647 setCursor(*smallcursor);
654 setCursor(Qt::ArrowCursor);
658 void ComicImageView::clear()
662 resizeContents(0, 0);
665 Size ComicImageView::getSize() const
670 int ComicImageView::imageWidth() const