kivio

kivio_canvas.cpp

00001 /*
00002  * Kivio - Visual Modelling and Flowcharting
00003  * Copyright (C) 2000-2001 theKompany.com & Dave Marotti
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018  */
00019 #include "kivio_canvas.h"
00020 #include "kivio_page.h"
00021 #include "kivio_map.h"
00022 #include "kivio_view.h"
00023 #include "kivio_doc.h"
00024 
00025 #include "kivio_icon_view.h"
00026 #include "kivio_stencil.h"
00027 #include "kivio_stencil_spawner.h"
00028 #include "kivio_stencil_spawner_info.h"
00029 #include "kivio_stackbar.h"
00030 #include "kivio_screen_painter.h"
00031 #include "kivio_grid_data.h"
00032 #include "kivio_layer.h"
00033 
00034 #include "kivio_pluginmanager.h"
00035 
00036 #include <kdebug.h>
00037 #include <klocale.h>
00038 #include <kmessagebox.h>
00039 #include <kcursor.h>
00040 #include <KoGlobal.h>
00041 #include <KoZoomHandler.h>
00042 #include <KoSize.h>
00043 #include <KoRuler.h>
00044 #include <KoPoint.h>
00045 #include <KoTabBar.h>
00046 #include <kapplication.h>
00047 
00048 #include <assert.h>
00049 #include <stdio.h>
00050 #include <qlabel.h>
00051 #include <qpixmap.h>
00052 #include <qscrollbar.h>
00053 #include <qtimer.h>
00054 #include <qsize.h>
00055 
00056 using namespace Kivio;
00057 
00058 KivioCanvas::KivioCanvas( QWidget *par, KivioView* view, KivioDoc* doc, QScrollBar* vs, QScrollBar* hs)
00059 : QWidget(par, "KivioCanvas", WResizeNoErase | WRepaintNoErase),
00060   m_pView(view),
00061   m_pDoc(doc),
00062   m_pVertScrollBar(vs),
00063   m_pHorzScrollBar(hs),
00064   m_guides(view, view->zoomHandler())
00065 {
00066   setBackgroundMode(NoBackground);
00067   setAcceptDrops(true);
00068   setMouseTracking(true);
00069   setFocusPolicy(StrongFocus);
00070   setFocus();
00071 
00072   m_showConnectorTargets = false;
00073   delegateThisEvent = true;
00074 
00075   m_pVertScrollBar->setLineStep(1);
00076   m_pHorzScrollBar->setLineStep(1);
00077 
00078 
00079   m_pVertScrollBar->setPageStep(10);
00080   m_pHorzScrollBar->setPageStep(10);
00081 
00082   connect(m_pVertScrollBar, SIGNAL(valueChanged(int)), SLOT(scrollV(int)));
00083   connect( m_pHorzScrollBar, SIGNAL(valueChanged(int)), SLOT(scrollH(int)));
00084 
00085   m_iXOffset = 0;
00086   m_iYOffset = 0;
00087 
00088   m_pScrollX = 0;
00089   m_pScrollY = 0;
00090 
00091   m_pageOffsetX = 0;
00092   m_pageOffsetY = 0;
00093 
00094   m_pasteMoving = false;
00095 
00096   m_buffer = new QPixmap();
00097 
00098   m_pDragStencil = 0L;
00099   unclippedSpawnerPainter = 0L;
00100   unclippedPainter = 0L;
00101 
00102   m_borderTimer = new QTimer(this);
00103   connect(m_borderTimer,SIGNAL(timeout()),SLOT(borderTimerTimeout()));
00104 }
00105 
00106 KivioCanvas::~KivioCanvas()
00107 {
00108   delete m_buffer;
00109   delete m_borderTimer;
00110   delete unclippedPainter;
00111 }
00112 
00113 KivioPage* KivioCanvas::findPage( const QString& _name )
00114 {
00115   return m_pDoc->map()->findPage( _name );
00116 }
00117 
00118 const KivioPage* KivioCanvas::activePage() const
00119 {
00120   return m_pView->activePage();
00121 }
00122 
00123 KivioPage* KivioCanvas::activePage()
00124 {
00125   return m_pView->activePage();
00126 }
00127 
00128 void KivioCanvas::scrollH( int value )
00129 {
00130   // Relative movement
00131   int dx = m_iXOffset - value;
00132   // New absolute position
00133   m_iXOffset = value;
00134 
00135   bitBlt(m_buffer, dx, 0, m_buffer);
00136   scroll(dx, 0);
00137 
00138   emit visibleAreaChanged();
00139 }
00140 
00141 void KivioCanvas::scrollV( int value )
00142 {
00143   // Relative movement
00144   int dy = m_iYOffset - value;
00145   // New absolute position
00146   m_iYOffset = value;
00147 
00148   bitBlt(m_buffer, 0, dy, m_buffer);
00149   scroll(0, dy);
00150 
00151   emit visibleAreaChanged();
00152 }
00153 
00154 void KivioCanvas::scrollDx( int dx )
00155 {
00156   if ( dx == 0 )
00157     return;
00158 
00159   int value = m_iXOffset - dx;
00160   m_pHorzScrollBar->setValue(value);
00161 }
00162 
00163 void KivioCanvas::scrollDy( int dy )
00164 {
00165   if ( dy == 0 )
00166     return;
00167 
00168   int value = m_iYOffset - dy;
00169   m_pVertScrollBar->setValue(value);
00170 }
00171 
00172 void KivioCanvas::resizeEvent( QResizeEvent* )
00173 {
00174   m_buffer->resize(size());
00175   updateScrollBars();
00176 
00177   emit visibleAreaChanged();
00178 }
00179 
00180 void KivioCanvas::wheelEvent( QWheelEvent* ev )
00181 {
00182   ev->accept();
00183   
00184   if( (ev->delta()>0))
00185   {
00186      if(ev->state() == ControlButton) {
00187        zoomIn(ev->pos());
00188      } else if(ev->state() == ShiftButton) {
00189        m_pVertScrollBar->setValue(m_pVertScrollBar->value() - height());
00190      } else {
00191        m_pVertScrollBar->setValue(m_pVertScrollBar->value() - 30);
00192      }
00193   }
00194   else
00195   {
00196      if(ev->state() == ControlButton) {
00197        zoomOut(ev->pos());
00198      } else if(ev->state() == ShiftButton) {
00199        m_pVertScrollBar->setValue(m_pVertScrollBar->value() + height());
00200      } else {
00201        m_pVertScrollBar->setValue(m_pVertScrollBar->value() + 30);
00202      }
00203   }
00204 }
00205 
00206 void KivioCanvas::setUpdatesEnabled( bool isUpdate )
00207 {
00208   static int i = 0;
00209 
00210   QWidget::setUpdatesEnabled(isUpdate);
00211   if (isUpdate) {
00212     --i;
00213     if (i == 0) {
00214       update();
00215       updateScrollBars();
00216 
00217       blockSignals(false);
00218 
00219       emit visibleAreaChanged();
00220     }
00221   } else {
00222     i++;
00223     blockSignals(true);
00224   }
00225 }
00226 
00227 void KivioCanvas::zoomIn(const QPoint &p)
00228 {
00229   setUpdatesEnabled(false);
00230   KoPoint p0 = mapFromScreen(p);
00231   m_pView->viewZoom(m_pView->zoomHandler()->zoom() + 25);
00232   QPoint p1 = mapToScreen(p0);
00233   scrollDx(-p1.x()+p.x());
00234   scrollDy(-p1.y()+p.y());
00235   setUpdatesEnabled(true);
00236 }
00237 
00238 void KivioCanvas::zoomOut(const QPoint &p)
00239 {
00240   setUpdatesEnabled(false);
00241   KoPoint p0 = mapFromScreen(p);
00242   int newZoom = m_pView->zoomHandler()->zoom() - 25;
00243 
00244   if(newZoom > 0) {
00245     m_pView->viewZoom(newZoom);
00246     QPoint p1 = mapToScreen(p0);
00247     scrollDx(-p1.x()+p.x());
00248     scrollDy(-p1.y()+p.y());
00249   }
00250   setUpdatesEnabled(true);
00251 }
00252 
00253 void KivioCanvas::paintEvent( QPaintEvent* ev )
00254 {
00255   if ( m_pDoc->isLoading() || !activePage() )
00256     return;
00257 
00258   KivioPage* page = activePage();
00259 
00260   QPainter painter;
00261   painter.begin(m_buffer);
00262 
00263   KoPageLayout pl = page->paperLayout();
00264   int pw = m_pView->zoomHandler()->zoomItX(pl.ptWidth);
00265   int ph = m_pView->zoomHandler()->zoomItY(pl.ptHeight);
00266   QRect fillRect(0, 0, pw, ph);
00267   QRect paintRect = ev->rect();
00268   QRegion grayRegion(paintRect);
00269   grayRegion.translate(m_iXOffset - m_pageOffsetX, m_iYOffset - m_pageOffsetY);
00270   grayRegion -= fillRect;
00271   grayRegion.translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
00272 
00273   // This code comes from KPresenter's kprcanvas.cpp
00274   // Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
00275   painter.save();
00276   painter.setClipRegion(grayRegion, QPainter::CoordPainter);
00277   painter.setPen(Qt::NoPen);
00278   painter.fillRect(grayRegion.boundingRect(), KApplication::palette().active().brush(QColorGroup::Mid));
00279   painter.restore();
00280   // end of copy...
00281 
00282   painter.translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset +m_pageOffsetY);
00283   painter.fillRect(fillRect, white);
00284 
00285   // Draw Grid
00286   if(m_pDoc->grid().isShow) {
00287     KoPoint topLeft(0, 0);
00288     KoPoint bottomRight(pl.ptWidth, pl.ptHeight);
00289     QPoint zoomedTL = m_pView->zoomHandler()->zoomPoint(topLeft);
00290     QPoint zoomedBR = m_pView->zoomHandler()->zoomPoint(bottomRight);
00291 
00292     KoSize freq = m_pDoc->grid().freq;
00293 
00294     painter.setPen(m_pDoc->grid().color);
00295 
00296     double x = qRound(topLeft.x() / freq.width()) * freq.width();
00297     int zoomed = 0;
00298 
00299     while(x <= bottomRight.x()) {
00300       zoomed = m_pView->zoomHandler()->zoomItX(x);
00301       painter.drawLine(zoomed, zoomedTL.y(), zoomed, zoomedBR.y());
00302       x += freq.width();
00303     }
00304 
00305     double y = qRound(topLeft.y() / freq.height()) * freq.height();
00306 
00307     while(y <= bottomRight.y()) {
00308       zoomed = m_pView->zoomHandler()->zoomItY(y);
00309       painter.drawLine(zoomedTL.x(), zoomed, zoomedBR.x(), zoomed);
00310       y += freq.height();
00311     }
00312   }
00313 
00314   if(m_pView->isShowPageMargins()) {
00315     int ml = m_pView->zoomHandler()->zoomItX(pl.ptLeft);
00316     int mt = m_pView->zoomHandler()->zoomItY(pl.ptTop);
00317     int mr = m_pView->zoomHandler()->zoomItX(pl.ptRight);
00318     int mb = m_pView->zoomHandler()->zoomItY(pl.ptBottom);
00319 
00320     painter.save();
00321     painter.setPen(QPen("#C7C7C7",1,SolidLine));
00322     painter.drawRect(ml,mt,pw-ml-mr,ph-mt-mb);
00323     painter.restore();
00324   }
00325 
00326   // Draw page borders
00327   painter.setPen(black);
00328   painter.fillRect(pw, 3, 5, ph, gray);
00329   painter.fillRect(3, ph, pw, 3, gray);
00330   painter.drawRect(0, 0, pw, ph);
00331 
00332   // Draw content
00333   KivioScreenPainter kpainter;
00334   kpainter.start(m_buffer);
00335   kpainter.translateBy(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
00336   m_pDoc->paintContent(kpainter, paintRect, false, page, QPoint(0, 0), m_pView->zoomHandler(), showConnectorTargets(), true);
00337   kpainter.stop();
00338 
00339   if(m_pView->isShowGuides()) {
00340     m_guides.paintGuides(painter);
00341   }
00342 
00343   painter.end();
00344 
00345   bitBlt(this, paintRect.left(), paintRect.top(), m_buffer,
00346          paintRect.left(), paintRect.top(), paintRect.width(), paintRect.height());
00347 }
00348 
00349 void KivioCanvas::updateScrollBars()
00350 {
00351   if(!activePage()) {
00352     return;
00353   }
00354 
00355   KoPageLayout pl = activePage()->paperLayout();
00356   int pw = m_pView->zoomHandler()->zoomItX(pl.ptWidth);
00357   int ph = m_pView->zoomHandler()->zoomItY(pl.ptHeight);
00358 
00359   m_pScrollX = QMAX(pw - width(), 0);
00360   m_pScrollY = QMAX(ph - height(), 0);
00361 
00362   m_pHorzScrollBar->setRange(0, m_pScrollX);
00363   if ( m_pHorzScrollBar->value() > m_pHorzScrollBar->maxValue() ||
00364        m_pHorzScrollBar->value() < m_pHorzScrollBar->minValue() )
00365   {
00366     m_pHorzScrollBar->setValue(0);
00367   }
00368 
00369   m_pVertScrollBar->setRange(0, m_pScrollY);
00370   if ( m_pVertScrollBar->value() > m_pVertScrollBar->maxValue() ||
00371        m_pVertScrollBar->value() < m_pVertScrollBar->minValue() )
00372   {
00373     m_pVertScrollBar->setValue(0);
00374   }
00375 
00376   m_pVertScrollBar->setPageStep( height() );
00377   m_pHorzScrollBar->setPageStep( width() );
00378 
00379   if(pw >= width()) {
00380     m_pageOffsetX = 0;
00381   } else {
00382     m_pageOffsetX = (width() - pw) / 2;
00383   }
00384 
00385   if(ph >= height()) {
00386     m_pageOffsetY = 0;
00387   } else {
00388     m_pageOffsetY = (height() - ph) / 2;
00389   }
00390 }
00391 
00392 QSize KivioCanvas::actualSize() const
00393 {
00394   return QSize(m_pScrollX, m_pScrollY);
00395 }
00396 
00397 bool KivioCanvas::event( QEvent* e )
00398 {
00399   bool f = QWidget::event(e);
00400 
00401   if (m_pView->pluginManager() && delegateThisEvent) {
00402     f = m_pView->pluginManager()->delegateEvent(e);
00403   }
00404 
00405   delegateThisEvent = true;
00406   return f;
00407 }
00408 
00409 void KivioCanvas::enterEvent( QEvent* )
00410 {
00411 }
00412 
00413 void KivioCanvas::leaveEvent( QEvent* )
00414 {
00415   m_pView->setMousePos(-1, -1);
00416 }
00417 
00418 void KivioCanvas::mousePressEvent(QMouseEvent* e)
00419 {
00420     if(!m_pDoc->isReadWrite())
00421         return;
00422 
00423     if(m_pasteMoving) {
00424       endPasteMoving();
00425       return;
00426     }
00427 
00428     Kivio::PluginManager* pluginManager = view()->pluginManager();
00429 
00430     if(m_pView->isShowGuides() && (!pluginManager || (pluginManager->defaultTool() == pluginManager->activeTool()))) {
00431       if(m_guides.mousePressEvent(e)) {
00432         delegateThisEvent = false;
00433         return;
00434       }
00435     }
00436 }
00437 
00438 void KivioCanvas::mouseReleaseEvent(QMouseEvent* e)
00439 {
00440   if(!m_pDoc->isReadWrite())
00441     return;
00442 
00443   Kivio::PluginManager* pluginManager = view()->pluginManager();
00444 
00445   if(view()->isShowGuides() && (!pluginManager || (pluginManager->defaultTool() == pluginManager->activeTool()))) {
00446     if(m_guides.mouseReleaseEvent(e)) {
00447       delegateThisEvent = false;
00448       return;
00449     }
00450   }
00451 }
00452 
00453 void KivioCanvas::mouseMoveEvent(QMouseEvent* e)
00454 {
00455   if(!m_pDoc->isReadWrite())
00456     return;
00457 
00458   if(m_pasteMoving) {
00459     continuePasteMoving(e->pos());
00460   } else {
00461     Kivio::PluginManager* pluginManager = view()->pluginManager();
00462 
00463     if(m_pView->isShowGuides() && (!pluginManager || (pluginManager->defaultTool() == pluginManager->activeTool()))) {
00464       delegateThisEvent = !m_guides.mouseMoveEvent(e);
00465     }
00466   }
00467 
00468   lastPoint = e->pos();
00469   view()->setMousePos(lastPoint.x(), lastPoint.y());
00470 }
00471 
00472 QPoint KivioCanvas::mapToScreen(const KoPoint& pos)
00473 {
00474   QPoint p;
00475   int x = m_pView->zoomHandler()->zoomItX(pos.x());
00476   int y = m_pView->zoomHandler()->zoomItY(pos.y());
00477 
00478   p.setX( x - m_iXOffset + m_pageOffsetX);
00479   p.setY( y - m_iYOffset + m_pageOffsetY);
00480 
00481   return p;
00482 }
00483 
00484 KoPoint KivioCanvas::mapFromScreen( const QPoint & pos )
00485 {
00486   int x = pos.x() + m_iXOffset - m_pageOffsetX;
00487   int y = pos.y() + m_iYOffset - m_pageOffsetY;
00488   double xf = m_pView->zoomHandler()->unzoomItX(x);
00489   double yf = m_pView->zoomHandler()->unzoomItY(y);
00490 
00491   KoPoint p(xf, yf);
00492   return p;
00493 }
00494 
00495 void KivioCanvas::startRectDraw( const QPoint &p, RectType )
00496 {
00497   currRect = QRect( 0, 0, -1, -1 );
00498 
00499   QPoint pos( p );
00500   oldRectValid = false;
00501   beginUnclippedPainter();
00502   rectAnchor = pos;
00503   currRect = QRect( rectAnchor, QPoint(0,0) );
00504 
00505   m_borderTimer->start(100);
00506 }
00507 
00508 void KivioCanvas::continueRectDraw( const QPoint &p, RectType )
00509 {
00510   QPoint pos = p;
00511   QPoint p2 = pos;
00512   QRect r( rectAnchor, p2 );
00513   r = r.normalize();
00514 
00515   if ( oldRectValid )
00516     unclippedPainter->drawRect( currRect );
00517   if ( r.width() > 1 || r.height() > 1 ) {
00518     oldRectValid = true;
00519     currRect = r;
00520     unclippedPainter->drawRect( currRect );
00521   } else {
00522     oldRectValid = false;
00523   }
00524 }
00525 
00526 void KivioCanvas::endRectDraw()
00527 {
00528   m_borderTimer->stop();
00529 
00530   if ( !unclippedPainter )
00531     return;
00532 
00533   if ( oldRectValid )
00534     unclippedPainter->drawRect( currRect );
00535 
00536   endUnclippedPainter();
00537 }
00538 
00547 void KivioCanvas::startSpawnerDragDraw( const QPoint &p )
00548 {
00549   currRect = QRect( 0, 0, -1, -1 );
00550 
00551   KivioStencilSpawner *pSpawner = KivioIconView::curDragSpawner();
00552   if( !pSpawner )
00553     return;
00554 
00555   // If we for some reason didn't delete an old drag stencil,
00556   // do so now.
00557   if( m_pDragStencil )
00558   {
00559     kdDebug(43000) << "KivioCanvas::startSpawnerDragDraw() - m_pDragStencil still exists.  BUG!" << endl;
00560     delete m_pDragStencil;
00561     m_pDragStencil = 0L;
00562   }
00563 
00564   // Map the point from screenspace to page space
00565   KoPoint qp = mapFromScreen( p );
00566   qp = snapToGrid(qp);
00567 
00568   // Allocate a new stencil for dragging around
00569   m_pDragStencil = pSpawner->newStencil();
00570   m_pDragStencil->setPosition( qp.x(), qp.y() );
00571 
00572   // Invalidate the rectangle
00573   oldRectValid = true;
00574 
00575   // Create a new painter object
00576   beginUnclippedSpawnerPainter();
00577 
00578   // Translate the painter so that 0,0 means where the page starts on the canvas
00579   unclippedSpawnerPainter->painter()->save();
00580   unclippedSpawnerPainter->painter()->translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
00581 
00582   // Assign the painter object to the intra-stencil data object, as well
00583   // as the zoom factor
00584   m_dragStencilData.painter = unclippedSpawnerPainter;
00585   m_dragStencilData.zoomHandler = m_pView->zoomHandler();
00586 
00587   // Draw the outline of the stencil
00588   m_pDragStencil->paintOutline( &m_dragStencilData );
00589 
00590   unclippedSpawnerPainter->painter()->restore();
00591 }
00592 
00596 void KivioCanvas::continueSpawnerDragDraw( const QPoint &p )
00597 {
00598   bool snappedX, snappedY;
00599 
00600   // Translate the painter so that 0,0 means where the page starts on the canvas
00601   unclippedSpawnerPainter->painter()->save();
00602   unclippedSpawnerPainter->painter()->translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
00603 
00604   // Undraw the old outline
00605   if( oldRectValid )
00606   {
00607     m_pDragStencil->paintOutline( &m_dragStencilData );
00608   }
00609 
00610   // Map the new point from screenspace to page space
00611   KoPoint orig = mapFromScreen(p);
00612   KoPoint qp = snapToGrid( orig );
00613 
00614   // First snap to screen
00615   qp = snapToGrid(qp);
00616   m_pDragStencil->setPosition( qp.x(), qp.y() );
00617 
00618   // Now snap to the guides
00619   qp.setCoords(orig.x() + m_pDragStencil->w(), orig.y() + m_pDragStencil->h());
00620   qp = snapToGuides(qp, snappedX, snappedY);
00621 
00622   if(snappedX) {
00623     m_pDragStencil->setX(qp.x() - m_pDragStencil->w());
00624   }
00625 
00626   if(snappedY) {
00627     m_pDragStencil->setY(qp.y() - m_pDragStencil->h());
00628   }
00629 
00630   qp.setCoords(orig.x() + (m_pDragStencil->w() / 2.0), orig.y() + (m_pDragStencil->h() / 2.0));
00631   qp = snapToGuides(qp, snappedX, snappedY);
00632 
00633   if(snappedX) {
00634     m_pDragStencil->setX(qp.x() - (m_pDragStencil->w() / 2.0));
00635   }
00636 
00637   if(snappedY) {
00638     m_pDragStencil->setY(qp.y() - (m_pDragStencil->h() / 2.0));
00639   }
00640 
00641   qp.setCoords(orig.x(), orig.y());
00642   qp = snapToGuides(qp, snappedX, snappedY);
00643 
00644   if(snappedX) {
00645     m_pDragStencil->setX(qp.x());
00646   }
00647 
00648   if(snappedY) {
00649     m_pDragStencil->setY(qp.y());
00650   }
00651 
00652   // Redraw the new outline
00653   oldRectValid = true;
00654   m_pDragStencil->paintOutline( &m_dragStencilData );
00655   unclippedSpawnerPainter->painter()->restore();
00656 
00657 }
00658 
00659 
00663 void KivioCanvas::endSpawnerDragDraw()
00664 {
00665   // Avoid the noid
00666   if ( !unclippedSpawnerPainter )
00667     return;
00668 
00669   // If we have a valid old drawing spot, undraw it
00670   if ( oldRectValid )
00671   {
00672     unclippedSpawnerPainter->painter()->save();
00673     unclippedSpawnerPainter->painter()->translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
00674     m_pDragStencil->paintOutline( &m_dragStencilData );
00675     unclippedSpawnerPainter->painter()->restore();
00676   }
00677 
00678   // Smack the painter around a bit
00679   endUnclippedSpawnerPainter();
00680 
00681   // If we have a stencil we were dragging around, delete it.
00682   if( m_pDragStencil )
00683   {
00684     delete m_pDragStencil;
00685     m_pDragStencil = 0L;
00686   }
00687 
00688   setFocus();
00689 }
00690 
00691 
00695 void KivioCanvas::beginUnclippedSpawnerPainter()
00696 {
00697     // End any previous attempts
00698     endUnclippedSpawnerPainter();
00699 
00700     // I have no idea what this does.  Max?
00701     bool unclipped = testWFlags( WPaintUnclipped );
00702     setWFlags( WPaintUnclipped );
00703 
00704 
00705     // Allocate a new painter object for use in drawing
00706     unclippedSpawnerPainter = new KivioScreenPainter();
00707 
00708     // Tell it to start (allocates a Qpainter object)
00709     unclippedSpawnerPainter->start(this);
00710 
00711     // Uhhhhh??
00712     if( !unclipped )
00713         clearWFlags( WPaintUnclipped );
00714 
00715 
00716     // Make sure it's doing NOT drawing.
00717     unclippedSpawnerPainter->painter()->setRasterOp( NotROP );
00718     unclippedSpawnerPainter->painter()->setPen( QColor(0,0,250) );
00719 
00720 }
00721 
00722 
00726 void KivioCanvas::endUnclippedSpawnerPainter()
00727 {
00728     if( unclippedSpawnerPainter )
00729     {
00730         unclippedSpawnerPainter->stop();
00731         delete unclippedSpawnerPainter;
00732         unclippedSpawnerPainter = 0L;
00733     }
00734 }
00735 
00736 void KivioCanvas::beginUnclippedPainter()
00737 {
00738     endUnclippedPainter();
00739     bool unclipped = testWFlags( WPaintUnclipped );
00740 
00741     setWFlags( WPaintUnclipped );
00742     unclippedPainter = new QPainter;
00743     unclippedPainter->begin( this );
00744 
00745     if ( !unclipped )
00746         clearWFlags( WPaintUnclipped );
00747 
00748     unclippedPainter->setRasterOp( NotROP );
00749     unclippedPainter->setPen( QPen(blue,1,DotLine) );
00750 }
00751 
00752 void KivioCanvas::endUnclippedPainter()
00753 {
00754     if ( unclippedPainter )
00755     {
00756         unclippedPainter->end();
00757         delete unclippedPainter;
00758         unclippedPainter = 0;
00759     }
00760 }
00761 
00762 void KivioCanvas::borderTimerTimeout()
00763 {
00764   QPoint p = mapFromGlobal(QCursor::pos());
00765   int dx = 0;
00766   int dy = 0;
00767   int d = 10;
00768 
00769   QRect r(currRect);
00770   int vpos = m_pVertScrollBar->value();
00771   int vmax = m_pVertScrollBar->maxValue();
00772   int vmin = m_pVertScrollBar->minValue();
00773 
00774   int hpos = m_pHorzScrollBar->value();
00775   int hmax = m_pHorzScrollBar->maxValue();
00776   int hmin = m_pHorzScrollBar->minValue();
00777 
00778   if ( p.x() < 0 && hpos > hmin ) {
00779     dx = QMIN(d,hpos-hmin);
00780     r.setRight(r.right()+dx);
00781     rectAnchor.setX(rectAnchor.x()+dx);
00782   }
00783 
00784   if ( p.y() < 0 && vpos > vmin ) {
00785     dy = QMIN(d,vpos-vmin);
00786     r.setBottom(r.bottom()+dy);
00787     rectAnchor.setY(rectAnchor.y()+dy);
00788   }
00789 
00790   if ( p.x() > width() && hpos < hmax ) {
00791     dx = -QMIN(d,hmax-hpos);
00792     r.setLeft(r.left()+dx);
00793     rectAnchor.setX(rectAnchor.x()+dx);
00794   }
00795 
00796   if ( p.y() > height() && vpos < vmax  ) {
00797     dy = -QMIN(d,vmax-vpos);
00798     r.setTop(r.top()+dy);
00799     rectAnchor.setY(rectAnchor.y()+dy);
00800   }
00801 
00802   if ( dx != 0 || dy != 0 ) {
00803     unclippedPainter->drawRect( currRect );
00804     scrollDx(dx);
00805     scrollDy(dy);
00806     unclippedPainter->drawRect( r );
00807     currRect = r;
00808   }
00809 }
00810 
00811 
00822 void KivioCanvas::dragEnterEvent( QDragEnterEvent *e )
00823 {
00824     if( e->provides("kivio/stencilSpawner") )
00825     {
00826         e->accept();
00827         startSpawnerDragDraw( e->pos() );
00828         activePage()->unselectAllStencils();
00829         updateAutoGuideLines();
00830     }
00831 }
00832 
00833 
00834 
00844 void KivioCanvas::dragMoveEvent( QDragMoveEvent *e )
00845 {
00846     // Does it speak our language?
00847     if( e->provides("kivio/stencilSpawner") )
00848     {
00849         e->accept();
00850         continueSpawnerDragDraw( e->pos() );
00851     }
00852 }
00853 
00854 
00865 void KivioCanvas::dropEvent( QDropEvent *e )
00866 {
00867     // Terminate the drawing object
00868     endSpawnerDragDraw();
00869 
00870     // Get a pointer to the currently dragged KivioStencilSpawner object
00871     KivioStencilSpawner *pSpawner = KivioIconView::curDragSpawner();
00872     
00873     if( !pSpawner )
00874         return;
00875         
00876     QPoint pos = e->pos();
00877     KoPoint pagePoint = snapToGrid(mapFromScreen( pos ));
00878     view()->addStencilFromSpawner(pSpawner, pagePoint.x(), pagePoint.y());
00879 
00880     // FIXME Select the "selection tool" in case it's not done
00881 }
00882 
00883 
00892 void KivioCanvas::dragLeaveEvent( QDragLeaveEvent * )
00893 {
00894     endSpawnerDragDraw();
00895 }
00896 
00897 
00898 
00899 void KivioCanvas::drawSelectedStencilsXOR()
00900 {
00901     // This should never happen, but check just in case
00902     if ( !unclippedSpawnerPainter )
00903         return;
00904 
00905     // Translate the painter so that 0,0 means where the page starts on the canvas
00906     unclippedSpawnerPainter->painter()->save();
00907     unclippedSpawnerPainter->painter()->translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
00908 
00909     // Assign the painter object to the intra-stencil data object, as well
00910     // as the zoom factor
00911     m_dragStencilData.painter = unclippedSpawnerPainter;
00912     m_dragStencilData.zoomHandler = m_pView->zoomHandler();
00913 
00914     KivioStencil *pStencil = activePage()->selectedStencils()->first();
00915     while( pStencil )
00916     {
00917         pStencil->paintOutline( &m_dragStencilData );
00918         pStencil->paintSelectionHandles( &m_dragStencilData );
00919 
00920         pStencil = activePage()->selectedStencils()->next();
00921     }
00922 
00923     unclippedSpawnerPainter->painter()->restore();
00924 }
00925 
00926 void KivioCanvas::drawStencilXOR( KivioStencil *pStencil )
00927 {
00928     // This should never happen, but check just in case
00929     if ( !unclippedSpawnerPainter )
00930         return;
00931 
00932     // Translate the painter so that 0,0 means where the page starts on the canvas
00933     unclippedSpawnerPainter->painter()->save();
00934     unclippedSpawnerPainter->painter()->translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
00935 
00936     // Assign the painter object to the intra-stencil data object, as well
00937     // as the zoom factor
00938     m_dragStencilData.painter = unclippedSpawnerPainter;
00939     m_dragStencilData.zoomHandler = m_pView->zoomHandler();
00940 
00941     pStencil->paintOutline( &m_dragStencilData );
00942     pStencil->paintSelectionHandles( &m_dragStencilData );
00943 
00944     unclippedSpawnerPainter->painter()->restore();
00945 }
00946 
00947 void KivioCanvas::keyPressEvent( QKeyEvent *e )
00948 {
00949   if(view()->isShowGuides() && m_guides.keyPressEvent(e)) {
00950     return;
00951   }
00952 }
00953 
00954 KoPoint KivioCanvas::snapToGridAndGuides(const KoPoint& point)
00955 {
00956   KoPoint p = point;
00957 
00958   p = snapToGrid(p);
00959 
00960   bool snappedX, snappedY;
00961   KoPoint guidePoint = snapToGuides(point, snappedX, snappedY);
00962 
00963   if(snappedX) {
00964     p.setX(guidePoint.x());
00965   }
00966 
00967   if(snappedY) {
00968     p.setY(guidePoint.y());
00969   }
00970 
00971   return p;
00972 }
00973 
00974 KoPoint KivioCanvas::snapToGrid(const KoPoint& point)
00975 {
00976   if (!m_pDoc->grid().isSnap)
00977     return point;
00978 
00979   KoPoint p = point;
00980 
00981   KoSize dist = m_pDoc->grid().snap;
00982   KoSize freq = m_pDoc->grid().freq;
00983 
00984   double dx = qRound(p.x() / freq.width());
00985   double dy = qRound(p.y() / freq.height());
00986 
00987   double distx = QABS(p.x() - (freq.width() * dx));
00988   double disty = QABS(p.y() - (freq.height() * dy));
00989 
00990   if(distx < dist.width()) {
00991     p.setX(freq.width() * dx);
00992   }
00993 
00994   if(disty < dist.height()) {
00995     p.setY(freq.height() * dy);
00996   }
00997 
00998   return p;
00999 }
01000 
01001 KoPoint KivioCanvas::snapToGuides(const KoPoint& point, bool &snappedX, bool &snappedY)
01002 {
01003   snappedX = false;
01004   snappedY = false;
01005   KoPoint p = point;
01006 
01007   if (m_pView->isSnapGuides())
01008   {
01009     KoGuides::SnapStatus status = KoGuides::SNAP_NONE;
01010     KoPoint diff;
01011     m_guides.snapToGuideLines(p, 4, status, diff);
01012     p += diff;
01013 
01014     if(status & KoGuides::SNAP_HORIZ) {
01015       snappedY = true;
01016     }
01017     if(status & KoGuides::SNAP_VERT) {
01018       snappedX = true;
01019     }
01020 
01021     m_guides.repaintSnapping(p, status);
01022   }
01023 
01024   return p;
01025 }
01026 
01027 void KivioCanvas::setViewCenterPoint(const KoPoint &p)
01028 {
01029   setUpdatesEnabled(false);
01030 
01031   KoRect va = visibleArea();
01032 
01033   double x = QMAX(0.0, p.x() - (va.width() / 2.0));
01034   double y = QMAX(0.0, p.y() - (va.height() / 2.0));
01035 
01036   m_pVertScrollBar->setValue(m_pView->zoomHandler()->zoomItY(y));
01037   m_pHorzScrollBar->setValue(m_pView->zoomHandler()->zoomItX(x));
01038 
01039   setUpdatesEnabled(true);
01040 }
01041 
01042 KoRect KivioCanvas::visibleArea()
01043 {
01044   KoPoint p0 = mapFromScreen(QPoint(0,0));
01045   KoPoint p1 = mapFromScreen(QPoint(width()-1,height()-1));
01046 
01047   return KoRect(p0.x(), p0.y(), p1.x() - p0.x(), p1.y() - p0.y());
01048 }
01049 
01050 void KivioCanvas::setVisibleArea(KoRect r, int margin)
01051 {
01052   setUpdatesEnabled(false);
01053   KoZoomHandler zoom;
01054   zoom.setZoomAndResolution(100, KoGlobal::dpiX(),
01055     KoGlobal::dpiY());
01056 
01057   float cw = width() - 2 * margin;
01058   float ch = height() - 2 * margin;
01059 
01060   float zw = cw / (float)zoom.zoomItX(r.width());
01061   float zh = ch / (float)zoom.zoomItY(r.height());
01062   float z = QMIN(zw, zh);
01063 
01064   m_pView->viewZoom(qRound(z * 100));
01065 
01066   KoPoint c = r.center();
01067 
01068   setViewCenterPoint(KoPoint(c.x(), c.y()));
01069   setUpdatesEnabled(true);
01070 }
01071 
01072 void KivioCanvas::setVisibleAreaByWidth(KoRect r, int margin)
01073 {
01074   setUpdatesEnabled(false);
01075   KoZoomHandler zoom;
01076   zoom.setZoomAndResolution(100, KoGlobal::dpiX(),
01077     KoGlobal::dpiY());
01078 
01079   float cw = width() - 2*margin;
01080   float z = cw / (float)zoom.zoomItX(r.width());
01081 
01082   m_pView->viewZoom(qRound(z * 100));
01083 
01084   KoPoint c = r.center();
01085 
01086   setViewCenterPoint(KoPoint(c.x(), c.y()));
01087   setUpdatesEnabled(true);
01088 }
01089 
01090 void KivioCanvas::setVisibleAreaByHeight(KoRect r, int margin)
01091 {
01092   setUpdatesEnabled(false);
01093   KoZoomHandler zoom;
01094   zoom.setZoomAndResolution(100, KoGlobal::dpiX(),
01095     KoGlobal::dpiY());
01096 
01097   float ch = height() - 2*margin;
01098   float z = ch / (float)zoom.zoomItY(r.height());
01099 
01100   m_pView->viewZoom(qRound(z * 100));
01101 
01102   KoPoint c = r.center();
01103 
01104   setViewCenterPoint(KoPoint(c.x(), c.y()));
01105   setUpdatesEnabled(true);
01106 }
01107 
01108 void KivioCanvas::startPasteMoving()
01109 {
01110   setEnabled(false);
01111   KoPoint p = activePage()->getRectForAllSelectedStencils().center();
01112   m_origPoint.setCoords(p.x(), p.y());
01113 
01114   // Create a new painter object
01115   beginUnclippedSpawnerPainter();
01116   drawSelectedStencilsXOR();
01117 
01118   // Build the list of old geometry
01119   KoRect *pData;
01120   m_lstOldGeometry.clear();
01121   KivioStencil* pStencil = activePage()->selectedStencils()->first();
01122 
01123   while( pStencil )
01124   {
01125     pData = new KoRect;
01126     *pData = pStencil->rect();
01127     m_lstOldGeometry.append(pData);
01128 
01129     pStencil = activePage()->selectedStencils()->next();
01130   }
01131 
01132   continuePasteMoving(lastPoint);
01133   m_pasteMoving = true;
01134   setEnabled(true);
01135 }
01136 
01137 void KivioCanvas::continuePasteMoving(const QPoint &pos)
01138 {
01139   KoPoint pagePoint = mapFromScreen( pos );
01140 
01141   double dx = pagePoint.x() - m_origPoint.x();
01142   double dy = pagePoint.y() - m_origPoint.y();
01143 
01144   bool snappedX;
01145   bool snappedY;
01146 
01147   double newX, newY;
01148 
01149   // Undraw the old stencils
01150   drawSelectedStencilsXOR();
01151 
01152   // Translate to the new position
01153   KoPoint p;
01154   KoRect selectedRect = activePage()->getRectForAllSelectedStencils();
01155 
01156   newX = selectedRect.x() + dx;
01157   newY = selectedRect.y() + dy;
01158 
01159   // First attempt a snap-to-grid
01160   p.setCoords(newX, newY);
01161   p = snapToGrid(p);
01162 
01163   newX = p.x();
01164   newY = p.y();
01165 
01166   // Now the guides override the grid so we attempt to snap to them
01167   p.setCoords(selectedRect.x() + dx + selectedRect.width(), selectedRect.y() + dy + selectedRect.height());
01168   p = snapToGuides(p, snappedX, snappedY);
01169 
01170   if(snappedX) {
01171     newX = p.x() - selectedRect.width();
01172   }
01173 
01174   if(snappedY) {
01175     newY = p.y() - selectedRect.height();
01176   }
01177 
01178   p.setCoords(selectedRect.x() + dx + (selectedRect.width() / 2.0), selectedRect.y() + dy + (selectedRect.height() / 2.0));
01179   p = snapToGuides(p, snappedX, snappedY);
01180 
01181   if(snappedX) {
01182     newX = p.x() - (selectedRect.width() / 2.0);
01183   }
01184 
01185   if(snappedY) {
01186     newY = p.y() - (selectedRect.height() / 2.0);
01187   }
01188 
01189   p.setCoords(selectedRect.x() + dx, selectedRect.y() + dy);
01190   p = snapToGuides(p, snappedX, snappedY);
01191 
01192   if(snappedX) {
01193     newX = p.x();
01194   }
01195 
01196   if(snappedY) {
01197     newY = p.y();
01198   }
01199 
01200   dx = newX - selectedRect.x();
01201   dy = newY - selectedRect.y();
01202 
01203   // Translate to the new position
01204   KivioStencil *pStencil = activePage()->selectedStencils()->first();
01205   KoRect* pData = m_lstOldGeometry.first();
01206   // bool move = true;
01207 
01208   while( pStencil && pData )
01209   {
01210     newX = pData->x() + dx;
01211     newY = pData->y() + dy;
01212 
01213     if( pStencil->protection()->at( kpX ) == false ) {
01214       pStencil->setX(newX);
01215     }
01216     if( pStencil->protection()->at( kpY ) == false ) {
01217       pStencil->setY(newY);
01218     }
01219 
01220     pData = m_lstOldGeometry.next();
01221     pStencil = activePage()->selectedStencils()->next();
01222   }
01223 
01224   // Draw the stencils
01225   drawSelectedStencilsXOR();
01226   m_pView->updateToolBars();
01227 }
01228 
01229 void KivioCanvas::endPasteMoving()
01230 {
01231   KivioStencil *pStencil = activePage()->selectedStencils()->first();
01232   KoRect *pData = m_lstOldGeometry.first();
01233 
01234   while( pStencil && pData )
01235   {
01236     if(pStencil->type() == kstConnector) {
01237       pStencil->searchForConnections(m_pView->activePage(), m_pView->zoomHandler()->unzoomItY(4));
01238     }
01239 
01240     pData = m_lstOldGeometry.next();
01241     pStencil = activePage()->selectedStencils()->next();
01242   }
01243 
01244   drawSelectedStencilsXOR();
01245 
01246   endUnclippedSpawnerPainter();
01247 
01248   // Clear the list of old geometry
01249   m_lstOldGeometry.clear();
01250   m_pasteMoving = false;
01251 }
01252 
01253 void KivioCanvas::updateAutoGuideLines()
01254 {
01255   QValueList<double> hGuideLines;
01256   QValueList<double> vGuideLines;
01257   QPtrList<KivioLayer> layerList = *(activePage()->layers());
01258   QPtrListIterator<KivioLayer> layerIt(layerList);
01259   KivioLayer* layer = 0;
01260   QPtrList<KivioStencil> stencilList;
01261   QPtrListIterator<KivioStencil> stencilIt(stencilList);
01262   KivioStencil* stencil = 0;
01263 
01264   while((layer = layerIt.current()) != 0) {
01265     ++layerIt;
01266 
01267     if(layer->visible()) {
01268       stencilList = *(layer->stencilList());
01269       stencilIt.toFirst();
01270 
01271       while((stencil = stencilIt.current()) != 0) {
01272         ++stencilIt;
01273 
01274         if(!stencil->isSelected()) {
01275           hGuideLines << stencil->y() << (stencil->y() + (stencil->h() / 2.0)) << (stencil->y() + stencil->h());
01276           vGuideLines << stencil->x() << (stencil->x() + (stencil->w() / 2.0)) << (stencil->x() + stencil->w());
01277         }
01278       }
01279     }
01280   }
01281 
01282   KoPageLayout pl = activePage()->paperLayout();
01283 
01284   // Add the middle of the page and the margins
01285   hGuideLines << (pl.ptHeight / 2.0) << pl.ptTop << pl.ptBottom;
01286   vGuideLines << (pl.ptWidth / 2.0) << pl.ptLeft << pl.ptRight;
01287 
01288   guideLines().setAutoGuideLines(hGuideLines, vGuideLines);
01289 }
01290 
01291 #include "kivio_canvas.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys