/* This file is part of the KDE project Copyright (C) 2001, 2002, 2003 The Karbon Developers 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. */ #include #include #include #include "karbon_view.h" #include "karbon_part.h" #include "karbon_drag.h" #include "vcanvas.h" #include "vdocument.h" #include "vpainter.h" #include "vqpainter.h" #include "vpainterfactory.h" #include "vselection.h" #include "vtoolcontroller.h" #include "vtool.h" #include #include #include int VCanvas::pageOffsetX() const { double zoomedWidth = m_part->document().width() * m_view->zoom(); if( contentsWidth() < visibleWidth() ) return int( 0.5 * ( visibleWidth() - zoomedWidth ) ); else return int( 0.5 * ( contentsWidth() - zoomedWidth ) ); } int VCanvas::pageOffsetY() const { double zoomedHeight = m_part->document().height() * m_view->zoom(); if( contentsHeight() < visibleHeight() ) return int( 0.5 * ( visibleHeight() - zoomedHeight ) ); else return int( 0.5 * ( contentsHeight() - zoomedHeight ) ); } KoPoint VCanvas::snapToGrid( const KoPoint &point ) { if( !m_part->document().grid().isSnap ) return point; KoPoint p = point; KoSize dist = m_part->document().grid().snap; KoSize dxy = m_part->document().grid().freq; int dx = tqRound( p.x() / dxy.width() ); int dy = tqRound( p.y() / dxy.height() ); float distx = TQMIN( TQABS( p.x() - dxy.width() * dx ), TQABS( p.x() - dxy.width() * ( dx + 1 ) ) ); float disty = TQMIN( TQABS( p.y() - dxy.height() * dy ), TQABS( p.y() - dxy.height() * ( dy + 1 ) ) ); if( distx < dist.width() ) { if( TQABS(p.x() - dxy.width() * dx ) < TQABS( p.x() - dxy.width() * ( dx + 1 ) ) ) p.rx() = dxy.width() * dx; else p.rx() = dxy.width() * ( dx + 1 ); } if( disty < dist.height() ) { if( TQABS( p.y() - dxy.height() * dy ) < TQABS( p.y() - dxy.height() * ( dy + 1 ) ) ) p.ry() = dxy.height() * dy; else p.ry() = dxy.height() * ( dy + 1 ); } return p; } VCanvas::VCanvas( TQWidget *parent, KarbonView* view, KarbonPart* part ) : TQScrollView( parent, "canvas", WStaticContents/*WNorthWestGravity*/ | WResizeNoErase | WRepaintNoErase ), m_part( part ), m_view( view ) { connect(this, TQT_SIGNAL( contentsMoving( int, int ) ), this, TQT_SLOT( slotContentsMoving( int, int ) ) ); viewport()->setFocusPolicy( TQ_StrongFocus ); viewport()->setMouseTracking( true ); setMouseTracking( true ); viewport()->setBackgroundColor( TQt::white ); viewport()->setBackgroundMode( TQWidget::NoBackground ); viewport()->installEventFilter( this ); resizeContents( 800, 600 ); m_pixmap = new TQPixmap( 800, 600 ); setFocus(); setAcceptDrops( true ); } VCanvas::~VCanvas() { delete m_pixmap; m_view = 0L; m_part = 0L; } void VCanvas::setPos( const KoPoint& p ) { KoPoint p2 = toViewport( p ); TQCursor::setPos( mapToGlobal( TQPoint( int(p2.x()), int(p2.y()) ) ) ); } bool VCanvas::eventFilter( TQObject* object, TQEvent* event ) { TQScrollView::eventFilter( object, event ); if( event->type() == TQEvent::AccelOverride || event->type() == TQEvent::Accel ) return TQScrollView::eventFilter( object, event ); if( event->type() == TQEvent::KeyPress || event->type() == TQEvent::KeyRelease ) return m_view->keyEvent( event ); TQMouseEvent* mouseEvent = dynamic_cast( event ); if( mouseEvent && m_view ) { KoPoint canvasCoordinate = toContents( KoPoint( mouseEvent->pos() ) ); return m_view->mouseEvent( mouseEvent, canvasCoordinate ); } return false; } // This causes a repaint normally, so just overwriting it omits the repainting void VCanvas::focusInEvent( TQFocusEvent * ) { } KoPoint VCanvas::toViewport( const KoPoint &p ) const { KoPoint p2 = p; p2.setX( ( p.x() * m_view->zoom() ) - contentsX() + pageOffsetX() ); if( contentsHeight() > height() ) p2.setY( ( contentsHeight() - ( p.y() * m_view->zoom() + contentsY() + pageOffsetY() ) ) ); else p2.setY( ( height() - p.y() * m_view->zoom() + pageOffsetY() ) ); return p2; } KoPoint VCanvas::toContents( const KoPoint &p ) const { KoPoint p2 = p; p2.setX( ( p.x() + contentsX() - pageOffsetX() ) / m_view->zoom() ); if( contentsHeight() > height() ) p2.setY( ( contentsHeight() - ( p.y() + contentsY() + pageOffsetY()) ) / m_view->zoom() ); else p2.setY( ( height() - p.y() - pageOffsetY() ) / m_view->zoom() ); return p2; } KoRect VCanvas::boundingBox() const { KoPoint p1( 0, 0 ); KoPoint p2( width(), height() ); if( !m_view->documentDeleted() ) { p1 = toContents( p1 ); p2 = toContents( p2 ); } return KoRect( p1, p2 ).normalize(); } void VCanvas::setYMirroring( VPainter *p ) { TQWMatrix mat; mat.scale( 1, -1 ); mat.translate( pageOffsetX(), pageOffsetY() ); if( contentsHeight() > visibleHeight() ) mat.translate( -contentsX(), contentsY() - contentsHeight() ); else mat.translate( 0, -visibleHeight() ); p->setWorldMatrix( mat ); } void VCanvas::viewportPaintEvent( TQPaintEvent *e ) { TQRect eventRect = e->rect(); KoRect rect = KoRect::fromTQRect( eventRect ); setYMirroring( m_view->painterFactory()->editpainter() ); viewport()->setUpdatesEnabled( false ); VPainter *p = m_view->painterFactory()->painter(); // TODO : only update ROIs p->begin(); p->clear( rect, TQColor( 195, 194, 193 ) ); p->setZoomFactor( m_view->zoom() ); setYMirroring( p ); // TRICK : slightly adjust the matrix so libart AA looks better TQWMatrix mat = p->worldMatrix(); p->setWorldMatrix( mat.translate( -.5, -.5 ) ); // set up clippath p->newPath(); p->moveTo( rect.topLeft() ); p->lineTo( rect.topRight() ); p->lineTo( rect.bottomRight() ); p->lineTo( rect.bottomLeft() ); p->lineTo( rect.topLeft() ); p->setClipPath(); m_part->document().drawPage( p, m_part->pageLayout(), m_view->showPageMargins() ); KoRect bbox = boundingBox(); m_part->document().draw( p, &bbox ); p->resetClipPath(); p->end(); // draw handle: VTQPainter qpainter( p->device() ); setYMirroring( &qpainter ); qpainter.setZoomFactor( m_view->zoom() ); m_part->document().selection()->draw( &qpainter, m_view->zoom() ); if( m_view->toolController()->currentTool() ) m_view->toolController()->currentTool()->draw( &qpainter ); bitBlt( viewport(), eventRect.topLeft(), p->device(), eventRect ); viewport()->setUpdatesEnabled( true ); } void VCanvas::setViewport( double centerX, double centerY ) { setContentsPos( int( centerX * contentsWidth() - 0.5 * visibleWidth() ), int( centerY * contentsHeight() - 0.5 * visibleHeight() ) ); } void VCanvas::setViewportRect( const KoRect &r ) { viewport()->setUpdatesEnabled( false ); double zoomX = m_view->zoom() * ( ( visibleWidth() / m_view->zoom() ) / r.width() ); double zoomY = m_view->zoom() * ( ( visibleHeight() / m_view->zoom() ) / r.height() ); double pageOffX = ( contentsWidth() - ( m_part->document().width() * m_view->zoom() ) ) / 2.0; double centerX = double( ( r.center().x() ) * m_view->zoom() + pageOffX ) / double( contentsWidth() ); double pageOffY = ( contentsHeight() - ( m_part->document().height() * m_view->zoom() ) ) / 2.0; double centerY = double( ( r.center().y() ) * m_view->zoom() + pageOffY ) / double( contentsHeight() ); double zoom = zoomX < zoomY ? zoomX : zoomY; resizeContents( int( ( zoom / m_view->zoom() ) * contentsWidth() ), int( ( zoom / m_view->zoom() ) * contentsHeight() ) ); setViewport( centerX, 1.0 - centerY ); m_view->setZoomAt( zoom ); viewport()->setUpdatesEnabled( true ); } void VCanvas::drawContents( TQPainter* painter, int clipx, int clipy, int clipw, int cliph ) { drawDocument( painter, KoRect( clipx, clipy, clipw, cliph ) ); } void VCanvas::drawDocument( TQPainter* /*painter*/, const KoRect&, bool drawVObjects ) { setYMirroring( m_view->painterFactory()->editpainter() ); VPainter* p = m_view->painterFactory()->painter(); if( drawVObjects ) { p->begin(); p->clear( TQColor( 195, 194, 193 ) ); p->setZoomFactor( m_view->zoom() ); setYMirroring( p ); // TRICK : slightly adjust the matrix so libart AA looks better TQWMatrix mat = p->worldMatrix(); p->setWorldMatrix( mat.translate( -.5, -.5 ) ); m_part->document().drawPage( p, m_part->pageLayout(), m_view->showPageMargins() ); KoRect r2 = boundingBox(); m_part->document().draw( p, &r2 ); p->end(); } // draw handle: VTQPainter qpainter( p->device() ); setYMirroring( &qpainter ); qpainter.setZoomFactor( m_view->zoom() ); m_part->document().selection()->draw( &qpainter, m_view->zoom() ); if( m_view->toolController()->currentTool() ) m_view->toolController()->currentTool()->draw( &qpainter ); bitBlt( viewport(), 0, 0, p->device(), 0, 0, width(), height() ); } void VCanvas::repaintAll( bool drawVObjects ) { drawDocument( 0, KoRect( 0, 0, width(), height() ), drawVObjects ); } /// repaints just a rect area (no scrolling) void VCanvas::repaintAll( const KoRect &r ) { drawDocument( 0, r ); } void VCanvas::resizeEvent( TQResizeEvent* event ) { double centerX = double( contentsX() + 0.5 * visibleWidth() ) / double( contentsWidth() ); double centerY = double( contentsY() + 0.5 * visibleHeight() ) / double( contentsHeight() ); TQScrollView::resizeEvent( event ); if( !m_pixmap ) m_pixmap = new TQPixmap( width(), height() ); else m_pixmap->resize( width(), height() ); VPainter *p = m_view->painterFactory()->painter(); p->resize( width(), height() ); p->clear( TQColor( 195, 194, 193 ) ); setViewport( centerX, centerY ); } void VCanvas::slotContentsMoving( int /*x*/, int /*y*/ ) { emit viewportChanged(); } void VCanvas::dragEnterEvent( TQDragEnterEvent *e ) { e->accept( KarbonDrag::canDecode( e ) || KColorDrag::canDecode( e ) ); } void VCanvas::dropEvent( TQDropEvent *e ) { m_view->dropEvent( e ); } #include "vcanvas.moc"