summaryrefslogtreecommitdiffstats
path: root/kview/kviewcanvas/kimagecanvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kview/kviewcanvas/kimagecanvas.cpp')
-rw-r--r--kview/kviewcanvas/kimagecanvas.cpp953
1 files changed, 953 insertions, 0 deletions
diff --git a/kview/kviewcanvas/kimagecanvas.cpp b/kview/kviewcanvas/kimagecanvas.cpp
new file mode 100644
index 00000000..6c54850f
--- /dev/null
+++ b/kview/kviewcanvas/kimagecanvas.cpp
@@ -0,0 +1,953 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 "kimagecanvas.h"
+#include "kimageholder.h"
+#include "version.h"
+#include "config/defaults.h"
+
+#include <qcolor.h>
+#include <qimage.h>
+#include <qapplication.h>
+#include <qwmatrix.h>
+#include <qtimer.h>
+
+#include <kpixmap.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <ksettings/dispatcher.h>
+#include <kconfig.h>
+
+#define KIMAGECANVAS_WIPESIZE 5
+
+const int MOUSECURSORHIDETIME = 3000;
+
+//extern bool qt_use_xrender;
+
+typedef KGenericFactory<KImageCanvas> KImageCanvasFactory;
+K_EXPORT_COMPONENT_FACTORY( libkviewcanvas,
+ KImageCanvasFactory( "kviewcanvas" ) )
+
+KImageCanvas::KImageCanvas( QWidget * parent, const char * name, const QStringList & )
+ : QScrollView( parent, name, WResizeNoErase | WStaticContents )
+ , m_client( 0 )
+ , m_oldClient( 0 )
+ , m_image( 0 )
+ , m_imageTransformed( 0 )
+ , m_pixmap( 0 )
+ , m_pTimer( new QTimer( this, "KImageCanvas/Timer" ) )
+ , m_maxsize( Defaults::maxSize )
+ , m_minsize( Defaults::minSize )
+ , m_currentsize( 0, 0 )
+ , m_zoom( 1.0 )
+ , m_fastscale( ! Defaults::smoothScaling )
+ , m_keepaspectratio( Defaults::keepAspectRatio )
+ , m_bImageChanged( false )
+ , m_bSizeChanged( false )
+ , m_bNeedNewPixmap( false )
+ , m_bCentered( Defaults::centerImage )
+ , m_bImageUpdateScheduled( false )
+ , m_bNewImage( false )
+ , m_iBlendTimerId( 0 )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ setFrameStyle( QFrame::NoFrame );
+ setResizePolicy( QScrollView::Manual );
+ setMinimumSize( 0, 0 );
+ setBgColor( Defaults::bgColor );
+
+ connect( this, SIGNAL( imageChanged() ), this, SLOT( slotImageChanged() ) );
+ connect( m_pTimer, SIGNAL( timeout() ), this, SLOT( hideCursor() ) );
+
+ KSettings::Dispatcher::self()->registerInstance(
+ KImageCanvasFactory::instance(), this,
+ SLOT( loadSettings() ) );
+
+ viewport()->setFocusProxy( this );
+ clear();
+
+ QWidget::setMouseTracking( true );
+ viewport()->setMouseTracking( true );
+ m_cursor.setShape( Qt::CrossCursor );
+ viewport()->setCursor( m_cursor );
+ m_pTimer->start( MOUSECURSORHIDETIME, true );
+
+ loadSettings();
+}
+
+KImageCanvas::~KImageCanvas()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ delete m_image; m_image = 0;
+ delete m_pixmap; m_pixmap = 0;
+}
+
+void KImageCanvas::setBgColor( const QColor & color )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ viewport()->setPaletteBackgroundColor( color );
+ if( m_client )
+ m_client->setPaletteBackgroundColor( color );
+}
+
+const QColor & KImageCanvas::bgColor() const
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ return viewport()->paletteBackgroundColor();
+}
+
+int KImageCanvas::imageDepth() const
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_image )
+ return 0;
+
+ return m_image->depth();
+}
+
+QSize KImageCanvas::imageSize() const
+{
+ //kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_image )
+ return QSize( 0, 0 );
+
+ return m_matrix.isIdentity() ? m_image->size() : m_matrix.mapRect( QRect( QPoint(), m_image->size() ) ).size();
+}
+
+QSize KImageCanvas::currentSize() const
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_image )
+ return QSize( 0, 0 );
+
+ return m_currentsize;
+}
+
+const QImage * KImageCanvas::image() const
+{
+ if( m_imageTransformed )
+ return m_imageTransformed;
+ return m_image;
+}
+
+QRect KImageCanvas::selection() const
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_client )
+ return m_selection;
+ else
+ return QRect();
+}
+
+void KImageCanvas::setCentered( bool centered )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_bCentered != centered )
+ {
+ m_bCentered = centered;
+ center();
+ }
+}
+
+void KImageCanvas::setImage( const QImage & newimage )
+{
+ bool emitHasImage = m_image ? false : true;
+ m_matrix.reset();
+ matrixChanged();
+ delete m_image;
+ m_image = new QImage( newimage );
+ m_bNewImage = true;
+ // don't emit the signal here - call the slot directly
+ slotImageChanged();
+
+ sizeFromZoom( m_zoom );
+ updateImage();
+ if( emitHasImage && m_image )
+ emit hasImage( true );
+}
+
+void KImageCanvas::setImage( const QImage & newimage, const QSize & size )
+{
+ kdDebug( 4620 ) << k_funcinfo << size << endl;
+ bool emitHasImage = m_image ? false : true;
+ m_matrix.reset();
+ matrixChanged();
+ delete m_image;
+ m_image = new QImage( newimage );
+ m_bNewImage = true;
+ // don't emit the signal here - call the slot directly
+ slotImageChanged();
+
+ resizeImage( size );
+ updateImage();
+ if( emitHasImage && m_image )
+ emit hasImage( true );
+}
+
+void KImageCanvas::setZoom( double zoom )
+{
+ kdDebug( 4620 ) << k_funcinfo << zoom << endl;
+ if( m_image == 0 )
+ return;
+
+ if( zoom > 0.0 && m_zoom != zoom )
+ {
+ m_zoom = zoom;
+ sizeFromZoom( m_zoom );
+ emit zoomChanged( m_zoom );
+ updateImage();
+ }
+}
+
+void KImageCanvas::boundImageTo( const QSize & size )
+{
+ bool keepAspectRatio = m_keepaspectratio;
+ m_keepaspectratio = true;
+ resizeImage( size );
+ m_keepaspectratio = keepAspectRatio;
+}
+
+void KImageCanvas::setMaximumImageSize( const QSize & maxsize )
+{
+ kdDebug( 4620 ) << k_funcinfo << maxsize << endl;
+ if( ( ! m_minsize.isEmpty() ) &&
+ ( maxsize.width() < m_minsize.width() || maxsize.height() < m_minsize.height() ) )
+ {
+ kdWarning( 4620 ) << "the new maximum image size is smaller than the minimum size" << endl;
+ return;
+ }
+
+ m_maxsize = maxsize;
+
+ resizeImage( m_currentsize );
+}
+
+void KImageCanvas::setMinimumImageSize( const QSize & minsize )
+{
+ kdDebug( 4620 ) << k_funcinfo << minsize << endl;
+ if( ( ! m_maxsize.isEmpty() ) &&
+ ( minsize.width() > m_maxsize.width() || minsize.height() > m_maxsize.height() ) )
+ {
+ kdWarning( 4620 ) << "the new minimum image size is greater than the maximum size" << endl;
+ return;
+ }
+
+ m_minsize = minsize;
+
+ resizeImage( m_currentsize );
+}
+
+void KImageCanvas::resizeImage( const QSize & newsize )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_image == 0 )
+ return;
+
+ QSize size = newsize;
+
+ // check that it fits into min and max sizes
+ checkBounds( size );
+
+ // calculate the new zoom factor
+ zoomFromSize( size );
+
+ if( size != m_currentsize )
+ {
+ m_currentsize = size;
+ sizeChanged();
+
+ updateImage();
+ }
+}
+
+void KImageCanvas::hideScrollbars( bool hidden )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( hidden )
+ {
+ setVScrollBarMode( AlwaysOff );
+ setHScrollBarMode( AlwaysOff );
+ }
+ else
+ {
+ setVScrollBarMode( Auto );
+ setHScrollBarMode( Auto );
+ }
+}
+
+void KImageCanvas::setKeepAspectRatio( bool aspect )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_keepaspectratio = aspect;
+}
+
+unsigned int KImageCanvas::numOfBlendEffects() const
+{
+ return Defaults::numOfBlendEffects;
+}
+
+QString KImageCanvas::blendEffectDescription( unsigned int idx ) const
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ switch( idx )
+ {
+ case NoBlending:
+ kdWarning( 4620 ) << k_funcinfo << " shouldn't be called with an index of 0 - That's always not really defined\n";
+ return i18n( Defaults::blendEffectDescription[ 0 ] );
+ case AlphaBlend:
+ return i18n( Defaults::blendEffectDescription[ 5 ] );
+ case WipeFromLeft:
+ return i18n( Defaults::blendEffectDescription[ 1 ] );
+ case WipeFromRight:
+ return i18n( Defaults::blendEffectDescription[ 2 ] );
+ case WipeFromTop:
+ return i18n( Defaults::blendEffectDescription[ 3 ] );
+ case WipeFromBottom:
+ return i18n( Defaults::blendEffectDescription[ 4 ] );
+ }
+ kdError( 4620 ) << "Effect description for effect with index " << idx << " doesn't exist\n";
+ return QString::null;
+}
+
+bool KImageCanvas::eventFilter( QObject * obj, QEvent * ev )
+{
+ if( ( obj == m_client || obj == m_oldClient ) && ev->type() == QEvent::MouseMove )
+ mouseMoveEvent( static_cast<QMouseEvent*>( ev ) );
+ return QScrollView::eventFilter( obj, ev );
+}
+
+void KImageCanvas::setFastScale( bool fastscale )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_fastscale = fastscale;
+ if( m_fastscale )
+ {
+ // wo do scaling with a matrix now, so the m_imageTransformed isn't needed anymore
+ delete m_imageTransformed;
+ m_imageTransformed = 0;
+ }
+ else
+ {
+ matrixChanged(); // set the flag to dirty so that a new m_imageTransformed will be created
+ // else we very relyably get a crash
+ }
+ updateImage();
+}
+
+void KImageCanvas::clear()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ bool emitHasImage = m_image ? true : false;
+ delete m_image;
+ m_image = 0;
+ m_currentsize -= m_currentsize; //zero size
+ if( m_client )
+ m_client->clear();
+ if( emitHasImage && ! m_image )
+ emit hasImage( false );
+}
+
+void KImageCanvas::flipHorizontal( bool change )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_image == 0 )
+ return;
+
+ if( change )
+ {
+ QWMatrix matrix( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F );
+ *m_image = m_image->xForm( matrix );
+ emit imageChanged();
+ }
+ else
+ {
+ m_matrix.scale( 1.0, -1.0 );
+ matrixChanged();
+ }
+ // size didn't change
+ updateImage();
+}
+
+void KImageCanvas::flipVertical( bool change )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_image == 0 )
+ return;
+
+ if( change )
+ {
+ QWMatrix matrix( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
+ *m_image = m_image->xForm( matrix );
+ emit imageChanged();
+ }
+ else
+ {
+ m_matrix.scale( -1.0, 1.0 );
+ matrixChanged();
+ }
+ // size didn't change
+ updateImage();
+}
+
+void KImageCanvas::rotate( double a, bool change )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_image == 0 )
+ return;
+
+ if( change )
+ {
+ QWMatrix matrix;
+ matrix.rotate( a );
+ *m_image = m_image->xForm( matrix );
+ emit imageChanged();
+ }
+ else
+ {
+ m_matrix.rotate( a );
+ matrixChanged();
+ }
+ //adjust m_currentsize
+ sizeFromZoom( m_zoom );
+ updateImage();
+}
+
+void KImageCanvas::checkBounds( QSize & newsize )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_keepaspectratio )
+ {
+ // check that the new size has the same aspect ratio the original image had
+ QSize origsize = imageSize();
+ double x1 = double( origsize.height() ) / double( newsize.height() );
+ double x2 = double( origsize.width() ) / double( newsize.width() );
+ if( ( newsize * x1 != origsize ) || ( newsize * x2 != origsize ) )
+ {
+ // not OK
+ kdDebug( 4620 ) << "checkBounds: the aspect ratio wasn't kept changing from " << newsize << endl;
+ // the user want's that the aspect ratio doesn't change. The
+ // question is: make it larger or smaller?
+ // we make it smaller (we depend on that in boundImageTo)
+ newsize = origsize / KMAX( x1, x2 );
+ kdDebug( 4620 ) << "checkBounds: to " << newsize << endl;
+ }
+ }
+ if( ( ! m_maxsize.isEmpty() ) &&
+ ( newsize.width() > m_maxsize.width() || newsize.height() > m_maxsize.height() ) )
+ {
+ kdDebug( 4620 ) << "checkBounds: the new size is bigger than the max size" << endl;
+ if( m_keepaspectratio )
+ {
+ double x1 = double( m_maxsize.height() ) / double( newsize.height() );
+ double x2 = double( m_maxsize.width() ) / double( newsize.width() );
+ double x = KMIN( x1, x2 );//( x1 > x2 ) ? x2 : x1;
+ newsize *= x;
+ }
+ else
+ newsize = newsize.boundedTo( m_maxsize );
+ }
+ if( ( ! m_minsize.isEmpty() ) &&
+ ( newsize.width() < m_minsize.width() || newsize.height() < m_minsize.height() ) )
+ {
+ kdDebug( 4620 ) << "checkBounds: the new size is smaller than the min size" << endl;
+ if( m_keepaspectratio )
+ {
+ double x1 = double( m_minsize.height() ) / double( newsize.height() );
+ double x2 = double( m_minsize.width() ) / double( newsize.width() );
+ double x = KMAX( x1, x2 );//( x1 > x2 ) ? x1 : x2;
+ newsize *= x;
+ }
+ else
+ newsize = newsize.expandedTo( m_minsize );
+ }
+ // if it still won't fit we have a problem: we can't keep the aspect ratio or we have
+ // to violate the min/max settings
+ if( ( ! m_maxsize.isEmpty() ) &&
+ ( newsize.width() > m_maxsize.width() || newsize.height() > m_maxsize.height() ) )
+ {
+ kdDebug( 4620 ) << "checkBounds: Sorry, I can't keep the aspect ratio." << endl;
+ newsize = newsize.boundedTo( m_maxsize );
+ }
+}
+
+void KImageCanvas::zoomFromSize( const QSize & newsize )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_image )
+ return;
+
+ QSize originalsize = imageSize();
+ double widthzoom = double( newsize.width() ) / double( originalsize.width() );
+ double heightzoom = double( newsize.height() ) / double( originalsize.height() );
+ double zoom = ( widthzoom + heightzoom ) / 2;
+ if( zoom != m_zoom )
+ {
+ m_zoom = zoom;
+ emit zoomChanged( m_zoom );
+ }
+}
+
+void KImageCanvas::sizeFromZoom( double zoom )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_image )
+ return;
+
+ QSize newsize = zoom * imageSize();
+ kdDebug( 4620 ) << "change size from " << imageSize() << " to " << newsize << endl;
+ resizeImage( newsize );
+}
+
+void KImageCanvas::updateImage()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_bImageUpdateScheduled )
+ QTimer::singleShot( 0, this, SLOT( slotUpdateImage() ) );
+ m_bImageUpdateScheduled = true;
+}
+
+void KImageCanvas::slotUpdateImage()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_bImageUpdateScheduled = false;
+ if( m_image == 0 )
+ return;
+
+ //only update if something was changed
+ if( m_bImageChanged || m_bSizeChanged || m_bMatrixChanged )
+ {
+ kdDebug( 4620 ) << "actually updating the image now" << endl;
+ QApplication::setOverrideCursor( WaitCursor );
+ if( m_bNewImage || ! m_client )
+ {
+ finishNewClient();
+ m_oldClient = m_client;
+ m_client = createNewClient();
+ }
+ m_client->setImage( pixmap() );
+
+ if( m_bSizeChanged || m_bNewImage )
+ {
+ QSize sh = m_client->sizeHint();
+ if( ! sh.isValid() )
+ sh = QSize( 0, 0 );
+ m_client->resize( sh );
+ resizeContents( sh.width(), sh.height() );
+ center();
+ }
+ QRect drawRect = m_client->drawRect();
+ switch( m_iBlendEffect )
+ {
+ case NoBlending:
+ break;
+ case AlphaBlend:
+ break;
+ case WipeFromLeft:
+ drawRect.setRight( KIMAGECANVAS_WIPESIZE + contentsX() );
+ m_client->setDrawRect( drawRect );
+ break;
+ case WipeFromRight:
+ drawRect.rLeft() += KMIN( drawRect.width() - KIMAGECANVAS_WIPESIZE, contentsX() + visibleWidth() );
+ m_client->setDrawRect( drawRect );
+ break;
+ case WipeFromTop:
+ drawRect.setBottom( KIMAGECANVAS_WIPESIZE + contentsY() );
+ m_client->setDrawRect( drawRect );
+ break;
+ case WipeFromBottom:
+ drawRect.setTop( KMIN( drawRect.height() - KIMAGECANVAS_WIPESIZE, contentsY() + visibleHeight() ) );
+ m_client->setDrawRect( drawRect );
+ break;
+ }
+ m_client->update();
+ m_iBlendTimerId = startTimer( 5 );
+ QApplication::restoreOverrideCursor();
+ }
+
+ m_bNewImage = false;
+ m_bImageChanged = false;
+ m_bSizeChanged = false;
+ m_bMatrixChanged = false;
+}
+
+void KImageCanvas::mouseMoveEvent( QMouseEvent * )
+{
+ if( m_cursor.shape() == Qt::BlankCursor )
+ {
+ m_cursor.setShape( Qt::CrossCursor );
+ viewport()->setCursor( m_cursor );
+ if( m_client )
+ m_client->setCursor( m_cursor );
+ }
+ m_pTimer->start( MOUSECURSORHIDETIME, true );
+}
+
+
+void KImageCanvas::resizeEvent( QResizeEvent * ev )
+{
+ kdDebug( 4620 ) << "KImageCanvas resized to " << ev->size() << endl;
+ QScrollView::resizeEvent( ev );
+ center();
+}
+
+void KImageCanvas::contentsMousePressEvent( QMouseEvent * ev )
+{
+ if ( ev->button() == RightButton )
+ emit contextPress( ev->globalPos() );
+ QScrollView::contentsMousePressEvent( ev );
+}
+
+void KImageCanvas::contentsWheelEvent( QWheelEvent * ev )
+{
+ //kdDebug( 4620 ) << k_funcinfo << endl;
+ // Ctrl+Wheelmouse changes the zoom.
+ // Wheelmouse scrolls around
+ if ( ev->state() & ControlButton )
+ {
+ int delta = ev->delta() / 120;
+ double zoom = m_zoom;
+ // make zoom a value of 1/16, 1/15, 1/14, .. , 1/2, 1, 2, 3, .. , 15, 16
+ bool done = false;
+ for( int i = 15; i > 0; --i )
+ {
+ if( zoom <= ( 1.0 / i ) )
+ {
+ if( zoom < ( 1.0 / ( i + 0.5 ) ) )
+ zoom = ( 1.0 / ( i + 1 ) );
+ else
+ zoom = ( 1.0 / i );
+ done = true;
+ // zoom = 1/16, 1/15, .. , 1/2, 1
+ double x = 1.0 / zoom - delta;
+ if( x == 0 )
+ zoom = 2.0;
+ else
+ zoom = 1.0 / x;
+ break;
+ }
+ }
+ if( ! done )
+ for( int i = 2; i < 17; ++i )
+ {
+ if( zoom < (double)i )
+ {
+ if( zoom < ( i - 0.5 ) )
+ zoom = i - 1.0;
+ else
+ zoom = (double)i;
+ done = true;
+ // zoom = 1, 2, .., 15, 16
+ zoom = zoom + delta;
+ if( zoom < 0.9 )
+ zoom = 0.5;
+ break;
+ }
+ }
+ if( ! done )
+ {
+ zoom = 16.0;
+ zoom = zoom + delta;
+ if( zoom > 16.0 )
+ zoom = 16.0;
+ }
+ kdDebug( 4620 ) << "Mousewheel: oldzoom = " << m_zoom << " newzoom = " << zoom << endl;
+ ev->accept();
+ bool oldscale = fastScale();
+ setFastScale( true );
+ setZoom( zoom );
+ setFastScale( oldscale );
+ }
+ else
+ QScrollView::contentsWheelEvent( ev );
+}
+
+void KImageCanvas::keyPressEvent( QKeyEvent * ev )
+{
+ //kdDebug( 4620 ) << k_funcinfo << endl;
+ switch( ev->key() )
+ {
+ case Key_Down:
+ ev->accept();
+ verticalScrollBar()->addLine();
+ break;
+ case Key_Up:
+ ev->accept();
+ verticalScrollBar()->subtractLine();
+ break;
+ case Key_Left:
+ ev->accept();
+ horizontalScrollBar()->subtractLine();
+ break;
+ case Key_Right:
+ ev->accept();
+ horizontalScrollBar()->addLine();
+ break;
+ case Key_PageUp:
+ ev->accept();
+ verticalScrollBar()->subtractPage();
+ break;
+ case Key_PageDown:
+ ev->accept();
+ verticalScrollBar()->addPage();
+ break;
+ default:
+ ev->ignore();
+ break;
+ }
+}
+
+void KImageCanvas::timerEvent( QTimerEvent * ev )
+{
+ if( ev->timerId() == m_iBlendTimerId )
+ {
+ QRect drawRect = m_client->drawRect();
+ switch( m_iBlendEffect )
+ {
+ case NoBlending:
+ finishNewClient();
+ break;
+ case AlphaBlend:
+ finishNewClient();
+ //if( qt_use_xrender )
+ //{
+ //}
+ //else
+ //{
+ //kdWarning( 4620 ) << "no XRender" << endl;
+ //finishNewClient();
+ //}
+ break;
+ case WipeFromLeft:
+ drawRect.rRight() += KIMAGECANVAS_WIPESIZE;
+ m_client->setDrawRect( drawRect );
+ m_client->update( drawRect.right() - KIMAGECANVAS_WIPESIZE, 0, KIMAGECANVAS_WIPESIZE, m_client->height() );
+ if( drawRect.right() >= contentsX() + visibleWidth() )
+ finishNewClient();
+ break;
+ case WipeFromRight:
+ drawRect.rLeft() -= KIMAGECANVAS_WIPESIZE;
+ m_client->setDrawRect( drawRect );
+ m_client->update( drawRect.left(), 0, KIMAGECANVAS_WIPESIZE, m_client->height() );
+ if( drawRect.left() <= contentsX() )
+ finishNewClient();
+ break;
+ case WipeFromTop:
+ drawRect.rBottom() += KIMAGECANVAS_WIPESIZE;
+ m_client->setDrawRect( drawRect );
+ m_client->update( 0, drawRect.bottom() - KIMAGECANVAS_WIPESIZE, m_client->width(), KIMAGECANVAS_WIPESIZE );
+ if( drawRect.bottom() >= contentsY() + visibleHeight() )
+ finishNewClient();
+ break;
+ case WipeFromBottom:
+ drawRect.rTop() -= KIMAGECANVAS_WIPESIZE;
+ m_client->setDrawRect( drawRect );
+ m_client->update( 0, drawRect.top(), m_client->width(), KIMAGECANVAS_WIPESIZE );
+ if( drawRect.top() <= contentsY() )
+ finishNewClient();
+ break;
+ default:
+ kdFatal( 4620 ) << "unknown Blend Effect" << endl;
+ break;
+ }
+ }
+ else
+ killTimer( ev->timerId() );
+}
+
+void KImageCanvas::hideCursor()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_cursor.setShape( Qt::BlankCursor );
+ viewport()->setCursor( m_cursor );
+ if( m_client )
+ m_client->setCursor( m_cursor );
+}
+
+const KPixmap KImageCanvas::pixmap()
+{
+ kdDebug( 4620 ) << k_funcinfo << ( m_bNeedNewPixmap ? "convert from Image" : "use old copy" ) << endl;
+ // create a new Pixmap in m_pixmap if needed
+ if( m_bNeedNewPixmap )
+ {
+ // only do it again if requested
+ m_bNeedNewPixmap = false;
+ // ok, the old one may go now
+ delete m_pixmap;
+
+ // if smoothscaling is wanted and the transformation matrix or the image
+ // itself changed...
+ if( ! m_fastscale && ( m_bMatrixChanged || m_bImageChanged ) )
+ {
+ delete m_imageTransformed;
+ // we create a new image transformed by the matrix
+ m_imageTransformed = new QImage( m_matrix.isIdentity() ? *m_image : m_image->xForm( m_matrix ) );
+ kdDebug( 4620 ) << "Size of m_image: " << m_image->size() << endl;
+ kdDebug( 4620 ) << "Size of m_imageTransformed: " << m_imageTransformed->size() << endl;
+ }
+ // smoothScale or fast scaling via m_matrix
+ m_pixmap = new KPixmap();
+ m_pixmap->convertFromImage( m_fastscale ? *m_image : m_imageTransformed->smoothScale( m_currentsize ), KPixmap::ColorOnly );
+ }
+ if( m_fastscale )
+ {
+ // fast scaling is needed so we need to scale now
+ QWMatrix matrix( m_matrix );
+ matrix.scale( m_zoom, m_zoom );
+ if( ! matrix.isIdentity() )
+ return m_pixmap->xForm( matrix );
+ }
+ return *m_pixmap;
+}
+
+void KImageCanvas::slotImageChanged()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_bImageChanged = true;
+ m_bNeedNewPixmap = true;
+}
+
+void KImageCanvas::loadSettings()
+{
+ KConfigGroup cfgGroup( KImageCanvasFactory::instance()->config(),
+ "Settings" );
+ setFastScale( ! cfgGroup.readBoolEntry( "Smooth Scaling", ! fastScale() ) );
+ setKeepAspectRatio( cfgGroup.readBoolEntry( "Keep Aspect Ratio",
+ keepAspectRatio() ) );
+ setCentered( cfgGroup.readBoolEntry( "Center Image", centered() ) );
+
+ setBgColor( cfgGroup.readColorEntry( "Background Color", &bgColor() ) );
+
+ setMinimumImageSize( QSize( cfgGroup.readNumEntry( "Minimum Width",
+ minimumImageSize().width() ), cfgGroup.readNumEntry(
+ "Minimum Height", minimumImageSize().height() ) ) );
+ setMaximumImageSize( QSize( cfgGroup.readNumEntry( "Maximum Width",
+ maximumImageSize().width() ), cfgGroup.readNumEntry(
+ "Maximum Height", maximumImageSize().height() ) ) );
+
+ KConfigGroup blendConfig( KImageCanvasFactory::instance()->config(),
+ "Blend Effects" );
+ /* TODO
+ m_vEffects.clear();
+ for( unsigned int i = 1; i <= numOfBlendEffects(); ++i )
+ {
+ if( blendConfig.readBoolEntry( QString::number( i ), false ) )
+ m_vEffects.push_back( i );
+ }
+ // and now tell the canvas what blend effect to use
+ switchBlendEffect();
+ */
+}
+
+void KImageCanvas::selected( const QRect & rect )
+{
+ //kdDebug( 4620 ) << k_funcinfo << rect << endl;
+ m_selection = rect;
+ if( ! m_selection.isNull() )
+ {
+ m_selection.setTop( int( ( m_selection.top() + 0.5 ) / m_zoom ) );
+ m_selection.setLeft( int( ( m_selection.left() + 0.5 ) / m_zoom ) );
+ m_selection.setRight( int( ( m_selection.right() + 0.5 ) / m_zoom ) );
+ m_selection.setBottom( int( ( m_selection.bottom() + 0.5 ) / m_zoom ) );
+ }
+ //kdDebug( 4620 ) << "m_selection = " << m_selection << endl;
+ emit selectionChanged( m_selection );
+}
+
+void KImageCanvas::mapCursorPos( const QPoint & pos )
+{
+ QPoint mapped( static_cast<int>( ( pos.x() + 0.5 ) / m_zoom ), static_cast<int>( ( pos.y() + 0.5 ) / m_zoom ) );
+ //kdDebug( 4620 ) << k_funcinfo << pos << " -> " << mapped << endl;
+ emit cursorPos( mapped );
+}
+
+void KImageCanvas::sizeChanged()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_bSizeChanged = true;
+ if( ! m_fastscale )
+ m_bNeedNewPixmap = true;
+ emit imageSizeChanged( m_currentsize );
+}
+
+void KImageCanvas::matrixChanged()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_bMatrixChanged = true;
+ m_bNeedNewPixmap = true;
+}
+
+void KImageCanvas::center()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_bCentered && m_client )
+ {
+ int x = 0;
+ int y = 0;
+
+ int scrollbarwidth = ( height() >= m_currentsize.height() ) ? 0 : verticalScrollBar()->width();
+ int scrollbarheight = ( width() - scrollbarwidth >= m_currentsize.width() ) ? 0 : horizontalScrollBar()->height();
+ scrollbarwidth = ( height() - scrollbarheight >= m_currentsize.height() ) ? 0 : verticalScrollBar()->width();
+
+ int availheight = height() - scrollbarheight;
+ int availwidth = width() - scrollbarwidth;
+
+ if( availwidth > m_currentsize.width() )
+ x = ( availwidth - m_currentsize.width() ) / 2;
+ if( availheight > m_currentsize.height() )
+ y = ( availheight - m_currentsize.height() ) / 2;
+
+ kdDebug( 4620 ) << "center with left top at " << x << ", " << y << endl;
+ moveChild( m_client, x, y );
+ }
+}
+
+void KImageCanvas::finishNewClient()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ killTimer( m_iBlendTimerId );
+ if( m_client )
+ m_client->setDrawRect( m_client->rect() );
+ delete m_oldClient;
+ m_oldClient = 0;
+ emit showingImageDone();
+}
+
+KImageHolder * KImageCanvas::createNewClient()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ KImageHolder * client = new KImageHolder( viewport() );
+ client->setMinimumSize( 0, 0 );
+ client->setMouseTracking( true );
+ client->installEventFilter( this );
+ setFocusProxy( client );
+ client->setFocusPolicy( QWidget::StrongFocus );
+ client->setFocus();
+
+ addChild( client, 0, 0 );
+
+ connect( client, SIGNAL( contextPress( const QPoint& ) ), SIGNAL( contextPress( const QPoint& ) ) );
+ connect( client, SIGNAL( cursorPos( const QPoint & ) ), SLOT( mapCursorPos( const QPoint & ) ) );
+ connect( client, SIGNAL( selected( const QRect & ) ), SLOT( selected( const QRect & ) ) );
+ connect( client, SIGNAL( wannaScroll( int, int ) ), SLOT( scrollBy( int, int ) ) );
+
+ return client;
+}
+
+#include "kimagecanvas.moc"
+
+// vim:sw=4:ts=4