You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kview/kviewcanvas/kimagecanvas.cpp

954 lines
25 KiB

/* 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 <tqcolor.h>
#include <tqimage.h>
#include <tqapplication.h>
#include <tqwmatrix.h>
#include <tqtimer.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( TQWidget * parent, const char * name, const TQStringList & )
: TQScrollView( parent, name, WResizeNoErase | WStaticContents )
, m_client( 0 )
, m_oldClient( 0 )
, m_image( 0 )
, m_imageTransformed( 0 )
, m_pixmap( 0 )
, m_pTimer( new TQTimer( 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( TQFrame::NoFrame );
setResizePolicy( TQScrollView::Manual );
setMinimumSize( 0, 0 );
setBgColor( Defaults::bgColor );
connect( this, TQT_SIGNAL( imageChanged() ), this, TQT_SLOT( slotImageChanged() ) );
connect( m_pTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( hideCursor() ) );
KSettings::Dispatcher::self()->registerInstance(
KImageCanvasFactory::instance(), TQT_TQOBJECT(this),
TQT_SLOT( loadSettings() ) );
viewport()->setFocusProxy( this );
clear();
TQWidget::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 TQColor & color )
{
kdDebug( 4620 ) << k_funcinfo << endl;
viewport()->setPaletteBackgroundColor( color );
if( m_client )
m_client->setPaletteBackgroundColor( color );
}
const TQColor & 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();
}
TQSize KImageCanvas::imageSize() const
{
//kdDebug( 4620 ) << k_funcinfo << endl;
if( ! m_image )
return TQSize( 0, 0 );
return m_matrix.isIdentity() ? m_image->size() : m_matrix.mapRect( TQRect( TQPoint(), m_image->size() ) ).size();
}
TQSize KImageCanvas::currentSize() const
{
kdDebug( 4620 ) << k_funcinfo << endl;
if( ! m_image )
return TQSize( 0, 0 );
return m_currentsize;
}
const TQImage * KImageCanvas::image() const
{
if( m_imageTransformed )
return m_imageTransformed;
return m_image;
}
TQRect KImageCanvas::selection() const
{
kdDebug( 4620 ) << k_funcinfo << endl;
if( m_client )
return m_selection;
else
return TQRect();
}
void KImageCanvas::setCentered( bool centered )
{
kdDebug( 4620 ) << k_funcinfo << endl;
if( m_bCentered != centered )
{
m_bCentered = centered;
center();
}
}
void KImageCanvas::setImage( const TQImage & newimage )
{
bool emitHasImage = m_image ? false : true;
m_matrix.reset();
matrixChanged();
delete m_image;
m_image = new TQImage( 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 TQImage & newimage, const TQSize & size )
{
kdDebug( 4620 ) << k_funcinfo << size << endl;
bool emitHasImage = m_image ? false : true;
m_matrix.reset();
matrixChanged();
delete m_image;
m_image = new TQImage( 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 TQSize & size )
{
bool keepAspectRatio = m_keepaspectratio;
m_keepaspectratio = true;
resizeImage( size );
m_keepaspectratio = keepAspectRatio;
}
void KImageCanvas::setMaximumImageSize( const TQSize & 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 TQSize & 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 TQSize & newsize )
{
kdDebug( 4620 ) << k_funcinfo << endl;
if( m_image == 0 )
return;
TQSize 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;
}
TQString 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 TQString();
}
bool KImageCanvas::eventFilter( TQObject * obj, TQEvent * ev )
{
if( ( TQT_BASE_OBJECT(obj) == TQT_BASE_OBJECT(m_client) || TQT_BASE_OBJECT(obj) == TQT_BASE_OBJECT(m_oldClient) ) && ev->type() == TQEvent::MouseMove )
mouseMoveEvent( TQT_TQMOUSEEVENT( ev ) );
return TQScrollView::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 )
{
TQWMatrix 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 )
{
TQWMatrix 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 )
{
TQWMatrix 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( TQSize & newsize )
{
kdDebug( 4620 ) << k_funcinfo << endl;
if( m_keepaspectratio )
{
// check that the new size has the same aspect ratio the original image had
TQSize 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 TQSize & newsize )
{
kdDebug( 4620 ) << k_funcinfo << endl;
if( ! m_image )
return;
TQSize 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;
TQSize 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 )
TQTimer::singleShot( 0, this, TQT_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;
TQApplication::setOverrideCursor( WaitCursor );
if( m_bNewImage || ! m_client )
{
finishNewClient();
m_oldClient = m_client;
m_client = createNewClient();
}
m_client->setImage( pixmap() );
if( m_bSizeChanged || m_bNewImage )
{
TQSize sh = m_client->tqsizeHint();
if( ! sh.isValid() )
sh = TQSize( 0, 0 );
m_client->resize( sh );
resizeContents( sh.width(), sh.height() );
center();
}
TQRect 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 );
TQApplication::restoreOverrideCursor();
}
m_bNewImage = false;
m_bImageChanged = false;
m_bSizeChanged = false;
m_bMatrixChanged = false;
}
void KImageCanvas::mouseMoveEvent( TQMouseEvent * )
{
if( m_cursor.tqshape() == TQt::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( TQResizeEvent * ev )
{
kdDebug( 4620 ) << "KImageCanvas resized to " << ev->size() << endl;
TQScrollView::resizeEvent( ev );
center();
}
void KImageCanvas::contentsMousePressEvent( TQMouseEvent * ev )
{
if ( ev->button() == Qt::RightButton )
emit contextPress( ev->globalPos() );
TQScrollView::contentsMousePressEvent( ev );
}
void KImageCanvas::contentsWheelEvent( TQWheelEvent * 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
TQScrollView::contentsWheelEvent( ev );
}
void KImageCanvas::keyPressEvent( TQKeyEvent * 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( TQTimerEvent * ev )
{
if( ev->timerId() == m_iBlendTimerId )
{
TQRect 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 TQImage( 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
TQWMatrix 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( TQSize( cfgGroup.readNumEntry( "Minimum Width",
minimumImageSize().width() ), cfgGroup.readNumEntry(
"Minimum Height", minimumImageSize().height() ) ) );
setMaximumImageSize( TQSize( 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( TQString::number( i ), false ) )
m_vEffects.push_back( i );
}
// and now tell the canvas what blend effect to use
switchBlendEffect();
*/
}
void KImageCanvas::selected( const TQRect & 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 TQPoint & pos )
{
TQPoint 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( TQ_StrongFocus );
client->setFocus();
addChild( client, 0, 0 );
connect( client, TQT_SIGNAL( contextPress( const TQPoint& ) ), TQT_SIGNAL( contextPress( const TQPoint& ) ) );
connect( client, TQT_SIGNAL( cursorPos( const TQPoint & ) ), TQT_SLOT( mapCursorPos( const TQPoint & ) ) );
connect( client, TQT_SIGNAL( selected( const TQRect & ) ), TQT_SLOT( selected( const TQRect & ) ) );
connect( client, TQT_SIGNAL( wannaScroll( int, int ) ), TQT_SLOT( scrollBy( int, int ) ) );
return client;
}
#include "kimagecanvas.moc"
// vim:sw=4:ts=4