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].getFirst();
53 image2 = orgimage[0].getFirst();
57 image1 = orgimage[0].getFirst();
58 image2 = orgimage[1].getFirst();
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].getFirst()->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].getFirst()->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].getFirst()->rotate(iangle);
211 if (!orgimage[1].isEmpty())
212 orgimage[1].getFirst()->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].getFirst()->rotate(iangle);
236 if (!orgimage[1].isEmpty())
237 orgimage[1].getFirst()->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())
327 // calculate iw, ih - the size of total image(s) area without scaling;
328 // roatation angle of 2nd image is taken into account
333 // We calculate the width and height of the left column of images:
334 // the width is the maximum width of the components.
335 for (img = orgimage[0].first(); img != NULL; img = orgimage[0].next())
337 if (img->width() > lw)
343 // The height is the sum of all the heights when the items have been
344 // scaled to have all the same (maximum) width
345 for (img = orgimage[0].first(); img != NULL; img = orgimage[0].next())
347 if (img->width() > 0)
348 lh += img->height()*lw/img->width();
351 // Total area is initially the same as the left area
355 if (!orgimage[1].isEmpty())
357 // If we have a second column of images too, first we
358 // calculate its width and height, as we did for the left side
359 for (img = orgimage[1].first(); img != NULL; img = orgimage[1].next())
361 if (img->width() > rw)
366 for (img = orgimage[1].first(); img != NULL; img = orgimage[1].next())
368 if (img->width() > 0)
369 rh += img->height()*rw/img->width();
408 w_asp = h_asp = 1.0f;
409 if (size == Original)
411 dw = static_cast<int>(iw);
412 dh = static_cast<int>(ih);
416 asp = (double)iw / ih;
418 if (size == FitWidth)
420 w_asp = iw / viewport()->width();
424 else if (size == FitHeight)
426 h_asp = ih / viewport()->height();
429 else if (size == WholePage)
431 w_asp = iw / viewport()->width();
432 h_asp = ih / viewport()->height();
439 dw = static_cast<int>(iw / w_asp);
440 dh = static_cast<int>(ih / h_asp);
447 // calculate offsets for image centering
448 if ((d = viewport()->width() - dw) > 0)
450 if ((d = viewport()->height() - dh) > 0)
453 resizeContents(dw + xoff, dh + yoff);
456 // update scrolling speeds
461 /*void ComicImageView::setScaling(Scaling s)
466 void ComicImageView::setRotation(Rotation r)
468 if (r == QComicBook::Right)
470 else if (r == QComicBook::Left)
474 for (int i=0; i<2; i++)
475 if (!orgimage[i].isEmpty())
477 if (r == QComicBook::Right)
478 orgimage[i].getFirst()->rotate(1);
479 else if (r == QComicBook::Left)
480 orgimage[i].getFirst()->rotate(3);
481 else if (r == QComicBook::None && iangle != 0)
483 orgimage[i].getFirst()->rotate(4-iangle);
489 repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height(), true);
492 void ComicImageView::setSize(Size s)
496 repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height(), true);
499 void ComicImageView::setSizeOriginal()
504 void ComicImageView::setSizeFitWidth()
509 void ComicImageView::setSizeFitHeight()
514 void ComicImageView::setSizeWholePage()
519 void ComicImageView::setSizeBestFit()
524 void ComicImageView::scrollToTop()
529 void ComicImageView::scrollToBottom()
531 ensureVisible(1, contentsHeight());
534 void ComicImageView::scrollRight()
539 void ComicImageView::scrollLeft()
544 void ComicImageView::scrollRightFast()
549 void ComicImageView::scrollLeftFast()
551 scrollBy(-3*spdx, 0);
554 void ComicImageView::scrollUp()
558 wheelupcnt = wheeldowncnt = 0;
565 void ComicImageView::scrollDown()
569 wheelupcnt = wheeldowncnt = 0;
570 emit bottomReached();
576 void ComicImageView::scrollUpFast()
581 scrollBy(0, -3*spdy);
584 void ComicImageView::scrollDownFast()
587 emit bottomReached();
592 void ComicImageView::rotateRight()
594 setRotation(QComicBook::Right);
597 void ComicImageView::rotateLeft()
599 setRotation(QComicBook::Left);
602 void ComicImageView::resetRotation()
607 void ComicImageView::jumpUp()
612 scrollBy(0, -viewport()->height());
615 void ComicImageView::jumpDown()
618 emit bottomReached();
620 scrollBy(0, viewport()->height());
623 void ComicImageView::enableScrollbars(bool f)
625 ScrollBarMode s = f ? Auto : AlwaysOff;
626 setVScrollBarMode(s);
627 setHScrollBarMode(s);
630 void ComicImageView::setBackground(const QColor &color)
632 viewport()->setPaletteBackgroundColor(color);
635 void ComicImageView::setSmallCursor(bool f)
639 static unsigned char bmp_bits[4*32];
640 static unsigned char msk_bits[4*32];
645 for (int i=0; i<4*32; i++)
646 bmp_bits[i] = msk_bits[i] = 0;
647 bmp_bits[0] = msk_bits[0] = 0xe0;
650 bmp_bits[8] = msk_bits[8] = 0xe0;
651 const QBitmap bmp(32, 32, bmp_bits, false);
652 const QBitmap msk(32, 32, msk_bits, false);
653 smallcursor = new QCursor(bmp, msk, 0, 0);
654 setCursor(*smallcursor);
661 setCursor(Qt::ArrowCursor);
665 void ComicImageView::clear()
669 resizeContents(0, 0);
672 Size ComicImageView::getSize() const
677 int ComicImageView::imageWidth() const
679 if (!orgimage[0].isEmpty())
680 return orgimage[0].getFirst()->width();