diff options
Diffstat (limited to 'kdeui/kpixmapregionselectorwidget.cpp')
-rw-r--r-- | kdeui/kpixmapregionselectorwidget.cpp | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/kdeui/kpixmapregionselectorwidget.cpp b/kdeui/kpixmapregionselectorwidget.cpp new file mode 100644 index 000000000..da2be5f92 --- /dev/null +++ b/kdeui/kpixmapregionselectorwidget.cpp @@ -0,0 +1,450 @@ +/* This file is part of the KDE libraries + Copyright (C) 2004 Antonio Larrosa <larrosa@kde.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/* NOTE: There are two copies of this .h and the .cpp file, with subtle differences. + * One copy is in kdelibs/kdeui, and the other copy is in kdepim/libkdepim + * This is because kdepim has to remain backwards compatible. Any changes + * to either file should be made to the other. + */ + +#include "kpixmapregionselectorwidget.h" +#include <qpainter.h> +#include <qcolor.h> +#include <qimage.h> +#include <qlayout.h> +#include <kimageeffect.h> +#include <kdebug.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kaction.h> +#include <stdlib.h> +#include <qcursor.h> +#include <qapplication.h> + +KPixmapRegionSelectorWidget::KPixmapRegionSelectorWidget( QWidget *parent, + const char *name) : QWidget( parent, name) +{ + QHBoxLayout * hboxLayout=new QHBoxLayout( this ); + + hboxLayout->addStretch(); + QVBoxLayout * vboxLayout=new QVBoxLayout( hboxLayout ); + + vboxLayout->addStretch(); + m_label = new QLabel(this, "pixmapHolder"); + m_label->setBackgroundMode( Qt::NoBackground ); + m_label->installEventFilter( this ); + + vboxLayout->addWidget(m_label); + vboxLayout->addStretch(); + + hboxLayout->addStretch(); + + m_forcedAspectRatio=0; + + m_zoomFactor=1.0; +} + +KPixmapRegionSelectorWidget::~KPixmapRegionSelectorWidget() +{ +} + +void KPixmapRegionSelectorWidget::setPixmap( const QPixmap &pixmap ) +{ + Q_ASSERT(!pixmap.isNull()); //This class isn't designed to deal with null pixmaps. + m_originalPixmap = pixmap; + m_unzoomedPixmap = pixmap; + m_label->setPixmap( pixmap ); + resetSelection(); +} + +void KPixmapRegionSelectorWidget::resetSelection() +{ + m_selectedRegion = m_originalPixmap.rect(); + updatePixmap(); +} + +QRect KPixmapRegionSelectorWidget::selectedRegion() const +{ + return m_selectedRegion; +} + +void KPixmapRegionSelectorWidget::setSelectedRegion(const QRect &rect) +{ + if (!rect.isValid()) resetSelection(); + else + { + m_selectedRegion=rect; + updatePixmap(); + + QRect r=unzoomedSelectedRegion(); + } +} + +void KPixmapRegionSelectorWidget::updatePixmap() +{ + Q_ASSERT(!m_originalPixmap.isNull()); if(m_originalPixmap.isNull()) { m_label->setPixmap(m_originalPixmap); return; } + if (m_selectedRegion.width()>m_originalPixmap.width()) m_selectedRegion.setWidth( m_originalPixmap.width() ); + if (m_selectedRegion.height()>m_originalPixmap.height()) m_selectedRegion.setHeight( m_originalPixmap.height() ); + + QPainter painter; + if (m_linedPixmap.isNull()) + { + m_linedPixmap = m_originalPixmap; + + painter.begin(&m_linedPixmap); + painter.setRasterOp( Qt::XorROP ); + painter.fillRect(0,0,m_linedPixmap.width(), m_linedPixmap.height(), + QBrush( QColor(255,255,255), Qt::BDiagPattern) ); + painter.end(); + + QImage image=m_linedPixmap.convertToImage(); + image=KImageEffect::fade(image, (float)0.4, QColor(0,0,0)); + m_linedPixmap.convertFromImage(image); + } + + QPixmap pixmap = m_linedPixmap; + + painter.begin(&pixmap); + painter.drawPixmap( m_selectedRegion.topLeft(), + m_originalPixmap, m_selectedRegion ); + + painter.setPen( QColor(255,255,255) ); + painter.setRasterOp( Qt::XorROP ); + + painter.drawRect( m_selectedRegion ); + + painter.end(); + + m_label->setPixmap(pixmap); +} + + +KPopupMenu *KPixmapRegionSelectorWidget::createPopupMenu() +{ + KPopupMenu *popup=new KPopupMenu(this, "PixmapRegionSelectorPopup"); + popup->insertTitle(i18n("Image Operations")); + + KAction *action = new KAction(i18n("&Rotate Clockwise"), "rotate_cw", + 0, this, SLOT(rotateClockwise()), + popup, "rotateclockwise"); + action->plug(popup); + + action = new KAction(i18n("Rotate &Counterclockwise"), "rotate_ccw", + 0, this, SLOT(rotateCounterclockwise()), + popup, "rotatecounterclockwise"); + action->plug(popup); + +/* + I wonder if it would be appropiate to have here an "Open with..." option to + edit the image (antlarr) +*/ + return popup; +} + +void KPixmapRegionSelectorWidget::rotate(KImageEffect::RotateDirection direction) +{ + int w=m_originalPixmap.width(); + int h=m_originalPixmap.height(); + QImage img=m_unzoomedPixmap.convertToImage(); + img= KImageEffect::rotate(img, direction); + m_unzoomedPixmap.convertFromImage(img); + + img=m_originalPixmap.convertToImage(); + img= KImageEffect::rotate(img, direction); + m_originalPixmap.convertFromImage(img); + + m_linedPixmap=QPixmap(); + + if (m_forcedAspectRatio>0 && m_forcedAspectRatio!=1) + resetSelection(); + else + { + switch (direction) + { + case ( KImageEffect::Rotate90 ): + { + int x=h-m_selectedRegion.y()-m_selectedRegion.height(); + int y=m_selectedRegion.x(); + m_selectedRegion.setRect(x, y, m_selectedRegion.height(), m_selectedRegion.width() ); + updatePixmap(); + } break; + case ( KImageEffect::Rotate270 ): + { + int x=m_selectedRegion.y(); + int y=w-m_selectedRegion.x()-m_selectedRegion.width(); + m_selectedRegion.setRect(x, y, m_selectedRegion.height(), m_selectedRegion.width() ); + updatePixmap(); + } break; + default: resetSelection(); + } + } +} + +void KPixmapRegionSelectorWidget::rotateClockwise() +{ + rotate(KImageEffect::Rotate90); +} + +void KPixmapRegionSelectorWidget::rotateCounterclockwise() +{ + rotate(KImageEffect::Rotate270); +} + +bool KPixmapRegionSelectorWidget::eventFilter(QObject *obj, QEvent *ev) +{ + if ( ev->type() == QEvent::MouseButtonPress ) + { + QMouseEvent *mev= (QMouseEvent *)(ev); + //kdDebug() << QString("click at %1,%2").arg( mev->x() ).arg( mev->y() ) << endl; + + if ( mev->button() == RightButton ) + { + KPopupMenu *popup = createPopupMenu( ); + popup->exec( mev->globalPos() ); + delete popup; + return TRUE; + }; + + QCursor cursor; + + if ( m_selectedRegion.contains( mev->pos() ) + && m_selectedRegion!=m_originalPixmap.rect() ) + { + m_state=Moving; + cursor.setShape( Qt::SizeAllCursor ); + } + else + { + m_state=Resizing; + cursor.setShape( Qt::CrossCursor ); + } + QApplication::setOverrideCursor(cursor); + + m_tempFirstClick=mev->pos(); + + + return TRUE; + } + + if ( ev->type() == QEvent::MouseMove ) + { + QMouseEvent *mev= (QMouseEvent *)(ev); + + //kdDebug() << QString("move to %1,%2").arg( mev->x() ).arg( mev->y() ) << endl; + + if ( m_state == Resizing ) + { + setSelectedRegion ( + calcSelectionRectangle( m_tempFirstClick, mev->pos() ) ); + } + else if (m_state == Moving ) + { + int mevx = mev->x(); + int mevy = mev->y(); + bool mouseOutside=false; + if ( mevx < 0 ) + { + m_selectedRegion.moveBy(-m_selectedRegion.x(),0); + mouseOutside=true; + } + else if ( mevx > m_originalPixmap.width() ) + { + m_selectedRegion.moveBy(m_originalPixmap.width()-m_selectedRegion.width()-m_selectedRegion.x(),0); + mouseOutside=true; + } + if ( mevy < 0 ) + { + m_selectedRegion.moveBy(0,-m_selectedRegion.y()); + mouseOutside=true; + } + else if ( mevy > m_originalPixmap.height() ) + { + m_selectedRegion.moveBy(0,m_originalPixmap.height()-m_selectedRegion.height()-m_selectedRegion.y()); + mouseOutside=true; + } + if (mouseOutside) { updatePixmap(); return TRUE; }; + + m_selectedRegion.moveBy( mev->x()-m_tempFirstClick.x(), + mev->y()-m_tempFirstClick.y() ); + + // Check that the region has not fallen outside the image + if (m_selectedRegion.x() < 0) + m_selectedRegion.moveBy(-m_selectedRegion.x(),0); + else if (m_selectedRegion.right() > m_originalPixmap.width()) + m_selectedRegion.moveBy(-(m_selectedRegion.right()-m_originalPixmap.width()),0); + + if (m_selectedRegion.y() < 0) + m_selectedRegion.moveBy(0,-m_selectedRegion.y()); + else if (m_selectedRegion.bottom() > m_originalPixmap.height()) + m_selectedRegion.moveBy(0,-(m_selectedRegion.bottom()-m_originalPixmap.height())); + + m_tempFirstClick=mev->pos(); + updatePixmap(); + } + return TRUE; + } + + if ( ev->type() == QEvent::MouseButtonRelease ) + { + QMouseEvent *mev= (QMouseEvent *)(ev); + + if ( m_state == Resizing && mev->pos() == m_tempFirstClick) + resetSelection(); + + m_state=None; + QApplication::restoreOverrideCursor(); + + return TRUE; + } + + QWidget::eventFilter(obj, ev); + return FALSE; +} + +QRect KPixmapRegionSelectorWidget::calcSelectionRectangle( const QPoint & startPoint, const QPoint & _endPoint ) +{ + QPoint endPoint = _endPoint; + if ( endPoint.x() < 0 ) endPoint.setX(0); + else if ( endPoint.x() > m_originalPixmap.width() ) endPoint.setX(m_originalPixmap.width()); + if ( endPoint.y() < 0 ) endPoint.setY(0); + else if ( endPoint.y() > m_originalPixmap.height() ) endPoint.setY(m_originalPixmap.height()); + int w=abs(startPoint.x()-endPoint.x()); + int h=abs(startPoint.y()-endPoint.y()); + + if (m_forcedAspectRatio>0) + { + double aspectRatio=w/double(h); + + if (aspectRatio>m_forcedAspectRatio) + h=(int)(w/m_forcedAspectRatio); + else + w=(int)(h*m_forcedAspectRatio); + } + + int x,y; + if ( startPoint.x() < endPoint.x() ) + x=startPoint.x(); + else + x=startPoint.x()-w; + if ( startPoint.y() < endPoint.y() ) + y=startPoint.y(); + else + y=startPoint.y()-h; + + if (x<0) + { + w+=x; + x=0; + h=(int)(w/m_forcedAspectRatio); + + if ( startPoint.y() > endPoint.y() ) + y=startPoint.y()-h; + } + else if (x+w>m_originalPixmap.width()) + { + w=m_originalPixmap.width()-x; + h=(int)(w/m_forcedAspectRatio); + + if ( startPoint.y() > endPoint.y() ) + y=startPoint.y()-h; + } + if (y<0) + { + h+=y; + y=0; + w=(int)(h*m_forcedAspectRatio); + + if ( startPoint.x() > endPoint.x() ) + x=startPoint.x()-w; + } + else if (y+h>m_originalPixmap.height()) + { + h=m_originalPixmap.height()-y; + w=(int)(h*m_forcedAspectRatio); + + if ( startPoint.x() > endPoint.x() ) + x=startPoint.x()-w; + } + + return QRect(x,y,w,h); +} + +QRect KPixmapRegionSelectorWidget::unzoomedSelectedRegion() const +{ + return QRect((int)(m_selectedRegion.x()/m_zoomFactor), + (int)(m_selectedRegion.y()/m_zoomFactor), + (int)(m_selectedRegion.width()/m_zoomFactor), + (int)(m_selectedRegion.height()/m_zoomFactor)); +} + +QImage KPixmapRegionSelectorWidget::selectedImage() const +{ + QImage origImage=m_unzoomedPixmap.convertToImage(); + return origImage.copy(unzoomedSelectedRegion()); +} + +void KPixmapRegionSelectorWidget::setSelectionAspectRatio(int width, int height) +{ + m_forcedAspectRatio=width/double(height); +} + +void KPixmapRegionSelectorWidget::setFreeSelectionAspectRatio() +{ + m_forcedAspectRatio=0; +} + +void KPixmapRegionSelectorWidget::setMaximumWidgetSize(int width, int height) +{ + m_maxWidth=width; + m_maxHeight=height; + + m_originalPixmap=m_unzoomedPixmap; + if (m_selectedRegion == m_originalPixmap.rect()) m_selectedRegion=QRect(); + +// kdDebug() << QString(" original Pixmap :") << m_originalPixmap.rect() << endl; +// kdDebug() << QString(" unzoomed Pixmap : %1 x %2 ").arg(m_unzoomedPixmap.width()).arg(m_unzoomedPixmap.height()) << endl; + + if ( !m_originalPixmap.isNull() && + ( m_originalPixmap.width() > m_maxWidth || + m_originalPixmap.height() > m_maxHeight ) ) + { + /* We have to resize the pixmap to get it complete on the screen */ + QImage image=m_originalPixmap.convertToImage(); + m_originalPixmap.convertFromImage( image.smoothScale( width, height, QImage::ScaleMin ) ); + double oldZoomFactor = m_zoomFactor; + m_zoomFactor=m_originalPixmap.width()/(double)m_unzoomedPixmap.width(); + + if (m_selectedRegion.isValid()) + { + m_selectedRegion= + QRect((int)(m_selectedRegion.x()*m_zoomFactor/oldZoomFactor), + (int)(m_selectedRegion.y()*m_zoomFactor/oldZoomFactor), + (int)(m_selectedRegion.width()*m_zoomFactor/oldZoomFactor), + (int)(m_selectedRegion.height()*m_zoomFactor/oldZoomFactor) ); + } + } + + if (!m_selectedRegion.isValid()) m_selectedRegion = m_originalPixmap.rect(); + + m_linedPixmap=QPixmap(); + updatePixmap(); + resize(m_label->width(), m_label->height()); +} + +#include "kpixmapregionselectorwidget.moc" |