kivio_canvas.cpp
1/*
2 * Kivio - Visual Modelling and Flowcharting
3 * Copyright (C) 2000-2001 theKompany.com & Dave Marotti
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19#include "kivio_canvas.h"
20#include "kivio_page.h"
21#include "kivio_map.h"
22#include "kivio_view.h"
23#include "kivio_doc.h"
24
25#include "kivio_icon_view.h"
26#include "kivio_stencil.h"
27#include "kivio_stencil_spawner.h"
28#include "kivio_stencil_spawner_info.h"
29#include "kivio_stackbar.h"
30#include "kivio_screen_painter.h"
31#include "kivio_grid_data.h"
32#include "kivio_layer.h"
33
34#include "kivio_pluginmanager.h"
35
36#include <kdebug.h>
37#include <tdelocale.h>
38#include <tdemessagebox.h>
39#include <kcursor.h>
40#include <KoGlobal.h>
41#include <KoZoomHandler.h>
42#include <KoSize.h>
43#include <KoRuler.h>
44#include <KoPoint.h>
45#include <KoTabBar.h>
46#include <tdeapplication.h>
47
48#include <assert.h>
49#include <stdio.h>
50#include <tqlabel.h>
51#include <tqpixmap.h>
52#include <tqscrollbar.h>
53#include <tqtimer.h>
54#include <tqsize.h>
55
56using namespace Kivio;
57
58KivioCanvas::KivioCanvas( TQWidget *par, KivioView* view, KivioDoc* doc, TQScrollBar* vs, TQScrollBar* hs)
59: TQWidget(par, "KivioCanvas", WResizeNoErase | WRepaintNoErase),
60 m_pView(view),
61 m_pDoc(doc),
62 m_pVertScrollBar(vs),
63 m_pHorzScrollBar(hs),
64 m_guides(view, view->zoomHandler())
65{
66 setBackgroundMode(NoBackground);
67 setAcceptDrops(true);
68 setMouseTracking(true);
69 setFocusPolicy(TQWidget::StrongFocus);
70 setFocus();
71
72 m_showConnectorTargets = false;
73 delegateThisEvent = true;
74
75 m_pVertScrollBar->setLineStep(1);
76 m_pHorzScrollBar->setLineStep(1);
77
78
79 m_pVertScrollBar->setPageStep(10);
80 m_pHorzScrollBar->setPageStep(10);
81
82 connect(m_pVertScrollBar, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(scrollV(int)));
83 connect( m_pHorzScrollBar, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(scrollH(int)));
84
85 m_iXOffset = 0;
86 m_iYOffset = 0;
87
88 m_pScrollX = 0;
89 m_pScrollY = 0;
90
91 m_pageOffsetX = 0;
92 m_pageOffsetY = 0;
93
94 m_pasteMoving = false;
95
96 m_buffer = new TQPixmap();
97
98 m_pDragStencil = 0L;
99 unclippedSpawnerPainter = 0L;
100 unclippedPainter = 0L;
101
102 m_borderTimer = new TQTimer(this);
103 connect(m_borderTimer,TQ_SIGNAL(timeout()),TQ_SLOT(borderTimerTimeout()));
104}
105
106KivioCanvas::~KivioCanvas()
107{
108 delete m_buffer;
109 delete m_borderTimer;
110 delete unclippedPainter;
111}
112
113KivioPage* KivioCanvas::findPage( const TQString& _name )
114{
115 return m_pDoc->map()->findPage( _name );
116}
117
118const KivioPage* KivioCanvas::activePage() const
119{
120 return m_pView->activePage();
121}
122
123KivioPage* KivioCanvas::activePage()
124{
125 return m_pView->activePage();
126}
127
128void KivioCanvas::scrollH( int value )
129{
130 // Relative movement
131 int dx = m_iXOffset - value;
132 // New absolute position
133 m_iXOffset = value;
134
135 bitBlt(m_buffer, dx, 0, m_buffer);
136 scroll(dx, 0);
137
138 emit visibleAreaChanged();
139}
140
141void KivioCanvas::scrollV( int value )
142{
143 // Relative movement
144 int dy = m_iYOffset - value;
145 // New absolute position
146 m_iYOffset = value;
147
148 bitBlt(m_buffer, 0, dy, m_buffer);
149 scroll(0, dy);
150
151 emit visibleAreaChanged();
152}
153
154void KivioCanvas::scrollDx( int dx )
155{
156 if ( dx == 0 )
157 return;
158
159 int value = m_iXOffset - dx;
160 m_pHorzScrollBar->setValue(value);
161}
162
163void KivioCanvas::scrollDy( int dy )
164{
165 if ( dy == 0 )
166 return;
167
168 int value = m_iYOffset - dy;
169 m_pVertScrollBar->setValue(value);
170}
171
172void KivioCanvas::resizeEvent( TQResizeEvent* )
173{
174 m_buffer->resize(size());
175 updateScrollBars();
176
177 emit visibleAreaChanged();
178}
179
180void KivioCanvas::wheelEvent( TQWheelEvent* ev )
181{
182 ev->accept();
183
184 if( (ev->delta()>0))
185 {
186 if(ev->state() == ControlButton) {
187 zoomIn(ev->pos());
188 } else if(ev->state() == ShiftButton) {
189 m_pVertScrollBar->setValue(m_pVertScrollBar->value() - height());
190 } else {
191 m_pVertScrollBar->setValue(m_pVertScrollBar->value() - 30);
192 }
193 }
194 else
195 {
196 if(ev->state() == ControlButton) {
197 zoomOut(ev->pos());
198 } else if(ev->state() == ShiftButton) {
199 m_pVertScrollBar->setValue(m_pVertScrollBar->value() + height());
200 } else {
201 m_pVertScrollBar->setValue(m_pVertScrollBar->value() + 30);
202 }
203 }
204}
205
206void KivioCanvas::setUpdatesEnabled( bool isUpdate )
207{
208 static int i = 0;
209
210 TQWidget::setUpdatesEnabled(isUpdate);
211 if (isUpdate) {
212 --i;
213 if (i == 0) {
214 update();
215 updateScrollBars();
216
217 blockSignals(false);
218
219 emit visibleAreaChanged();
220 }
221 } else {
222 i++;
223 blockSignals(true);
224 }
225}
226
227void KivioCanvas::zoomIn(const TQPoint &p)
228{
229 setUpdatesEnabled(false);
230 KoPoint p0 = mapFromScreen(p);
231 m_pView->viewZoom(m_pView->zoomHandler()->zoom() + 25);
232 TQPoint p1 = mapToScreen(p0);
233 scrollDx(-p1.x()+p.x());
234 scrollDy(-p1.y()+p.y());
235 setUpdatesEnabled(true);
236}
237
238void KivioCanvas::zoomOut(const TQPoint &p)
239{
240 setUpdatesEnabled(false);
241 KoPoint p0 = mapFromScreen(p);
242 int newZoom = m_pView->zoomHandler()->zoom() - 25;
243
244 if(newZoom > 0) {
245 m_pView->viewZoom(newZoom);
246 TQPoint p1 = mapToScreen(p0);
247 scrollDx(-p1.x()+p.x());
248 scrollDy(-p1.y()+p.y());
249 }
250 setUpdatesEnabled(true);
251}
252
253void KivioCanvas::paintEvent( TQPaintEvent* ev )
254{
255 if ( m_pDoc->isLoading() || !activePage() )
256 return;
257
258 KivioPage* page = activePage();
259
260 TQPainter painter;
261 painter.begin(m_buffer);
262
263 KoPageLayout pl = page->paperLayout();
264 int pw = m_pView->zoomHandler()->zoomItX(pl.ptWidth);
265 int ph = m_pView->zoomHandler()->zoomItY(pl.ptHeight);
266 TQRect fillRect(0, 0, pw, ph);
267 TQRect paintRect = ev->rect();
268 TQRegion grayRegion(paintRect);
269 grayRegion.translate(m_iXOffset - m_pageOffsetX, m_iYOffset - m_pageOffsetY);
270 grayRegion -= fillRect;
271 grayRegion.translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
272
273 // This code comes from KPresenter's kprcanvas.cpp
274 // Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
275 painter.save();
276 painter.setClipRegion(grayRegion, TQPainter::CoordPainter);
277 painter.setPen(TQt::NoPen);
278 painter.fillRect(grayRegion.boundingRect(), TDEApplication::palette().active().brush(TQColorGroup::Mid));
279 painter.restore();
280 // end of copy...
281
282 painter.translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset +m_pageOffsetY);
283 painter.fillRect(fillRect, white);
284
285 // Draw Grid
286 if(m_pDoc->grid().isShow) {
287 KoPoint topLeft(0, 0);
288 KoPoint bottomRight(pl.ptWidth, pl.ptHeight);
289 TQPoint zoomedTL = m_pView->zoomHandler()->zoomPoint(topLeft);
290 TQPoint zoomedBR = m_pView->zoomHandler()->zoomPoint(bottomRight);
291
292 KoSize freq = m_pDoc->grid().freq;
293
294 painter.setPen(m_pDoc->grid().color);
295
296 double x = tqRound(topLeft.x() / freq.width()) * freq.width();
297 int zoomed = 0;
298
299 while(x <= bottomRight.x()) {
300 zoomed = m_pView->zoomHandler()->zoomItX(x);
301 painter.drawLine(zoomed, zoomedTL.y(), zoomed, zoomedBR.y());
302 x += freq.width();
303 }
304
305 double y = tqRound(topLeft.y() / freq.height()) * freq.height();
306
307 while(y <= bottomRight.y()) {
308 zoomed = m_pView->zoomHandler()->zoomItY(y);
309 painter.drawLine(zoomedTL.x(), zoomed, zoomedBR.x(), zoomed);
310 y += freq.height();
311 }
312 }
313
314 if(m_pView->isShowPageMargins()) {
315 int ml = m_pView->zoomHandler()->zoomItX(pl.ptLeft);
316 int mt = m_pView->zoomHandler()->zoomItY(pl.ptTop);
317 int mr = m_pView->zoomHandler()->zoomItX(pl.ptRight);
318 int mb = m_pView->zoomHandler()->zoomItY(pl.ptBottom);
319
320 painter.save();
321 painter.setPen(TQPen("#C7C7C7",1,SolidLine));
322 painter.drawRect(ml,mt,pw-ml-mr,ph-mt-mb);
323 painter.restore();
324 }
325
326 // Draw page borders
327 painter.setPen(black);
328 painter.fillRect(pw, 3, 5, ph, gray);
329 painter.fillRect(3, ph, pw, 3, gray);
330 painter.drawRect(0, 0, pw, ph);
331
332 // Draw content
333 KivioScreenPainter kpainter;
334 kpainter.start(m_buffer);
335 kpainter.translateBy(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
336 m_pDoc->paintContent(kpainter, paintRect, false, page, TQPoint(0, 0), m_pView->zoomHandler(), showConnectorTargets(), true);
337 kpainter.stop();
338
339 if(m_pView->isShowGuides()) {
340 m_guides.paintGuides(painter);
341 }
342
343 painter.end();
344
345 bitBlt(this, paintRect.left(), paintRect.top(), m_buffer,
346 paintRect.left(), paintRect.top(), paintRect.width(), paintRect.height());
347}
348
349void KivioCanvas::updateScrollBars()
350{
351 if(!activePage()) {
352 return;
353 }
354
355 KoPageLayout pl = activePage()->paperLayout();
356 int pw = m_pView->zoomHandler()->zoomItX(pl.ptWidth);
357 int ph = m_pView->zoomHandler()->zoomItY(pl.ptHeight);
358
359 m_pScrollX = TQMAX(pw - width(), 0);
360 m_pScrollY = TQMAX(ph - height(), 0);
361
362 m_pHorzScrollBar->setRange(0, m_pScrollX);
363 if ( m_pHorzScrollBar->value() > m_pHorzScrollBar->maxValue() ||
364 m_pHorzScrollBar->value() < m_pHorzScrollBar->minValue() )
365 {
366 m_pHorzScrollBar->setValue(0);
367 }
368
369 m_pVertScrollBar->setRange(0, m_pScrollY);
370 if ( m_pVertScrollBar->value() > m_pVertScrollBar->maxValue() ||
371 m_pVertScrollBar->value() < m_pVertScrollBar->minValue() )
372 {
373 m_pVertScrollBar->setValue(0);
374 }
375
376 m_pVertScrollBar->setPageStep( height() );
377 m_pHorzScrollBar->setPageStep( width() );
378
379 if(pw >= width()) {
380 m_pageOffsetX = 0;
381 } else {
382 m_pageOffsetX = (width() - pw) / 2;
383 }
384
385 if(ph >= height()) {
386 m_pageOffsetY = 0;
387 } else {
388 m_pageOffsetY = (height() - ph) / 2;
389 }
390}
391
392TQSize KivioCanvas::actualSize() const
393{
394 return TQSize(m_pScrollX, m_pScrollY);
395}
396
397bool KivioCanvas::event( TQEvent* e )
398{
399 bool f = TQWidget::event(e);
400
401 if (m_pView->pluginManager() && delegateThisEvent) {
402 f = m_pView->pluginManager()->delegateEvent(e);
403 }
404
405 delegateThisEvent = true;
406 return f;
407}
408
409void KivioCanvas::enterEvent( TQEvent* )
410{
411}
412
413void KivioCanvas::leaveEvent( TQEvent* )
414{
415 m_pView->setMousePos(-1, -1);
416}
417
418void KivioCanvas::mousePressEvent(TQMouseEvent* e)
419{
420 if(!m_pDoc->isReadWrite())
421 return;
422
423 if(m_pasteMoving) {
424 endPasteMoving();
425 return;
426 }
427
428 Kivio::PluginManager* pluginManager = view()->pluginManager();
429
430 if(m_pView->isShowGuides() && (!pluginManager || (pluginManager->defaultTool() == pluginManager->activeTool()))) {
431 if(m_guides.mousePressEvent(e)) {
432 delegateThisEvent = false;
433 return;
434 }
435 }
436}
437
438void KivioCanvas::mouseReleaseEvent(TQMouseEvent* e)
439{
440 if(!m_pDoc->isReadWrite())
441 return;
442
443 Kivio::PluginManager* pluginManager = view()->pluginManager();
444
445 if(view()->isShowGuides() && (!pluginManager || (pluginManager->defaultTool() == pluginManager->activeTool()))) {
446 if(m_guides.mouseReleaseEvent(e)) {
447 delegateThisEvent = false;
448 return;
449 }
450 }
451}
452
453void KivioCanvas::mouseMoveEvent(TQMouseEvent* e)
454{
455 if(!m_pDoc->isReadWrite())
456 return;
457
458 if(m_pasteMoving) {
459 continuePasteMoving(e->pos());
460 } else {
461 Kivio::PluginManager* pluginManager = view()->pluginManager();
462
463 if(m_pView->isShowGuides() && (!pluginManager || (pluginManager->defaultTool() == pluginManager->activeTool()))) {
464 delegateThisEvent = !m_guides.mouseMoveEvent(e);
465 }
466 }
467
468 lastPoint = e->pos();
469 view()->setMousePos(lastPoint.x(), lastPoint.y());
470}
471
472TQPoint KivioCanvas::mapToScreen(const KoPoint& pos)
473{
474 TQPoint p;
475 int x = m_pView->zoomHandler()->zoomItX(pos.x());
476 int y = m_pView->zoomHandler()->zoomItY(pos.y());
477
478 p.setX( x - m_iXOffset + m_pageOffsetX);
479 p.setY( y - m_iYOffset + m_pageOffsetY);
480
481 return p;
482}
483
484KoPoint KivioCanvas::mapFromScreen( const TQPoint & pos )
485{
486 int x = pos.x() + m_iXOffset - m_pageOffsetX;
487 int y = pos.y() + m_iYOffset - m_pageOffsetY;
488 double xf = m_pView->zoomHandler()->unzoomItX(x);
489 double yf = m_pView->zoomHandler()->unzoomItY(y);
490
491 KoPoint p(xf, yf);
492 return p;
493}
494
495void KivioCanvas::startRectDraw( const TQPoint &p, RectType )
496{
497 currRect = TQRect( 0, 0, -1, -1 );
498
499 TQPoint pos( p );
500 oldRectValid = false;
501 beginUnclippedPainter();
502 rectAnchor = pos;
503 currRect = TQRect( rectAnchor, TQPoint(0,0) );
504
505 m_borderTimer->start(100);
506}
507
508void KivioCanvas::continueRectDraw( const TQPoint &p, RectType )
509{
510 TQPoint pos = p;
511 TQPoint p2 = pos;
512 TQRect r( rectAnchor, p2 );
513 r = r.normalize();
514
515 if ( oldRectValid )
516 unclippedPainter->drawRect( currRect );
517 if ( r.width() > 1 || r.height() > 1 ) {
518 oldRectValid = true;
519 currRect = r;
520 unclippedPainter->drawRect( currRect );
521 } else {
522 oldRectValid = false;
523 }
524}
525
526void KivioCanvas::endRectDraw()
527{
528 m_borderTimer->stop();
529
530 if ( !unclippedPainter )
531 return;
532
533 if ( oldRectValid )
534 unclippedPainter->drawRect( currRect );
535
536 endUnclippedPainter();
537}
538
547void KivioCanvas::startSpawnerDragDraw( const TQPoint &p )
548{
549 currRect = TQRect( 0, 0, -1, -1 );
550
551 KivioStencilSpawner *pSpawner = KivioIconView::curDragSpawner();
552 if( !pSpawner )
553 return;
554
555 // If we for some reason didn't delete an old drag stencil,
556 // do so now.
557 if( m_pDragStencil )
558 {
559 kdDebug(43000) << "KivioCanvas::startSpawnerDragDraw() - m_pDragStencil still exists. BUG!" << endl;
560 delete m_pDragStencil;
561 m_pDragStencil = 0L;
562 }
563
564 // Map the point from screenspace to page space
565 KoPoint qp = mapFromScreen( p );
566 qp = snapToGrid(qp);
567
568 // Allocate a new stencil for dragging around
569 m_pDragStencil = pSpawner->newStencil();
570 m_pDragStencil->setPosition( qp.x(), qp.y() );
571
572 // Invalidate the rectangle
573 oldRectValid = true;
574
575 // Create a new painter object
576 beginUnclippedSpawnerPainter();
577
578 // Translate the painter so that 0,0 means where the page starts on the canvas
579 unclippedSpawnerPainter->painter()->save();
580 unclippedSpawnerPainter->painter()->translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
581
582 // Assign the painter object to the intra-stencil data object, as well
583 // as the zoom factor
584 m_dragStencilData.painter = unclippedSpawnerPainter;
585 m_dragStencilData.zoomHandler = m_pView->zoomHandler();
586
587 // Draw the outline of the stencil
588 m_pDragStencil->paintOutline( &m_dragStencilData );
589
590 unclippedSpawnerPainter->painter()->restore();
591}
592
596void KivioCanvas::continueSpawnerDragDraw( const TQPoint &p )
597{
598 bool snappedX, snappedY;
599
600 // Translate the painter so that 0,0 means where the page starts on the canvas
601 unclippedSpawnerPainter->painter()->save();
602 unclippedSpawnerPainter->painter()->translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
603
604 // Undraw the old outline
605 if( oldRectValid )
606 {
607 m_pDragStencil->paintOutline( &m_dragStencilData );
608 }
609
610 // Map the new point from screenspace to page space
611 KoPoint orig = mapFromScreen(p);
612 KoPoint qp = snapToGrid( orig );
613
614 // First snap to screen
615 qp = snapToGrid(qp);
616 m_pDragStencil->setPosition( qp.x(), qp.y() );
617
618 // Now snap to the guides
619 qp.setCoords(orig.x() + m_pDragStencil->w(), orig.y() + m_pDragStencil->h());
620 qp = snapToGuides(qp, snappedX, snappedY);
621
622 if(snappedX) {
623 m_pDragStencil->setX(qp.x() - m_pDragStencil->w());
624 }
625
626 if(snappedY) {
627 m_pDragStencil->setY(qp.y() - m_pDragStencil->h());
628 }
629
630 qp.setCoords(orig.x() + (m_pDragStencil->w() / 2.0), orig.y() + (m_pDragStencil->h() / 2.0));
631 qp = snapToGuides(qp, snappedX, snappedY);
632
633 if(snappedX) {
634 m_pDragStencil->setX(qp.x() - (m_pDragStencil->w() / 2.0));
635 }
636
637 if(snappedY) {
638 m_pDragStencil->setY(qp.y() - (m_pDragStencil->h() / 2.0));
639 }
640
641 qp.setCoords(orig.x(), orig.y());
642 qp = snapToGuides(qp, snappedX, snappedY);
643
644 if(snappedX) {
645 m_pDragStencil->setX(qp.x());
646 }
647
648 if(snappedY) {
649 m_pDragStencil->setY(qp.y());
650 }
651
652 // Redraw the new outline
653 oldRectValid = true;
654 m_pDragStencil->paintOutline( &m_dragStencilData );
655 unclippedSpawnerPainter->painter()->restore();
656
657}
658
659
663void KivioCanvas::endSpawnerDragDraw()
664{
665 // Avoid the noid
666 if ( !unclippedSpawnerPainter )
667 return;
668
669 // If we have a valid old drawing spot, undraw it
670 if ( oldRectValid )
671 {
672 unclippedSpawnerPainter->painter()->save();
673 unclippedSpawnerPainter->painter()->translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
674 m_pDragStencil->paintOutline( &m_dragStencilData );
675 unclippedSpawnerPainter->painter()->restore();
676 }
677
678 // Smack the painter around a bit
679 endUnclippedSpawnerPainter();
680
681 // If we have a stencil we were dragging around, delete it.
682 if( m_pDragStencil )
683 {
684 delete m_pDragStencil;
685 m_pDragStencil = 0L;
686 }
687
688 setFocus();
689}
690
691
695void KivioCanvas::beginUnclippedSpawnerPainter()
696{
697 // End any previous attempts
698 endUnclippedSpawnerPainter();
699
700 // I have no idea what this does. Max?
701 bool unclipped = testWFlags( WPaintUnclipped );
702 setWFlags( WPaintUnclipped );
703
704
705 // Allocate a new painter object for use in drawing
706 unclippedSpawnerPainter = new KivioScreenPainter();
707
708 // Tell it to start (allocates a Qpainter object)
709 unclippedSpawnerPainter->start(this);
710
711 // Uhhhhh??
712 if( !unclipped )
713 clearWFlags( WPaintUnclipped );
714
715
716 // Make sure it's doing NOT drawing.
717 unclippedSpawnerPainter->painter()->setRasterOp( NotROP );
718 unclippedSpawnerPainter->painter()->setPen( TQColor(0,0,250) );
719
720}
721
722
726void KivioCanvas::endUnclippedSpawnerPainter()
727{
728 if( unclippedSpawnerPainter )
729 {
730 unclippedSpawnerPainter->stop();
731 delete unclippedSpawnerPainter;
732 unclippedSpawnerPainter = 0L;
733 }
734}
735
736void KivioCanvas::beginUnclippedPainter()
737{
738 endUnclippedPainter();
739 bool unclipped = testWFlags( WPaintUnclipped );
740
741 setWFlags( WPaintUnclipped );
742 unclippedPainter = new TQPainter;
743 unclippedPainter->begin( this );
744
745 if ( !unclipped )
746 clearWFlags( WPaintUnclipped );
747
748 unclippedPainter->setRasterOp( NotROP );
749 unclippedPainter->setPen( TQPen(blue,1,DotLine) );
750}
751
752void KivioCanvas::endUnclippedPainter()
753{
754 if ( unclippedPainter )
755 {
756 unclippedPainter->end();
757 delete unclippedPainter;
758 unclippedPainter = 0;
759 }
760}
761
762void KivioCanvas::borderTimerTimeout()
763{
764 TQPoint p = mapFromGlobal(TQCursor::pos());
765 int dx = 0;
766 int dy = 0;
767 int d = 10;
768
769 TQRect r(currRect);
770 int vpos = m_pVertScrollBar->value();
771 int vmax = m_pVertScrollBar->maxValue();
772 int vmin = m_pVertScrollBar->minValue();
773
774 int hpos = m_pHorzScrollBar->value();
775 int hmax = m_pHorzScrollBar->maxValue();
776 int hmin = m_pHorzScrollBar->minValue();
777
778 if ( p.x() < 0 && hpos > hmin ) {
779 dx = TQMIN(d,hpos-hmin);
780 r.setRight(r.right()+dx);
781 rectAnchor.setX(rectAnchor.x()+dx);
782 }
783
784 if ( p.y() < 0 && vpos > vmin ) {
785 dy = TQMIN(d,vpos-vmin);
786 r.setBottom(r.bottom()+dy);
787 rectAnchor.setY(rectAnchor.y()+dy);
788 }
789
790 if ( p.x() > width() && hpos < hmax ) {
791 dx = -TQMIN(d,hmax-hpos);
792 r.setLeft(r.left()+dx);
793 rectAnchor.setX(rectAnchor.x()+dx);
794 }
795
796 if ( p.y() > height() && vpos < vmax ) {
797 dy = -TQMIN(d,vmax-vpos);
798 r.setTop(r.top()+dy);
799 rectAnchor.setY(rectAnchor.y()+dy);
800 }
801
802 if ( dx != 0 || dy != 0 ) {
803 unclippedPainter->drawRect( currRect );
804 scrollDx(dx);
805 scrollDy(dy);
806 unclippedPainter->drawRect( r );
807 currRect = r;
808 }
809}
810
811
822void KivioCanvas::dragEnterEvent( TQDragEnterEvent *e )
823{
824 if( e->provides("kivio/stencilSpawner") )
825 {
826 e->accept();
827 startSpawnerDragDraw( e->pos() );
828 activePage()->unselectAllStencils();
829 updateAutoGuideLines();
830 }
831}
832
833
834
844void KivioCanvas::dragMoveEvent( TQDragMoveEvent *e )
845{
846 // Does it speak our language?
847 if( e->provides("kivio/stencilSpawner") )
848 {
849 e->accept();
850 continueSpawnerDragDraw( e->pos() );
851 }
852}
853
854
865void KivioCanvas::dropEvent( TQDropEvent *e )
866{
867 // Terminate the drawing object
868 endSpawnerDragDraw();
869
870 // Get a pointer to the currently dragged KivioStencilSpawner object
871 KivioStencilSpawner *pSpawner = KivioIconView::curDragSpawner();
872
873 if( !pSpawner )
874 return;
875
876 TQPoint pos = e->pos();
877 KoPoint pagePoint = snapToGrid(mapFromScreen( pos ));
878 view()->addStencilFromSpawner(pSpawner, pagePoint.x(), pagePoint.y());
879
880 // FIXME Select the "selection tool" in case it's not done
881}
882
883
892void KivioCanvas::dragLeaveEvent( TQDragLeaveEvent * )
893{
894 endSpawnerDragDraw();
895}
896
897
898
899void KivioCanvas::drawSelectedStencilsXOR()
900{
901 // This should never happen, but check just in case
902 if ( !unclippedSpawnerPainter )
903 return;
904
905 // Translate the painter so that 0,0 means where the page starts on the canvas
906 unclippedSpawnerPainter->painter()->save();
907 unclippedSpawnerPainter->painter()->translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
908
909 // Assign the painter object to the intra-stencil data object, as well
910 // as the zoom factor
911 m_dragStencilData.painter = unclippedSpawnerPainter;
912 m_dragStencilData.zoomHandler = m_pView->zoomHandler();
913
914 KivioStencil *pStencil = activePage()->selectedStencils()->first();
915 while( pStencil )
916 {
917 pStencil->paintOutline( &m_dragStencilData );
918 pStencil->paintSelectionHandles( &m_dragStencilData );
919
920 pStencil = activePage()->selectedStencils()->next();
921 }
922
923 unclippedSpawnerPainter->painter()->restore();
924}
925
926void KivioCanvas::drawStencilXOR( KivioStencil *pStencil )
927{
928 // This should never happen, but check just in case
929 if ( !unclippedSpawnerPainter )
930 return;
931
932 // Translate the painter so that 0,0 means where the page starts on the canvas
933 unclippedSpawnerPainter->painter()->save();
934 unclippedSpawnerPainter->painter()->translate(-m_iXOffset + m_pageOffsetX, -m_iYOffset + m_pageOffsetY);
935
936 // Assign the painter object to the intra-stencil data object, as well
937 // as the zoom factor
938 m_dragStencilData.painter = unclippedSpawnerPainter;
939 m_dragStencilData.zoomHandler = m_pView->zoomHandler();
940
941 pStencil->paintOutline( &m_dragStencilData );
942 pStencil->paintSelectionHandles( &m_dragStencilData );
943
944 unclippedSpawnerPainter->painter()->restore();
945}
946
947void KivioCanvas::keyPressEvent( TQKeyEvent *e )
948{
949 if(view()->isShowGuides() && m_guides.keyPressEvent(e)) {
950 return;
951 }
952}
953
954KoPoint KivioCanvas::snapToGridAndGuides(const KoPoint& point)
955{
956 KoPoint p = point;
957
958 p = snapToGrid(p);
959
960 bool snappedX, snappedY;
961 KoPoint guidePoint = snapToGuides(point, snappedX, snappedY);
962
963 if(snappedX) {
964 p.setX(guidePoint.x());
965 }
966
967 if(snappedY) {
968 p.setY(guidePoint.y());
969 }
970
971 return p;
972}
973
974KoPoint KivioCanvas::snapToGrid(const KoPoint& point)
975{
976 if (!m_pDoc->grid().isSnap)
977 return point;
978
979 KoPoint p = point;
980
981 KoSize dist = m_pDoc->grid().snap;
982 KoSize freq = m_pDoc->grid().freq;
983
984 double dx = tqRound(p.x() / freq.width());
985 double dy = tqRound(p.y() / freq.height());
986
987 double distx = TQABS(p.x() - (freq.width() * dx));
988 double disty = TQABS(p.y() - (freq.height() * dy));
989
990 if(distx < dist.width()) {
991 p.setX(freq.width() * dx);
992 }
993
994 if(disty < dist.height()) {
995 p.setY(freq.height() * dy);
996 }
997
998 return p;
999}
1000
1001KoPoint KivioCanvas::snapToGuides(const KoPoint& point, bool &snappedX, bool &snappedY)
1002{
1003 snappedX = false;
1004 snappedY = false;
1005 KoPoint p = point;
1006
1007 if (m_pView->isSnapGuides())
1008 {
1009 KoGuides::SnapStatus status = KoGuides::SNAP_NONE;
1010 KoPoint diff;
1011 m_guides.snapToGuideLines(p, 4, status, diff);
1012 p += diff;
1013
1014 if(status & KoGuides::SNAP_HORIZ) {
1015 snappedY = true;
1016 }
1017 if(status & KoGuides::SNAP_VERT) {
1018 snappedX = true;
1019 }
1020
1021 m_guides.repaintSnapping(p, status);
1022 }
1023
1024 return p;
1025}
1026
1027void KivioCanvas::setViewCenterPoint(const KoPoint &p)
1028{
1029 setUpdatesEnabled(false);
1030
1031 KoRect va = visibleArea();
1032
1033 double x = TQMAX(0.0, p.x() - (va.width() / 2.0));
1034 double y = TQMAX(0.0, p.y() - (va.height() / 2.0));
1035
1036 m_pVertScrollBar->setValue(m_pView->zoomHandler()->zoomItY(y));
1037 m_pHorzScrollBar->setValue(m_pView->zoomHandler()->zoomItX(x));
1038
1039 setUpdatesEnabled(true);
1040}
1041
1042KoRect KivioCanvas::visibleArea()
1043{
1044 KoPoint p0 = mapFromScreen(TQPoint(0,0));
1045 KoPoint p1 = mapFromScreen(TQPoint(width()-1,height()-1));
1046
1047 return KoRect(p0.x(), p0.y(), p1.x() - p0.x(), p1.y() - p0.y());
1048}
1049
1050void KivioCanvas::setVisibleArea(KoRect r, int margin)
1051{
1052 setUpdatesEnabled(false);
1053 KoZoomHandler zoom;
1054 zoom.setZoomAndResolution(100, KoGlobal::dpiX(),
1055 KoGlobal::dpiY());
1056
1057 float cw = width() - 2 * margin;
1058 float ch = height() - 2 * margin;
1059
1060 float zw = cw / (float)zoom.zoomItX(r.width());
1061 float zh = ch / (float)zoom.zoomItY(r.height());
1062 float z = TQMIN(zw, zh);
1063
1064 m_pView->viewZoom(tqRound(z * 100));
1065
1066 KoPoint c = r.center();
1067
1068 setViewCenterPoint(KoPoint(c.x(), c.y()));
1069 setUpdatesEnabled(true);
1070}
1071
1072void KivioCanvas::setVisibleAreaByWidth(KoRect r, int margin)
1073{
1074 setUpdatesEnabled(false);
1075 KoZoomHandler zoom;
1076 zoom.setZoomAndResolution(100, KoGlobal::dpiX(),
1077 KoGlobal::dpiY());
1078
1079 float cw = width() - 2*margin;
1080 float z = cw / (float)zoom.zoomItX(r.width());
1081
1082 m_pView->viewZoom(tqRound(z * 100));
1083
1084 KoPoint c = r.center();
1085
1086 setViewCenterPoint(KoPoint(c.x(), c.y()));
1087 setUpdatesEnabled(true);
1088}
1089
1090void KivioCanvas::setVisibleAreaByHeight(KoRect r, int margin)
1091{
1092 setUpdatesEnabled(false);
1093 KoZoomHandler zoom;
1094 zoom.setZoomAndResolution(100, KoGlobal::dpiX(),
1095 KoGlobal::dpiY());
1096
1097 float ch = height() - 2*margin;
1098 float z = ch / (float)zoom.zoomItY(r.height());
1099
1100 m_pView->viewZoom(tqRound(z * 100));
1101
1102 KoPoint c = r.center();
1103
1104 setViewCenterPoint(KoPoint(c.x(), c.y()));
1105 setUpdatesEnabled(true);
1106}
1107
1108void KivioCanvas::startPasteMoving()
1109{
1110 setEnabled(false);
1111 KoPoint p = activePage()->getRectForAllSelectedStencils().center();
1112 m_origPoint.setCoords(p.x(), p.y());
1113
1114 // Create a new painter object
1115 beginUnclippedSpawnerPainter();
1116 drawSelectedStencilsXOR();
1117
1118 // Build the list of old geometry
1119 KoRect *pData;
1120 m_lstOldGeometry.clear();
1121 KivioStencil* pStencil = activePage()->selectedStencils()->first();
1122
1123 while( pStencil )
1124 {
1125 pData = new KoRect;
1126 *pData = pStencil->rect();
1127 m_lstOldGeometry.append(pData);
1128
1129 pStencil = activePage()->selectedStencils()->next();
1130 }
1131
1132 continuePasteMoving(lastPoint);
1133 m_pasteMoving = true;
1134 setEnabled(true);
1135}
1136
1137void KivioCanvas::continuePasteMoving(const TQPoint &pos)
1138{
1139 KoPoint pagePoint = mapFromScreen( pos );
1140
1141 double dx = pagePoint.x() - m_origPoint.x();
1142 double dy = pagePoint.y() - m_origPoint.y();
1143
1144 bool snappedX;
1145 bool snappedY;
1146
1147 double newX, newY;
1148
1149 // Undraw the old stencils
1150 drawSelectedStencilsXOR();
1151
1152 // Translate to the new position
1153 KoPoint p;
1154 KoRect selectedRect = activePage()->getRectForAllSelectedStencils();
1155
1156 newX = selectedRect.x() + dx;
1157 newY = selectedRect.y() + dy;
1158
1159 // First attempt a snap-to-grid
1160 p.setCoords(newX, newY);
1161 p = snapToGrid(p);
1162
1163 newX = p.x();
1164 newY = p.y();
1165
1166 // Now the guides override the grid so we attempt to snap to them
1167 p.setCoords(selectedRect.x() + dx + selectedRect.width(), selectedRect.y() + dy + selectedRect.height());
1168 p = snapToGuides(p, snappedX, snappedY);
1169
1170 if(snappedX) {
1171 newX = p.x() - selectedRect.width();
1172 }
1173
1174 if(snappedY) {
1175 newY = p.y() - selectedRect.height();
1176 }
1177
1178 p.setCoords(selectedRect.x() + dx + (selectedRect.width() / 2.0), selectedRect.y() + dy + (selectedRect.height() / 2.0));
1179 p = snapToGuides(p, snappedX, snappedY);
1180
1181 if(snappedX) {
1182 newX = p.x() - (selectedRect.width() / 2.0);
1183 }
1184
1185 if(snappedY) {
1186 newY = p.y() - (selectedRect.height() / 2.0);
1187 }
1188
1189 p.setCoords(selectedRect.x() + dx, selectedRect.y() + dy);
1190 p = snapToGuides(p, snappedX, snappedY);
1191
1192 if(snappedX) {
1193 newX = p.x();
1194 }
1195
1196 if(snappedY) {
1197 newY = p.y();
1198 }
1199
1200 dx = newX - selectedRect.x();
1201 dy = newY - selectedRect.y();
1202
1203 // Translate to the new position
1204 KivioStencil *pStencil = activePage()->selectedStencils()->first();
1205 KoRect* pData = m_lstOldGeometry.first();
1206 // bool move = true;
1207
1208 while( pStencil && pData )
1209 {
1210 newX = pData->x() + dx;
1211 newY = pData->y() + dy;
1212
1213 if( pStencil->protection()->at( kpX ) == false ) {
1214 pStencil->setX(newX);
1215 }
1216 if( pStencil->protection()->at( kpY ) == false ) {
1217 pStencil->setY(newY);
1218 }
1219
1220 pData = m_lstOldGeometry.next();
1221 pStencil = activePage()->selectedStencils()->next();
1222 }
1223
1224 // Draw the stencils
1225 drawSelectedStencilsXOR();
1226 m_pView->updateToolBars();
1227}
1228
1229void KivioCanvas::endPasteMoving()
1230{
1231 KivioStencil *pStencil = activePage()->selectedStencils()->first();
1232 KoRect *pData = m_lstOldGeometry.first();
1233
1234 while( pStencil && pData )
1235 {
1236 if(pStencil->type() == kstConnector) {
1237 pStencil->searchForConnections(m_pView->activePage(), m_pView->zoomHandler()->unzoomItY(4));
1238 }
1239
1240 pData = m_lstOldGeometry.next();
1241 pStencil = activePage()->selectedStencils()->next();
1242 }
1243
1244 drawSelectedStencilsXOR();
1245
1246 endUnclippedSpawnerPainter();
1247
1248 // Clear the list of old geometry
1249 m_lstOldGeometry.clear();
1250 m_pasteMoving = false;
1251}
1252
1253void KivioCanvas::updateAutoGuideLines()
1254{
1255 TQValueList<double> hGuideLines;
1256 TQValueList<double> vGuideLines;
1257 TQPtrList<KivioLayer> layerList = *(activePage()->layers());
1258 TQPtrListIterator<KivioLayer> layerIt(layerList);
1259 KivioLayer* layer = 0;
1260 TQPtrList<KivioStencil> stencilList;
1261 TQPtrListIterator<KivioStencil> stencilIt(stencilList);
1262 KivioStencil* stencil = 0;
1263
1264 while((layer = layerIt.current()) != 0) {
1265 ++layerIt;
1266
1267 if(layer->visible()) {
1268 stencilList = *(layer->stencilList());
1269 stencilIt.toFirst();
1270
1271 while((stencil = stencilIt.current()) != 0) {
1272 ++stencilIt;
1273
1274 if(!stencil->isSelected()) {
1275 hGuideLines << stencil->y() << (stencil->y() + (stencil->h() / 2.0)) << (stencil->y() + stencil->h());
1276 vGuideLines << stencil->x() << (stencil->x() + (stencil->w() / 2.0)) << (stencil->x() + stencil->w());
1277 }
1278 }
1279 }
1280 }
1281
1282 KoPageLayout pl = activePage()->paperLayout();
1283
1284 // Add the middle of the page and the margins
1285 hGuideLines << (pl.ptHeight / 2.0) << pl.ptTop << pl.ptBottom;
1286 vGuideLines << (pl.ptWidth / 2.0) << pl.ptLeft << pl.ptRight;
1287
1288 guideLines().setAutoGuideLines(hGuideLines, vGuideLines);
1289}
1290
1291#include "kivio_canvas.moc"
This class manages the plugins.
Kivio::MouseTool * activeTool()
Returns the tool that is in use.
Kivio::MouseTool * defaultTool()
Returns the default tool.