00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <qpixmap.h>
00021 #include <qimage.h>
00022 #include <qlayout.h>
00023 #include <qpainter.h>
00024 #include <qframe.h>
00025 #include <qlabel.h>
00026 #include <qtoolbutton.h>
00027 #include <qslider.h>
00028 #include <qcursor.h>
00029
00030 #include <kdebug.h>
00031 #include <kglobalsettings.h>
00032 #include <kaction.h>
00033 #include <ktoolbar.h>
00034 #include <knuminput.h>
00035 #include <klocale.h>
00036
00037 #include <KoDocument.h>
00038
00039 #include "wdgbirdeye.h"
00040 #include "kobirdeyepanel.h"
00041 #include "kis_int_spinbox.h"
00042
00043 KoCanvasAdapter::KoCanvasAdapter() {}
00044 KoCanvasAdapter::~KoCanvasAdapter() {}
00045
00046 KoZoomAdapter::KoZoomAdapter() {}
00047 KoZoomAdapter::~KoZoomAdapter() {}
00048
00049 KoThumbnailAdapter::KoThumbnailAdapter() {}
00050 KoThumbnailAdapter::~KoThumbnailAdapter() {}
00051
00052 KoBirdEyePanel::KoBirdEyePanel( KoZoomAdapter * zoomListener,
00053 KoThumbnailAdapter * thumbnailProvider,
00054 KoCanvasAdapter * canvas,
00055 QWidget * parent,
00056 const char * name,
00057 WFlags f)
00058 : QWidget(parent, name, f)
00059 , m_zoomListener(zoomListener)
00060 , m_thumbnailProvider(thumbnailProvider)
00061 , m_canvas(canvas)
00062 , m_dragging(false)
00063 {
00064 QHBoxLayout * l = new QHBoxLayout(this);
00065 m_page = new WdgBirdEye(this);
00066 m_page->zoom->setRange((int) (QMAX(1, 100 * zoomListener->getMinZoom())), (int) (100 * zoomListener->getMaxZoom()));
00067 m_page->zoom->setValue(100);
00068 m_page->zoom->setSuffix("%");
00069
00070 m_page->toolbar->setIconSize(16);
00071 m_page->view->installEventFilter(this);
00072 m_page->view->setBackgroundMode(Qt::NoBackground);
00073
00074 m_zoomIn = new KAction( i18n("Zoom In"), "birdeye_zoom_plus", 0, this, SLOT(zoomPlus()), this, "zoomIn" );
00075 m_zoomOut = new KAction( i18n("Zoom Out"), "birdeye_zoom_minus", 0, this, SLOT(zoomMinus()), this, "zoomOut" );
00076
00077 l->addWidget(m_page);
00078
00079 connect(m_page->zoom, SIGNAL(valueChanged(int)), SLOT(zoomValueChanged(int)));
00080 connect(m_page->bn100, SIGNAL(clicked()), SLOT(zoom100()));
00081 connect(m_page->slZoom, SIGNAL(valueChanged(int)), SLOT(sliderChanged( int )));
00082 }
00083
00084 KoBirdEyePanel::~KoBirdEyePanel()
00085 {
00086 delete m_canvas;
00087 delete m_thumbnailProvider;
00088 delete m_zoomListener;
00089 }
00090
00091 void KoBirdEyePanel::setZoom(int zoom)
00092 {
00093 m_page->zoom->blockSignals(true);
00094 m_page->slZoom->blockSignals(true);
00095
00096 m_page->zoom->setValue(zoom);
00097
00098 if (zoom < 10) {
00099 m_page->slZoom->setValue(0);
00100 }
00101 else if (zoom > 10 && zoom < 100) {
00102 m_page->slZoom->setValue(zoom / 10);
00103 }
00104 else if (zoom >= 100 && zoom < 150) {
00105 m_page->slZoom->setValue(10);
00106 }
00107 else if (zoom >= 150 && zoom < 250) {
00108 m_page->slZoom->setValue(11);
00109 }
00110 else if (zoom >= 250 && zoom < 350) {
00111 m_page->slZoom->setValue(12);
00112 }
00113 else if (zoom >= 350 && zoom < 450) {
00114 m_page->slZoom->setValue(13);
00115 }
00116 else if (zoom >= 450 && zoom < 550) {
00117 m_page->slZoom->setValue(14);
00118 }
00119 else if (zoom >= 550 && zoom < 650) {
00120 m_page->slZoom->setValue(15);
00121 }
00122 else if (zoom >= 650 && zoom < 875) {
00123 m_page->slZoom->setValue(16);
00124 }
00125 else if (zoom >= 875 && zoom < 1150) {
00126 m_page->slZoom->setValue(17);
00127 }
00128 else if (zoom >= 1150 && zoom < 1450) {
00129 m_page->slZoom->setValue(18);
00130 }
00131 else if (zoom >= 1450) {
00132 m_page->slZoom->setValue(19);
00133 }
00134
00135
00136 m_page->zoom->blockSignals(false);
00137 m_page->slZoom->blockSignals(false);
00138
00139
00140 }
00141
00142 void KoBirdEyePanel::zoomValueChanged(int zoom)
00143 {
00144 KoPoint center;
00145 center = m_canvas->visibleArea().center();
00146 m_zoomListener->zoomTo(center.x(), center.y(), zoom / 100.0);
00147 setZoom(zoom);
00148 }
00149
00150 void KoBirdEyePanel::zoom100()
00151 {
00152 zoomValueChanged( 100 );
00153 }
00154
00155 void KoBirdEyePanel::sliderChanged( int v )
00156 {
00157 if (v < 10) {
00158 zoomValueChanged((v + 1) * 10);
00159 }
00160 else {
00161 switch(v) {
00162 case 10:
00163 zoomValueChanged(100);
00164 break;
00165 case 11:
00166 zoomValueChanged(200);
00167 break;
00168 case 12:
00169 zoomValueChanged(300);
00170 case 13:
00171 zoomValueChanged(400);
00172 break;
00173 case 14:
00174 zoomValueChanged(500);
00175 break;
00176 case 15:
00177 zoomValueChanged(600);
00178 break;
00179 case 16:
00180 zoomValueChanged(750);
00181 break;
00182 case 17:
00183 zoomValueChanged(1000);
00184 break;
00185 case 18:
00186 zoomValueChanged(1300);
00187 break;
00188 case 19:
00189 zoomValueChanged(1600);
00190 break;
00191 }
00192 }
00193 }
00194
00195 void KoBirdEyePanel::cursorPosChanged(Q_INT32 xpos, Q_INT32 ypos)
00196 {
00197 m_page->txtX->setText(QString("%L1").arg(xpos, 5));
00198 m_page->txtY->setText(QString("%L1").arg(ypos, 5));
00199 }
00200
00201 void KoBirdEyePanel::setThumbnailProvider(KoThumbnailAdapter * thumbnailProvider)
00202 {
00203 delete m_thumbnailProvider;
00204 m_thumbnailProvider = thumbnailProvider;
00205 }
00206
00207 void KoBirdEyePanel::slotViewTransformationChanged()
00208 {
00209 updateVisibleArea();
00210 renderView();
00211 m_page->view->update();
00212 setZoom(qRound(m_canvas->zoomFactor() * 100));
00213 }
00214
00215 void KoBirdEyePanel::slotUpdate(const QRect & r)
00216 {
00217 QRect updateRect = r;
00218
00219 if (m_thumbnailProvider->pixelSize() != m_documentSize) {
00220 m_documentSize = m_thumbnailProvider->pixelSize();
00221 fitThumbnailToView();
00222 updateRect = QRect(0, 0, m_documentSize.width(), m_documentSize.height());
00223 }
00224
00225 updateRect &= QRect(0, 0, m_documentSize.width(), m_documentSize.height());
00226
00227 if (!updateRect.isEmpty() && !m_documentSize.isEmpty()) {
00228
00229 QRect thumbnailRect = documentToThumbnail(KoRect::fromQRect(updateRect));
00230
00231 if (!thumbnailRect.isEmpty()) {
00232
00233 QImage thumbnailImage = m_thumbnailProvider->image(thumbnailRect, m_thumbnail.size());
00234
00235 if (!thumbnailImage.isNull()) {
00236
00237 Q_ASSERT(thumbnailImage.size() == thumbnailRect.size());
00238
00239 QPainter painter(&m_thumbnail);
00240
00241 painter.fillRect(thumbnailRect, colorGroup().mid());
00242 painter.drawImage(thumbnailRect.x(), thumbnailRect.y(), thumbnailImage);
00243 }
00244 }
00245 }
00246
00247 renderView();
00248 m_page->view->update();
00249 }
00250
00251 QRect KoBirdEyePanel::documentToThumbnail(const KoRect& docRect)
00252 {
00253 if (docRect.isEmpty() || m_documentSize.isEmpty() || m_thumbnail.isNull()) {
00254 return QRect();
00255 }
00256
00257 Q_INT32 thumbnailLeft = static_cast<Q_INT32>((docRect.left() * m_thumbnail.width()) / m_documentSize.width());
00258 Q_INT32 thumbnailRight = static_cast<Q_INT32>(((docRect.right() + 1) * m_thumbnail.width()) / m_documentSize.width());
00259 Q_INT32 thumbnailTop = static_cast<Q_INT32>((docRect.top() * m_thumbnail.height()) / m_documentSize.height());
00260 Q_INT32 thumbnailBottom = static_cast<Q_INT32>(((docRect.bottom() + 1) * m_thumbnail.height()) / m_documentSize.height());
00261
00262 QRect thumbnailRect(thumbnailLeft, thumbnailTop, thumbnailRight - thumbnailLeft + 1, thumbnailBottom - thumbnailTop + 1);
00263 thumbnailRect &= m_thumbnail.rect();
00264
00265 return thumbnailRect;
00266 }
00267
00268 KoRect KoBirdEyePanel::thumbnailToDocument(const QRect& thumbnailRect)
00269 {
00270 if (thumbnailRect.isEmpty() || m_documentSize.isEmpty() || m_thumbnail.isNull()) {
00271 return KoRect();
00272 }
00273
00274 double docLeft = (static_cast<double>(thumbnailRect.left()) * m_documentSize.width()) / m_thumbnail.width();
00275 double docRight = (static_cast<double>(thumbnailRect.right() + 1) * m_documentSize.width()) / m_thumbnail.width();
00276 double docTop = (static_cast<double>(thumbnailRect.top()) * m_documentSize.height()) / m_thumbnail.height();
00277 double docBottom = (static_cast<double>(thumbnailRect.bottom() + 1) * m_documentSize.height()) / m_thumbnail.height();
00278
00279 KoRect docRect(docLeft, docTop, docRight - docLeft + 1, docBottom - docTop + 1);
00280 docRect &= KoRect(0, 0, m_documentSize.width(), m_documentSize.height());
00281
00282 return docRect;
00283 }
00284
00285 QPoint KoBirdEyePanel::viewToThumbnail(const QPoint& viewPoint)
00286 {
00287 int thumbnailX = (m_viewBuffer.width() - m_thumbnail.width()) / 2;
00288 int thumbnailY = (m_viewBuffer.height() - m_thumbnail.height()) / 2;
00289
00290 return QPoint(viewPoint.x() - thumbnailX, viewPoint.y() - thumbnailY);
00291 }
00292
00293
00294 void KoBirdEyePanel::zoomMinus()
00295 {
00296 }
00297
00298 void KoBirdEyePanel::zoomPlus()
00299 {
00300 }
00301
00302 void KoBirdEyePanel::updateVisibleArea()
00303 {
00304 m_visibleAreaInThumbnail = documentToThumbnail(m_canvas->visibleArea());
00305 }
00306
00307
00308 bool KoBirdEyePanel::eventFilter(QObject* o, QEvent* ev)
00309 {
00310 if (o == m_page->view && ev->type() == QEvent::Resize) {
00311 resizeViewEvent(static_cast<QResizeEvent *>(ev)->size());
00312 }
00313
00314 if (o == m_page->view && ev->type() == QEvent::Paint) {
00315 paintViewEvent(static_cast<QPaintEvent *>(ev));
00316 }
00317
00318 if (o == m_page->view && ev->type() == QEvent::MouseMove) {
00319
00320 QMouseEvent* me = (QMouseEvent*)ev;
00321 QPoint thumbnailPos = viewToThumbnail(me->pos());
00322
00323 if (m_dragging) {
00324 handleMouseMoveAction(thumbnailPos);
00325 } else {
00326 handleMouseMove(thumbnailPos);
00327 }
00328
00329 return true;
00330 }
00331
00332 if (o == m_page->view && ev->type() == QEvent::MouseButtonPress) {
00333
00334 QMouseEvent* me = (QMouseEvent*)ev;
00335 QPoint thumbnailPos = viewToThumbnail(me->pos());
00336
00337 if (me->button() == LeftButton) {
00338 handleMousePress(thumbnailPos);
00339 }
00340
00341 return true;
00342 }
00343
00344 if (o == m_page->view && ev->type() == QEvent::MouseButtonRelease) {
00345
00346 QMouseEvent* me = (QMouseEvent*)ev;
00347
00348 if (me->button() == LeftButton) {
00349 m_dragging = false;
00350 }
00351
00352 return true;
00353 }
00354
00355 return m_page->eventFilter(o, ev);
00356 }
00357
00358 KoBirdEyePanel::enumDragHandle KoBirdEyePanel::dragHandleAt(QPoint p)
00359 {
00360 QRect left = QRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.top()-1, 3, m_visibleAreaInThumbnail.height()+2);
00361 QRect right = QRect(m_visibleAreaInThumbnail.right()-1, m_visibleAreaInThumbnail.top()-1, 3, m_visibleAreaInThumbnail.height()+2);
00362 QRect top = QRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.top()-1, m_visibleAreaInThumbnail.width()+2, 3);
00363 QRect bottom = QRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.bottom()-1, m_visibleAreaInThumbnail.width()+2, 3);
00364
00365 if (left.contains(p)) {
00366 return DragHandleLeft;
00367 }
00368
00369 if (right.contains(p)) {
00370 return DragHandleRight;
00371 }
00372
00373 if (top.contains(p)) {
00374 return DragHandleTop;
00375 }
00376
00377 if (bottom.contains(p)) {
00378 return DragHandleBottom;
00379 }
00380
00381 if (m_visibleAreaInThumbnail.contains(p)) {
00382 return DragHandleCentre;
00383 }
00384
00385 return DragHandleNone;
00386 }
00387
00388 void KoBirdEyePanel::handleMouseMove(QPoint p)
00389 {
00390 QCursor cursor;
00391
00392 switch (dragHandleAt(p)) {
00393 case DragHandleLeft:
00394 case DragHandleRight:
00395 cursor = Qt::sizeHorCursor;
00396 break;
00397 case DragHandleTop:
00398 case DragHandleBottom:
00399 cursor = Qt::sizeVerCursor;
00400 break;
00401 case DragHandleCentre:
00402 cursor = Qt::sizeAllCursor;
00403 break;
00404 default:
00405 case DragHandleNone:
00406 if (m_thumbnail.rect().contains(p)) {
00407 cursor = Qt::PointingHandCursor;
00408 } else {
00409 cursor = Qt::arrowCursor;
00410 }
00411 break;
00412 }
00413
00414 m_page->view->setCursor(cursor);
00415 }
00416
00417 void KoBirdEyePanel::handleMouseMoveAction(QPoint p)
00418 {
00419 if (m_dragging) {
00420
00421 Q_INT32 dx = p.x() - m_lastDragPos.x();
00422 Q_INT32 dy = p.y() - m_lastDragPos.y();
00423
00424 m_lastDragPos = p;
00425
00426 QRect thumbnailRect = m_visibleAreaInThumbnail;
00427
00428 switch (m_dragHandle) {
00429 case DragHandleLeft: {
00430 thumbnailRect.setLeft(thumbnailRect.left()+dx);
00431 break;
00432 }
00433 case DragHandleRight: {
00434 thumbnailRect.setRight(thumbnailRect.right()+dx);
00435 break;
00436 }
00437 case DragHandleTop: {
00438 thumbnailRect.setTop(thumbnailRect.top()+dy);
00439 break;
00440 }
00441 case DragHandleBottom: {
00442 thumbnailRect.setBottom(thumbnailRect.bottom()+dy);
00443 break;
00444 }
00445 case DragHandleCentre: {
00446 thumbnailRect.moveBy(dx, dy);
00447 break;
00448 }
00449 default:
00450 case DragHandleNone:
00451 break;
00452 }
00453
00454 makeThumbnailRectVisible(thumbnailRect);
00455 }
00456 }
00457
00458 void KoBirdEyePanel::handleMousePress(QPoint p)
00459 {
00460 if (!m_dragging) {
00461
00462 enumDragHandle dragHandle = dragHandleAt(p);
00463
00464 if (dragHandle == DragHandleNone) {
00465 if (m_thumbnail.rect().contains(p)) {
00466
00467
00468
00469 QRect thumbnailRect = m_visibleAreaInThumbnail;
00470 thumbnailRect.moveCenter(p);
00471 makeThumbnailRectVisible(thumbnailRect);
00472
00473 m_dragHandle = DragHandleCentre;
00474 m_page->view->setCursor(Qt::sizeAllCursor);
00475 m_dragging = true;
00476 }
00477 } else {
00478 m_dragHandle = dragHandle;
00479 m_dragging = true;
00480 }
00481 m_lastDragPos = p;
00482 }
00483 }
00484
00485 void KoBirdEyePanel::makeThumbnailRectVisible(const QRect& r)
00486 {
00487 if (r.isEmpty()) {
00488 return;
00489 }
00490
00491 QRect thumbnailRect = r;
00492
00493 if (thumbnailRect.left() < m_thumbnail.rect().left()) {
00494 thumbnailRect.moveLeft(m_thumbnail.rect().left());
00495 }
00496 if (thumbnailRect.right() > m_thumbnail.rect().right()) {
00497 thumbnailRect.moveRight(m_thumbnail.rect().right());
00498 }
00499 if (thumbnailRect.top() < m_thumbnail.rect().top()) {
00500 thumbnailRect.moveTop(m_thumbnail.rect().top());
00501 }
00502 if (thumbnailRect.bottom() > m_thumbnail.rect().bottom()) {
00503 thumbnailRect.moveBottom(m_thumbnail.rect().bottom());
00504 }
00505
00506 if (thumbnailRect.width() > m_thumbnail.rect().width()) {
00507 thumbnailRect.setLeft(m_thumbnail.rect().left());
00508 thumbnailRect.setRight(m_thumbnail.rect().right());
00509 }
00510 if (thumbnailRect.height() > m_thumbnail.rect().height()) {
00511 thumbnailRect.setTop(m_thumbnail.rect().top());
00512 thumbnailRect.setBottom(m_thumbnail.rect().bottom());
00513 }
00514
00515 double zoomFactor = m_canvas->zoomFactor();
00516
00517 if (thumbnailRect.size() == m_visibleAreaInThumbnail.size()) {
00518
00519 } else if (thumbnailRect.width() != m_visibleAreaInThumbnail.width()) {
00520
00521 Q_ASSERT(thumbnailRect.height() == m_visibleAreaInThumbnail.height());
00522
00523 zoomFactor *= static_cast<double>(m_visibleAreaInThumbnail.width()) / thumbnailRect.width();
00524 } else {
00525
00526 Q_ASSERT(thumbnailRect.width() == m_visibleAreaInThumbnail.width());
00527
00528 zoomFactor *= static_cast<double>(m_visibleAreaInThumbnail.height()) / thumbnailRect.height();
00529 }
00530
00531 if (zoomFactor < m_zoomListener->getMinZoom()) {
00532 zoomFactor = m_zoomListener->getMinZoom();
00533 } else if (zoomFactor > m_zoomListener->getMaxZoom()) {
00534 zoomFactor = m_zoomListener->getMaxZoom();
00535 }
00536
00537 KoRect docRect = thumbnailToDocument(thumbnailRect);
00538 m_zoomListener->zoomTo(docRect.center().x(), docRect.center().y(), zoomFactor);
00539 }
00540
00541 void KoBirdEyePanel::resizeViewEvent(QSize size)
00542 {
00543 m_viewBuffer.resize(size);
00544 fitThumbnailToView();
00545 slotUpdate(QRect(0, 0, m_documentSize.width(), m_documentSize.height()));
00546 }
00547
00548 void KoBirdEyePanel::fitThumbnailToView()
00549 {
00550 QRect docRect = QRect(0, 0, m_thumbnailProvider->pixelSize().width(), m_thumbnailProvider->pixelSize().height());
00551 Q_INT32 thumbnailWidth;
00552 Q_INT32 thumbnailHeight;
00553
00554 if (docRect.isEmpty()) {
00555 thumbnailWidth = 0;
00556 thumbnailHeight = 0;
00557 } else {
00558 const int thumbnailBorderPixels = 4;
00559
00560 double xScale = double(m_page->view->contentsRect().width() - thumbnailBorderPixels) / docRect.width();
00561 double yScale = double(m_page->view->contentsRect().height() - thumbnailBorderPixels) / docRect.height();
00562
00563 if (xScale < yScale) {
00564 thumbnailWidth = m_page->view->contentsRect().width() - thumbnailBorderPixels;
00565 thumbnailHeight = Q_INT32(ceil(docRect.height() * xScale));
00566 } else {
00567 thumbnailWidth = Q_INT32(ceil(docRect.width() * yScale));
00568 thumbnailHeight = m_page->view->contentsRect().height() - thumbnailBorderPixels;
00569 }
00570 }
00571
00572 m_thumbnail.resize(thumbnailWidth, thumbnailHeight);
00573 updateVisibleArea();
00574 }
00575
00576 void KoBirdEyePanel::renderView()
00577 {
00578 Q_ASSERT(!m_viewBuffer.isNull());
00579
00580 if (!m_viewBuffer.isNull()) {
00581
00582 updateVisibleArea();
00583
00584 QPainter painter(&m_viewBuffer);
00585
00586 painter.fillRect(0, 0, m_viewBuffer.width(), m_viewBuffer.height(), colorGroup().mid());
00587
00588 if (!m_thumbnail.isNull()) {
00589
00590 int thumbnailX = (m_viewBuffer.width() - m_thumbnail.width()) / 2;
00591 int thumbnailY = (m_viewBuffer.height() - m_thumbnail.height()) / 2;
00592
00593 painter.drawPixmap(thumbnailX, thumbnailY, m_thumbnail);
00594
00595 painter.setPen(Qt::red);
00596 painter.drawRect(thumbnailX + m_visibleAreaInThumbnail.x() - 1,
00597 thumbnailY + m_visibleAreaInThumbnail.y() - 1,
00598 m_visibleAreaInThumbnail.width() + 2,
00599 m_visibleAreaInThumbnail.height() + 2);
00600 painter.setPen(Qt::red.light());
00601 painter.drawRect(thumbnailX + m_visibleAreaInThumbnail.x() - 2,
00602 thumbnailY + m_visibleAreaInThumbnail.y() - 2,
00603 m_visibleAreaInThumbnail.width() + 4,
00604 m_visibleAreaInThumbnail.height() + 4);
00605 }
00606 }
00607 }
00608
00609 void KoBirdEyePanel::paintViewEvent(QPaintEvent *e)
00610 {
00611 Q_ASSERT(!m_viewBuffer.isNull());
00612
00613 if (!m_viewBuffer.isNull()) {
00614 bitBlt(m_page->view, e->rect().x(), e->rect().y(), &m_viewBuffer,
00615 e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height());
00616 }
00617 }
00618
00619 #include "kobirdeyepanel.moc"