/* * This file is part of the KDE project * * Copyright (c) 2005 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wdgbirdeye.h" #include "kobirdeyepanel.h" #include "kis_int_spinbox.h" KoCanvasAdapter::KoCanvasAdapter() {} KoCanvasAdapter::~KoCanvasAdapter() {} KoZoomAdapter::KoZoomAdapter() {} KoZoomAdapter::~KoZoomAdapter() {} KoThumbnailAdapter::KoThumbnailAdapter() {} KoThumbnailAdapter::~KoThumbnailAdapter() {} KoBirdEyePanel::KoBirdEyePanel( KoZoomAdapter * zoomListener, KoThumbnailAdapter * thumbnailProvider, KoCanvasAdapter * canvas, TQWidget * parent, const char * name, WFlags f) : TQWidget(parent, name, f) , m_zoomListener(zoomListener) , m_thumbnailProvider(thumbnailProvider) , m_canvas(canvas) , m_dragging(false) { TQHBoxLayout * l = new TQHBoxLayout(this); m_page = new WdgBirdEye(this); m_page->zoom->setRange((int) (TQMAX(1, 100 * zoomListener->getMinZoom())), (int) (100 * zoomListener->getMaxZoom())); m_page->zoom->setValue(100); m_page->zoom->setSuffix("%"); m_page->toolbar->setIconSize(16); m_page->view->installEventFilter(this); m_page->view->setBackgroundMode(TQt::NoBackground); m_zoomIn = new KAction( i18n("Zoom In"), "birdeye_zoom_plus", 0, TQT_TQOBJECT(this), TQT_SLOT(zoomPlus()), TQT_TQOBJECT(this), "zoomIn" ); m_zoomOut = new KAction( i18n("Zoom Out"), "birdeye_zoom_minus", 0, TQT_TQOBJECT(this), TQT_SLOT(zoomMinus()), TQT_TQOBJECT(this), "zoomOut" ); l->addWidget(m_page); connect(m_page->zoom, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(zoomValueChanged(int))); connect(m_page->bn100, TQT_SIGNAL(clicked()), TQT_SLOT(zoom100())); connect(m_page->slZoom, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(sliderChanged( int ))); } KoBirdEyePanel::~KoBirdEyePanel() { delete m_canvas; delete m_thumbnailProvider; delete m_zoomListener; } void KoBirdEyePanel::setZoom(int zoom) { m_page->zoom->blockSignals(true); m_page->slZoom->blockSignals(true); m_page->zoom->setValue(zoom); if (zoom < 10) { m_page->slZoom->setValue(0); } else if (zoom > 10 && zoom < 100) { m_page->slZoom->setValue(zoom / 10); } else if (zoom >= 100 && zoom < 150) { m_page->slZoom->setValue(10); } else if (zoom >= 150 && zoom < 250) { m_page->slZoom->setValue(11); } else if (zoom >= 250 && zoom < 350) { m_page->slZoom->setValue(12); } else if (zoom >= 350 && zoom < 450) { m_page->slZoom->setValue(13); } else if (zoom >= 450 && zoom < 550) { m_page->slZoom->setValue(14); } else if (zoom >= 550 && zoom < 650) { m_page->slZoom->setValue(15); } else if (zoom >= 650 && zoom < 875) { m_page->slZoom->setValue(16); } else if (zoom >= 875 && zoom < 1150) { m_page->slZoom->setValue(17); } else if (zoom >= 1150 && zoom < 1450) { m_page->slZoom->setValue(18); } else if (zoom >= 1450) { m_page->slZoom->setValue(19); } m_page->zoom->blockSignals(false); m_page->slZoom->blockSignals(false); } void KoBirdEyePanel::zoomValueChanged(int zoom) { KoPoint center; center = m_canvas->visibleArea().center(); m_zoomListener->zoomTo(center.x(), center.y(), zoom / 100.0); setZoom(zoom); } void KoBirdEyePanel::zoom100() { zoomValueChanged( 100 ); } void KoBirdEyePanel::sliderChanged( int v ) { if (v < 10) { zoomValueChanged((v + 1) * 10); } else { switch(v) { case 10: zoomValueChanged(100); break; case 11: zoomValueChanged(200); break; case 12: zoomValueChanged(300); case 13: zoomValueChanged(400); break; case 14: zoomValueChanged(500); break; case 15: zoomValueChanged(600); break; case 16: zoomValueChanged(750); break; case 17: zoomValueChanged(1000); break; case 18: zoomValueChanged(1300); break; case 19: zoomValueChanged(1600); break; } } } void KoBirdEyePanel::cursorPosChanged(TQ_INT32 xpos, TQ_INT32 ypos) { m_page->txtX->setText(TQString("%L1").tqarg(xpos, 5)); m_page->txtY->setText(TQString("%L1").tqarg(ypos, 5)); } void KoBirdEyePanel::setThumbnailProvider(KoThumbnailAdapter * thumbnailProvider) { delete m_thumbnailProvider; m_thumbnailProvider = thumbnailProvider; } void KoBirdEyePanel::slotViewTransformationChanged() { updateVisibleArea(); renderView(); m_page->view->update(); setZoom(tqRound(m_canvas->zoomFactor() * 100)); } void KoBirdEyePanel::slotUpdate(const TQRect & r) { TQRect updateRect = r; if (m_thumbnailProvider->pixelSize() != m_documentSize) { m_documentSize = m_thumbnailProvider->pixelSize(); fitThumbnailToView(); updateRect = TQRect(0, 0, m_documentSize.width(), m_documentSize.height()); } updateRect &= TQRect(0, 0, m_documentSize.width(), m_documentSize.height()); if (!updateRect.isEmpty() && !m_documentSize.isEmpty()) { TQRect thumbnailRect = documentToThumbnail(KoRect::fromTQRect(updateRect)); if (!thumbnailRect.isEmpty()) { TQImage thumbnailImage = m_thumbnailProvider->image(thumbnailRect, m_thumbnail.size()); if (!thumbnailImage.isNull()) { Q_ASSERT(thumbnailImage.size() == thumbnailRect.size()); TQPainter painter(&m_thumbnail); painter.fillRect(thumbnailRect, tqcolorGroup().mid()); painter.drawImage(thumbnailRect.x(), thumbnailRect.y(), thumbnailImage); } } } renderView(); m_page->view->update(); } TQRect KoBirdEyePanel::documentToThumbnail(const KoRect& docRect) { if (docRect.isEmpty() || m_documentSize.isEmpty() || m_thumbnail.isNull()) { return TQRect(); } TQ_INT32 thumbnailLeft = static_cast((docRect.left() * m_thumbnail.width()) / m_documentSize.width()); TQ_INT32 thumbnailRight = static_cast(((docRect.right() + 1) * m_thumbnail.width()) / m_documentSize.width()); TQ_INT32 thumbnailTop = static_cast((docRect.top() * m_thumbnail.height()) / m_documentSize.height()); TQ_INT32 thumbnailBottom = static_cast(((docRect.bottom() + 1) * m_thumbnail.height()) / m_documentSize.height()); TQRect thumbnailRect(thumbnailLeft, thumbnailTop, thumbnailRight - thumbnailLeft + 1, thumbnailBottom - thumbnailTop + 1); thumbnailRect &= m_thumbnail.rect(); return thumbnailRect; } KoRect KoBirdEyePanel::thumbnailToDocument(const TQRect& thumbnailRect) { if (thumbnailRect.isEmpty() || m_documentSize.isEmpty() || m_thumbnail.isNull()) { return KoRect(); } double docLeft = (static_cast(thumbnailRect.left()) * m_documentSize.width()) / m_thumbnail.width(); double docRight = (static_cast(thumbnailRect.right() + 1) * m_documentSize.width()) / m_thumbnail.width(); double docTop = (static_cast(thumbnailRect.top()) * m_documentSize.height()) / m_thumbnail.height(); double docBottom = (static_cast(thumbnailRect.bottom() + 1) * m_documentSize.height()) / m_thumbnail.height(); KoRect docRect(docLeft, docTop, docRight - docLeft + 1, docBottom - docTop + 1); docRect &= KoRect(0, 0, m_documentSize.width(), m_documentSize.height()); return docRect; } TQPoint KoBirdEyePanel::viewToThumbnail(const TQPoint& viewPoint) { int thumbnailX = (m_viewBuffer.width() - m_thumbnail.width()) / 2; int thumbnailY = (m_viewBuffer.height() - m_thumbnail.height()) / 2; return TQPoint(viewPoint.x() - thumbnailX, viewPoint.y() - thumbnailY); } void KoBirdEyePanel::zoomMinus() { } void KoBirdEyePanel::zoomPlus() { } void KoBirdEyePanel::updateVisibleArea() { m_visibleAreaInThumbnail = documentToThumbnail(m_canvas->visibleArea()); } bool KoBirdEyePanel::eventFilter(TQObject* o, TQEvent* ev) { if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_page->view) && ev->type() == TQEvent::Resize) { resizeViewEvent(TQT_TQRESIZEEVENT(ev)->size()); } if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_page->view) && ev->type() == TQEvent::Paint) { paintViewEvent(TQT_TQPAINTEVENT(ev)); } if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_page->view) && ev->type() == TQEvent::MouseMove) { TQMouseEvent* me = (TQMouseEvent*)ev; TQPoint thumbnailPos = viewToThumbnail(me->pos()); if (m_dragging) { handleMouseMoveAction(thumbnailPos); } else { handleMouseMove(thumbnailPos); } return true; } if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_page->view) && ev->type() == TQEvent::MouseButtonPress) { TQMouseEvent* me = (TQMouseEvent*)ev; TQPoint thumbnailPos = viewToThumbnail(me->pos()); if (me->button() == Qt::LeftButton) { handleMousePress(thumbnailPos); } return true; } if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_page->view) && ev->type() == TQEvent::MouseButtonRelease) { TQMouseEvent* me = (TQMouseEvent*)ev; if (me->button() == Qt::LeftButton) { m_dragging = false; } return true; } return m_page->eventFilter(o, ev); } KoBirdEyePanel::enumDragHandle KoBirdEyePanel::dragHandleAt(TQPoint p) { TQRect left = TQRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.top()-1, 3, m_visibleAreaInThumbnail.height()+2); TQRect right = TQRect(m_visibleAreaInThumbnail.right()-1, m_visibleAreaInThumbnail.top()-1, 3, m_visibleAreaInThumbnail.height()+2); TQRect top = TQRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.top()-1, m_visibleAreaInThumbnail.width()+2, 3); TQRect bottom = TQRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.bottom()-1, m_visibleAreaInThumbnail.width()+2, 3); if (left.contains(p)) { return DragHandleLeft; } if (right.contains(p)) { return DragHandleRight; } if (top.contains(p)) { return DragHandleTop; } if (bottom.contains(p)) { return DragHandleBottom; } if (m_visibleAreaInThumbnail.contains(p)) { return DragHandleCentre; } return DragHandleNone; } void KoBirdEyePanel::handleMouseMove(TQPoint p) { TQCursor cursor; switch (dragHandleAt(p)) { case DragHandleLeft: case DragHandleRight: cursor = TQt::sizeHorCursor; break; case DragHandleTop: case DragHandleBottom: cursor = TQt::sizeVerCursor; break; case DragHandleCentre: cursor = TQt::sizeAllCursor; break; default: case DragHandleNone: if (TQT_TQRECT_OBJECT(m_thumbnail.rect()).contains(p)) { cursor = TQt::PointingHandCursor; } else { cursor = TQt::arrowCursor; } break; } m_page->view->setCursor(cursor); } void KoBirdEyePanel::handleMouseMoveAction(TQPoint p) { if (m_dragging) { TQ_INT32 dx = p.x() - m_lastDragPos.x(); TQ_INT32 dy = p.y() - m_lastDragPos.y(); m_lastDragPos = p; TQRect thumbnailRect = m_visibleAreaInThumbnail; switch (m_dragHandle) { case DragHandleLeft: { thumbnailRect.setLeft(thumbnailRect.left()+dx); break; } case DragHandleRight: { thumbnailRect.setRight(thumbnailRect.right()+dx); break; } case DragHandleTop: { thumbnailRect.setTop(thumbnailRect.top()+dy); break; } case DragHandleBottom: { thumbnailRect.setBottom(thumbnailRect.bottom()+dy); break; } case DragHandleCentre: { thumbnailRect.moveBy(dx, dy); break; } default: case DragHandleNone: break; } makeThumbnailRectVisible(thumbnailRect); } } void KoBirdEyePanel::handleMousePress(TQPoint p) { if (!m_dragging) { enumDragHandle dragHandle = dragHandleAt(p); if (dragHandle == DragHandleNone) { if (TQT_TQRECT_OBJECT(m_thumbnail.rect()).contains(p)) { // Snap visible area centre to p and begin a centre drag. TQRect thumbnailRect = m_visibleAreaInThumbnail; thumbnailRect.moveCenter(p); makeThumbnailRectVisible(thumbnailRect); m_dragHandle = DragHandleCentre; m_page->view->setCursor(TQt::sizeAllCursor); m_dragging = true; } } else { m_dragHandle = dragHandle; m_dragging = true; } m_lastDragPos = p; } } void KoBirdEyePanel::makeThumbnailRectVisible(const TQRect& r) { if (r.isEmpty()) { return; } TQRect thumbnailRect = r; if (thumbnailRect.left() < m_thumbnail.rect().left()) { thumbnailRect.moveLeft(m_thumbnail.rect().left()); } if (thumbnailRect.right() > m_thumbnail.rect().right()) { thumbnailRect.moveRight(m_thumbnail.rect().right()); } if (thumbnailRect.top() < m_thumbnail.rect().top()) { thumbnailRect.moveTop(m_thumbnail.rect().top()); } if (thumbnailRect.bottom() > m_thumbnail.rect().bottom()) { thumbnailRect.moveBottom(m_thumbnail.rect().bottom()); } if (thumbnailRect.width() > m_thumbnail.rect().width()) { thumbnailRect.setLeft(m_thumbnail.rect().left()); thumbnailRect.setRight(m_thumbnail.rect().right()); } if (thumbnailRect.height() > m_thumbnail.rect().height()) { thumbnailRect.setTop(m_thumbnail.rect().top()); thumbnailRect.setBottom(m_thumbnail.rect().bottom()); } double zoomFactor = m_canvas->zoomFactor(); if (thumbnailRect.size() == m_visibleAreaInThumbnail.size()) { // No change to zoom } else if (thumbnailRect.width() != m_visibleAreaInThumbnail.width()) { Q_ASSERT(thumbnailRect.height() == m_visibleAreaInThumbnail.height()); zoomFactor *= static_cast(m_visibleAreaInThumbnail.width()) / thumbnailRect.width(); } else { Q_ASSERT(thumbnailRect.width() == m_visibleAreaInThumbnail.width()); zoomFactor *= static_cast(m_visibleAreaInThumbnail.height()) / thumbnailRect.height(); } if (zoomFactor < m_zoomListener->getMinZoom()) { zoomFactor = m_zoomListener->getMinZoom(); } else if (zoomFactor > m_zoomListener->getMaxZoom()) { zoomFactor = m_zoomListener->getMaxZoom(); } KoRect docRect = thumbnailToDocument(thumbnailRect); m_zoomListener->zoomTo(docRect.center().x(), docRect.center().y(), zoomFactor); } void KoBirdEyePanel::resizeViewEvent(TQSize size) { m_viewBuffer.resize(size); fitThumbnailToView(); slotUpdate(TQRect(0, 0, m_documentSize.width(), m_documentSize.height())); } void KoBirdEyePanel::fitThumbnailToView() { TQRect docRect = TQRect(0, 0, m_thumbnailProvider->pixelSize().width(), m_thumbnailProvider->pixelSize().height()); TQ_INT32 thumbnailWidth; TQ_INT32 thumbnailHeight; if (docRect.isEmpty()) { thumbnailWidth = 0; thumbnailHeight = 0; } else { const int thumbnailBorderPixels = 4; double xScale = double(m_page->view->contentsRect().width() - thumbnailBorderPixels) / docRect.width(); double yScale = double(m_page->view->contentsRect().height() - thumbnailBorderPixels) / docRect.height(); if (xScale < yScale) { thumbnailWidth = m_page->view->contentsRect().width() - thumbnailBorderPixels; thumbnailHeight = TQ_INT32(ceil(docRect.height() * xScale)); } else { thumbnailWidth = TQ_INT32(ceil(docRect.width() * yScale)); thumbnailHeight = m_page->view->contentsRect().height() - thumbnailBorderPixels; } } m_thumbnail.resize(thumbnailWidth, thumbnailHeight); updateVisibleArea(); } void KoBirdEyePanel::renderView() { Q_ASSERT(!m_viewBuffer.isNull()); if (!m_viewBuffer.isNull()) { updateVisibleArea(); TQPainter painter(&m_viewBuffer); painter.fillRect(0, 0, m_viewBuffer.width(), m_viewBuffer.height(), tqcolorGroup().mid()); if (!m_thumbnail.isNull()) { int thumbnailX = (m_viewBuffer.width() - m_thumbnail.width()) / 2; int thumbnailY = (m_viewBuffer.height() - m_thumbnail.height()) / 2; painter.drawPixmap(thumbnailX, thumbnailY, m_thumbnail); painter.setPen(TQt::red); painter.drawRect(thumbnailX + m_visibleAreaInThumbnail.x() - 1, thumbnailY + m_visibleAreaInThumbnail.y() - 1, m_visibleAreaInThumbnail.width() + 2, m_visibleAreaInThumbnail.height() + 2); painter.setPen(TQt::red.light()); painter.drawRect(thumbnailX + m_visibleAreaInThumbnail.x() - 2, thumbnailY + m_visibleAreaInThumbnail.y() - 2, m_visibleAreaInThumbnail.width() + 4, m_visibleAreaInThumbnail.height() + 4); } } } void KoBirdEyePanel::paintViewEvent(TQPaintEvent *e) { Q_ASSERT(!m_viewBuffer.isNull()); if (!m_viewBuffer.isNull()) { bitBlt(m_page->view, e->rect().x(), e->rect().y(), &m_viewBuffer, e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height()); } } #include "kobirdeyepanel.moc"