diff options
Diffstat (limited to 'krita/ui/kobirdeyepanel.cpp')
-rw-r--r-- | krita/ui/kobirdeyepanel.cpp | 619 |
1 files changed, 619 insertions, 0 deletions
diff --git a/krita/ui/kobirdeyepanel.cpp b/krita/ui/kobirdeyepanel.cpp new file mode 100644 index 00000000..fda95945 --- /dev/null +++ b/krita/ui/kobirdeyepanel.cpp @@ -0,0 +1,619 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org> + * + * 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 <qpixmap.h> +#include <qimage.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qframe.h> +#include <qlabel.h> +#include <qtoolbutton.h> +#include <qslider.h> +#include <qcursor.h> + +#include <kdebug.h> +#include <kglobalsettings.h> +#include <kaction.h> +#include <ktoolbar.h> +#include <knuminput.h> +#include <klocale.h> + +#include <KoDocument.h> + +#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, + QWidget * parent, + const char * name, + WFlags f) + : QWidget(parent, name, f) + , m_zoomListener(zoomListener) + , m_thumbnailProvider(thumbnailProvider) + , m_canvas(canvas) + , m_dragging(false) +{ + QHBoxLayout * l = new QHBoxLayout(this); + m_page = new WdgBirdEye(this); + m_page->zoom->setRange((int) (QMAX(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(Qt::NoBackground); + + m_zoomIn = new KAction( i18n("Zoom In"), "birdeye_zoom_plus", 0, this, SLOT(zoomPlus()), this, "zoomIn" ); + m_zoomOut = new KAction( i18n("Zoom Out"), "birdeye_zoom_minus", 0, this, SLOT(zoomMinus()), this, "zoomOut" ); + + l->addWidget(m_page); + + connect(m_page->zoom, SIGNAL(valueChanged(int)), SLOT(zoomValueChanged(int))); + connect(m_page->bn100, SIGNAL(clicked()), SLOT(zoom100())); + connect(m_page->slZoom, SIGNAL(valueChanged(int)), 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(Q_INT32 xpos, Q_INT32 ypos) +{ + m_page->txtX->setText(QString("%L1").arg(xpos, 5)); + m_page->txtY->setText(QString("%L1").arg(ypos, 5)); +} + +void KoBirdEyePanel::setThumbnailProvider(KoThumbnailAdapter * thumbnailProvider) +{ + delete m_thumbnailProvider; + m_thumbnailProvider = thumbnailProvider; +} + +void KoBirdEyePanel::slotViewTransformationChanged() +{ + updateVisibleArea(); + renderView(); + m_page->view->update(); + setZoom(qRound(m_canvas->zoomFactor() * 100)); +} + +void KoBirdEyePanel::slotUpdate(const QRect & r) +{ + QRect updateRect = r; + + if (m_thumbnailProvider->pixelSize() != m_documentSize) { + m_documentSize = m_thumbnailProvider->pixelSize(); + fitThumbnailToView(); + updateRect = QRect(0, 0, m_documentSize.width(), m_documentSize.height()); + } + + updateRect &= QRect(0, 0, m_documentSize.width(), m_documentSize.height()); + + if (!updateRect.isEmpty() && !m_documentSize.isEmpty()) { + + QRect thumbnailRect = documentToThumbnail(KoRect::fromQRect(updateRect)); + + if (!thumbnailRect.isEmpty()) { + + QImage thumbnailImage = m_thumbnailProvider->image(thumbnailRect, m_thumbnail.size()); + + if (!thumbnailImage.isNull()) { + + Q_ASSERT(thumbnailImage.size() == thumbnailRect.size()); + + QPainter painter(&m_thumbnail); + + painter.fillRect(thumbnailRect, colorGroup().mid()); + painter.drawImage(thumbnailRect.x(), thumbnailRect.y(), thumbnailImage); + } + } + } + + renderView(); + m_page->view->update(); +} + +QRect KoBirdEyePanel::documentToThumbnail(const KoRect& docRect) +{ + if (docRect.isEmpty() || m_documentSize.isEmpty() || m_thumbnail.isNull()) { + return QRect(); + } + + Q_INT32 thumbnailLeft = static_cast<Q_INT32>((docRect.left() * m_thumbnail.width()) / m_documentSize.width()); + Q_INT32 thumbnailRight = static_cast<Q_INT32>(((docRect.right() + 1) * m_thumbnail.width()) / m_documentSize.width()); + Q_INT32 thumbnailTop = static_cast<Q_INT32>((docRect.top() * m_thumbnail.height()) / m_documentSize.height()); + Q_INT32 thumbnailBottom = static_cast<Q_INT32>(((docRect.bottom() + 1) * m_thumbnail.height()) / m_documentSize.height()); + + QRect thumbnailRect(thumbnailLeft, thumbnailTop, thumbnailRight - thumbnailLeft + 1, thumbnailBottom - thumbnailTop + 1); + thumbnailRect &= m_thumbnail.rect(); + + return thumbnailRect; +} + +KoRect KoBirdEyePanel::thumbnailToDocument(const QRect& thumbnailRect) +{ + if (thumbnailRect.isEmpty() || m_documentSize.isEmpty() || m_thumbnail.isNull()) { + return KoRect(); + } + + double docLeft = (static_cast<double>(thumbnailRect.left()) * m_documentSize.width()) / m_thumbnail.width(); + double docRight = (static_cast<double>(thumbnailRect.right() + 1) * m_documentSize.width()) / m_thumbnail.width(); + double docTop = (static_cast<double>(thumbnailRect.top()) * m_documentSize.height()) / m_thumbnail.height(); + double docBottom = (static_cast<double>(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; +} + +QPoint KoBirdEyePanel::viewToThumbnail(const QPoint& viewPoint) +{ + int thumbnailX = (m_viewBuffer.width() - m_thumbnail.width()) / 2; + int thumbnailY = (m_viewBuffer.height() - m_thumbnail.height()) / 2; + + return QPoint(viewPoint.x() - thumbnailX, viewPoint.y() - thumbnailY); +} + + +void KoBirdEyePanel::zoomMinus() +{ +} + +void KoBirdEyePanel::zoomPlus() +{ +} + +void KoBirdEyePanel::updateVisibleArea() +{ + m_visibleAreaInThumbnail = documentToThumbnail(m_canvas->visibleArea()); +} + + +bool KoBirdEyePanel::eventFilter(QObject* o, QEvent* ev) +{ + if (o == m_page->view && ev->type() == QEvent::Resize) { + resizeViewEvent(static_cast<QResizeEvent *>(ev)->size()); + } + + if (o == m_page->view && ev->type() == QEvent::Paint) { + paintViewEvent(static_cast<QPaintEvent *>(ev)); + } + + if (o == m_page->view && ev->type() == QEvent::MouseMove) { + + QMouseEvent* me = (QMouseEvent*)ev; + QPoint thumbnailPos = viewToThumbnail(me->pos()); + + if (m_dragging) { + handleMouseMoveAction(thumbnailPos); + } else { + handleMouseMove(thumbnailPos); + } + + return true; + } + + if (o == m_page->view && ev->type() == QEvent::MouseButtonPress) { + + QMouseEvent* me = (QMouseEvent*)ev; + QPoint thumbnailPos = viewToThumbnail(me->pos()); + + if (me->button() == LeftButton) { + handleMousePress(thumbnailPos); + } + + return true; + } + + if (o == m_page->view && ev->type() == QEvent::MouseButtonRelease) { + + QMouseEvent* me = (QMouseEvent*)ev; + + if (me->button() == LeftButton) { + m_dragging = false; + } + + return true; + } + + return m_page->eventFilter(o, ev); +} + +KoBirdEyePanel::enumDragHandle KoBirdEyePanel::dragHandleAt(QPoint p) +{ + QRect left = QRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.top()-1, 3, m_visibleAreaInThumbnail.height()+2); + QRect right = QRect(m_visibleAreaInThumbnail.right()-1, m_visibleAreaInThumbnail.top()-1, 3, m_visibleAreaInThumbnail.height()+2); + QRect top = QRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.top()-1, m_visibleAreaInThumbnail.width()+2, 3); + QRect bottom = QRect(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(QPoint p) +{ + QCursor cursor; + + switch (dragHandleAt(p)) { + case DragHandleLeft: + case DragHandleRight: + cursor = Qt::sizeHorCursor; + break; + case DragHandleTop: + case DragHandleBottom: + cursor = Qt::sizeVerCursor; + break; + case DragHandleCentre: + cursor = Qt::sizeAllCursor; + break; + default: + case DragHandleNone: + if (m_thumbnail.rect().contains(p)) { + cursor = Qt::PointingHandCursor; + } else { + cursor = Qt::arrowCursor; + } + break; + } + + m_page->view->setCursor(cursor); +} + +void KoBirdEyePanel::handleMouseMoveAction(QPoint p) +{ + if (m_dragging) { + + Q_INT32 dx = p.x() - m_lastDragPos.x(); + Q_INT32 dy = p.y() - m_lastDragPos.y(); + + m_lastDragPos = p; + + QRect 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(QPoint p) +{ + if (!m_dragging) { + + enumDragHandle dragHandle = dragHandleAt(p); + + if (dragHandle == DragHandleNone) { + if (m_thumbnail.rect().contains(p)) { + + // Snap visible area centre to p and begin a centre drag. + + QRect thumbnailRect = m_visibleAreaInThumbnail; + thumbnailRect.moveCenter(p); + makeThumbnailRectVisible(thumbnailRect); + + m_dragHandle = DragHandleCentre; + m_page->view->setCursor(Qt::sizeAllCursor); + m_dragging = true; + } + } else { + m_dragHandle = dragHandle; + m_dragging = true; + } + m_lastDragPos = p; + } +} + +void KoBirdEyePanel::makeThumbnailRectVisible(const QRect& r) +{ + if (r.isEmpty()) { + return; + } + + QRect 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<double>(m_visibleAreaInThumbnail.width()) / thumbnailRect.width(); + } else { + + Q_ASSERT(thumbnailRect.width() == m_visibleAreaInThumbnail.width()); + + zoomFactor *= static_cast<double>(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(QSize size) +{ + m_viewBuffer.resize(size); + fitThumbnailToView(); + slotUpdate(QRect(0, 0, m_documentSize.width(), m_documentSize.height())); +} + +void KoBirdEyePanel::fitThumbnailToView() +{ + QRect docRect = QRect(0, 0, m_thumbnailProvider->pixelSize().width(), m_thumbnailProvider->pixelSize().height()); + Q_INT32 thumbnailWidth; + Q_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 = Q_INT32(ceil(docRect.height() * xScale)); + } else { + thumbnailWidth = Q_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(); + + QPainter painter(&m_viewBuffer); + + painter.fillRect(0, 0, m_viewBuffer.width(), m_viewBuffer.height(), colorGroup().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(Qt::red); + painter.drawRect(thumbnailX + m_visibleAreaInThumbnail.x() - 1, + thumbnailY + m_visibleAreaInThumbnail.y() - 1, + m_visibleAreaInThumbnail.width() + 2, + m_visibleAreaInThumbnail.height() + 2); + painter.setPen(Qt::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(QPaintEvent *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" |