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);
36 ComicImageView::~ComicImageView()
42 void ComicImageView::drawContents(QPainter *p, int clipx, int clipy, int clipw, int cliph)
44 if (orgimage[0].isEmpty())
47 ImlibImage *image1, *image2;
50 if (iangle > 1 && !orgimage[1].isEmpty()) //switch image pointers to reflect rotation angle
52 image1 = orgimage[1].current();
53 image2 = orgimage[0].current();
57 image1 = orgimage[0].current();
58 image2 = orgimage[1].current();
61 int px = clipx - xoff;
62 int py = clipy - yoff;
64 if (py < 0 ) //clear strip on the top
66 p->eraseRect(clipx, clipy, clipw, -py);
69 if (px < 0) //clear strip on the left
71 p->eraseRect(clipx, yoff, -px, cliph);
75 if (clipx + clipw < xoff || clipy + cliph < yoff)
78 const double img1w = static_cast<double>(image1->width());
79 const double img1h = static_cast<double>(image1->height());
81 double sx = w_asp * px;
82 double sy = h_asp * py;
84 double sw = ceil(w_asp*clipw); //round up, so it's never 0
85 double sh = ceil(h_asp*cliph);
87 double dx = std::max(xoff, clipx) - contentsX();
88 double dy = std::max(yoff, clipy) - contentsY();
90 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);
93 // number of painted pixels
94 double painted_w = std::min(static_cast<double>(clipw), (img1w - sx)/w_asp);
95 double painted_h = std::min(static_cast<double>(cliph), (img1h - sy)/h_asp);
105 if ((painted_w < clipw) && (iangle & 1) == 0) //angle is 0 or 180 - left-right orientation
108 if (sx > img1w) //1st image was not drawn, part of 2nd image need to be painted only
110 sx = (static_cast<double>(clipx - xoff) - (img1w/w_asp))*w_asp;;
111 dx = std::max(static_cast<double>(xoff), static_cast<double>(clipx) - painted_w) - contentsX();
113 else //whole 2nd image to be painted
119 else if ((painted_h < cliph) && (iangle & 1)) //angle is 90 or 270 - top-bottom orientation
122 if (sy > img1h) //1st image was not drawn, part of 2nd image need to be painted only
124 sy = (static_cast<double>(clipy - yoff) - (img1h/h_asp))*h_asp;;
125 dy = std::max(static_cast<double>(yoff), static_cast<double>(clipy) - painted_h) - contentsY();
127 else //whole 2nd image to be painted
134 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);
138 QPopupMenu *ComicImageView::contextMenu() const
143 bool ComicImageView::onTop()
145 return contentsY() == 0;
148 bool ComicImageView::onBottom()
150 return contentsY() + viewport()->height() >= contentsHeight();
153 void ComicImageView::contentsContextMenuEvent(QContextMenuEvent *e)
155 if (!orgimage[0].isEmpty())
156 context_menu->popup(e->globalPos());
159 void ComicImageView::setImage(ImlibImage *img, bool preserveangle)
166 orgimage[0].append(img);
168 if (iangle != 0 && !orgimage[0].isEmpty())
169 orgimage[0].current()->rotate(iangle);
174 repaintContents(0, 0 , viewport()->width(), viewport()->height());
177 void ComicImageView::setImage(ImlibImageList &imglist, bool preserveangle)
185 orgimage[0] = imglist;
187 if (iangle != 0 && !orgimage[0].isEmpty())
188 orgimage[0].current()->rotate(iangle);
193 repaintContents(0, 0 , viewport()->width(), viewport()->height());
196 void ComicImageView::setImage(ImlibImage *img1, ImlibImage *img2, bool preserveangle)
204 orgimage[0].append(img1);
205 orgimage[1].append(img2);
209 if (!orgimage[0].isEmpty())
210 orgimage[0].current()->rotate(iangle);
211 if (!orgimage[1].isEmpty())
212 orgimage[1].current()->rotate(iangle);
218 repaintContents(0, 0 , viewport()->width(), viewport()->height());
221 void ComicImageView::setImage(ImlibImageList &imglist1, ImlibImageList &imglist2, bool preserveangle)
229 orgimage[0] = imglist1;
230 orgimage[1] = imglist2;
234 if (!orgimage[0].isEmpty())
235 orgimage[0].current()->rotate(iangle);
236 if (!orgimage[1].isEmpty())
237 orgimage[1].current()->rotate(iangle);
243 repaintContents(0, 0 , viewport()->width(), viewport()->height());
246 void ComicImageView::resizeEvent(QResizeEvent *e)
248 QScrollView::resizeEvent(e);
252 void ComicImageView::contentsWheelEvent(QWheelEvent *e)
255 if (e->delta() > 0) //scrolling up
257 if (contentsHeight()<=viewport()->height() || (onTop() && ++wheelupcnt > EXTRA_WHEEL_SPIN))
264 scrollBy(0, -3*spdy);
265 wheeldowncnt = 0; //reset opposite direction counter
268 else //scrolling down
270 if (contentsHeight()<=viewport()->height() || (onBottom() && ++wheeldowncnt > EXTRA_WHEEL_SPIN))
272 emit bottomReached();
278 wheelupcnt = 0; //reset opposite direction counter
283 void ComicImageView::contentsMouseMoveEvent(QMouseEvent *e)
287 const int dx = lx - e->x();
288 const int dy = ly - e->y();
290 lx = e->x() + dx; //need to add delta because e->x() is the old position
300 void ComicImageView::contentsMousePressEvent(QMouseEvent *e)
303 setCursor(Qt::PointingHandCursor);
306 void ComicImageView::contentsMouseReleaseEvent(QMouseEvent *e)
310 setCursor(Qt::ArrowCursor);
314 void ComicImageView::contentsMouseDoubleClickEvent(QMouseEvent *e)
319 void ComicImageView::updateImageSize()
321 if (orgimage[0].isEmpty())
323 if (orgimage[0].current()->width() * orgimage[0].current()->height() == 0)
329 // calculate iw, ih - the size of total image(s) area without scaling;
330 // roatation angle of 2nd image is taken into account
331 double iw = orgimage[0].current()->width();
332 double ih = orgimage[0].current()->height();
334 if (!orgimage[1].isEmpty())
338 ih += orgimage[1].current()->height();
339 if (orgimage[1].current()->width() > iw)
340 iw = orgimage[1].current()->width();
344 iw += orgimage[1].current()->width();
345 if (orgimage[1].current()->height() > ih)
346 ih = orgimage[1].current()->height();
370 w_asp = h_asp = 1.0f;
371 if (size == Original)
373 dw = static_cast<int>(iw);
374 dh = static_cast<int>(ih);
378 asp = (double)iw / ih;
380 if (size == FitWidth)
382 w_asp = iw / viewport()->width();
386 else if (size == FitHeight)
388 h_asp = ih / viewport()->height();
391 else if (size == WholePage)
393 w_asp = iw / viewport()->width();
394 h_asp = ih / viewport()->height();
401 dw = static_cast<int>(iw / w_asp);
402 dh = static_cast<int>(ih / h_asp);
409 // calculate offsets for image centering
410 if ((d = viewport()->width() - dw) > 0)
412 if ((d = viewport()->height() - dh) > 0)
415 resizeContents(dw + xoff, dh + yoff);
418 // update scrolling speeds
423 /*void ComicImageView::setScaling(Scaling s)
428 void ComicImageView::setRotation(Rotation r)
430 if (r == QComicBook::Right)
432 else if (r == QComicBook::Left)
436 for (int i=0; i<2; i++)
437 if (!orgimage[i].isEmpty())
439 if (r == QComicBook::Right)
440 orgimage[i].current()->rotate(1);
441 else if (r == QComicBook::Left)
442 orgimage[i].current()->rotate(3);
443 else if (r == QComicBook::None && iangle != 0)
445 orgimage[i].current()->rotate(4-iangle);
451 repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height(), true);
454 void ComicImageView::setSize(Size s)
458 repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height(), true);
461 void ComicImageView::setSizeOriginal()
466 void ComicImageView::setSizeFitWidth()
471 void ComicImageView::setSizeFitHeight()
476 void ComicImageView::setSizeWholePage()
481 void ComicImageView::setSizeBestFit()
486 void ComicImageView::scrollToTop()
491 void ComicImageView::scrollToBottom()
493 ensureVisible(1, contentsHeight());
496 void ComicImageView::scrollRight()
501 void ComicImageView::scrollLeft()
506 void ComicImageView::scrollRightFast()
511 void ComicImageView::scrollLeftFast()
513 scrollBy(-3*spdx, 0);
516 void ComicImageView::scrollUp()
520 wheelupcnt = wheeldowncnt = 0;
527 void ComicImageView::scrollDown()
531 wheelupcnt = wheeldowncnt = 0;
532 emit bottomReached();
538 void ComicImageView::scrollUpFast()
543 scrollBy(0, -3*spdy);
546 void ComicImageView::scrollDownFast()
549 emit bottomReached();
554 void ComicImageView::rotateRight()
556 setRotation(QComicBook::Right);
559 void ComicImageView::rotateLeft()
561 setRotation(QComicBook::Left);
564 void ComicImageView::resetRotation()
569 void ComicImageView::jumpUp()
574 scrollBy(0, -viewport()->height());
577 void ComicImageView::jumpDown()
580 emit bottomReached();
582 scrollBy(0, viewport()->height());
585 void ComicImageView::enableScrollbars(bool f)
587 ScrollBarMode s = f ? Auto : AlwaysOff;
588 setVScrollBarMode(s);
589 setHScrollBarMode(s);
592 void ComicImageView::setBackground(const QColor &color)
594 viewport()->setPaletteBackgroundColor(color);
597 void ComicImageView::setSmallCursor(bool f)
601 static unsigned char bmp_bits[4*32];
602 static unsigned char msk_bits[4*32];
607 for (int i=0; i<4*32; i++)
608 bmp_bits[i] = msk_bits[i] = 0;
609 bmp_bits[0] = msk_bits[0] = 0xe0;
612 bmp_bits[8] = msk_bits[8] = 0xe0;
613 const QBitmap bmp(32, 32, bmp_bits, false);
614 const QBitmap msk(32, 32, msk_bits, false);
615 smallcursor = new QCursor(bmp, msk, 0, 0);
616 setCursor(*smallcursor);
623 setCursor(Qt::ArrowCursor);
627 void ComicImageView::clear()
631 resizeContents(0, 0);
634 Size ComicImageView::getSize() const
639 int ComicImageView::imageWidth() const
641 if (!orgimage[0].isEmpty())
642 return orgimage[0].current()->width();