tool_select.cpp
1/*
2 * Kivio - Visual Modelling and Flowcharting
3 * Copyright (C) 2000-2003 theKompany.com & Dave Marotti,
4 * Peter Simonsson
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20/**************************************************************************************
21 *
22 * The code for dragging and resizing stencils is all contained in this class. KivioCanvas
23 * is used only for drawing since it's a canvas.
24 *
25 */
26
27#include "tool_select.h"
28
29#include "kivio_view.h"
30#include "kivio_doc.h"
31#include "kivio_canvas.h"
32#include "kivio_page.h"
33
34#include "kivio_custom_drag_data.h"
35#include "kivio_layer.h"
36#include "kivio_stencil.h"
37
38#include <tdeactionclasses.h>
39#include <tdepopupmenu.h>
40#include <kdebug.h>
41#include <KoZoomHandler.h>
42#include <KoPoint.h>
43#include <tdelocale.h>
44#include <KoGuides.h>
45#include "kivio_command.h"
46
47#include <tqwmatrix.h>
48
49#include "kivio_pluginmanager.h"
50
51SelectTool::SelectTool( KivioView* parent ) : Kivio::MouseTool(parent, "Selection Mouse Tool")
52{
53 view()->pluginManager()->setDefaultTool(this);
54
55 TDEShortcut selectShortCut(Key_Space);
56 selectShortCut.setSeq(1, TQKeySequence(Key_Escape));
57 m_selectAction = new TDERadioAction(i18n("&Select"), "select", selectShortCut, actionCollection(), "select");
58 connect(m_selectAction, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(setActivated(bool)));
59
60 m_textEditAction = new TDEAction(i18n("&Edit Text..."), "text", Key_F2,
61 this, TQ_SLOT(editStencilText()), actionCollection(), "editText");
62 (void) new TDEAction(i18n("Format &Stencils && Connectors..."), 0, 0, view(), TQ_SLOT(stencilFormat()),
63 actionCollection(), "formatStencil");
64 m_arrowHeadAction = new TDEAction(i18n("Format &Arrowheads..."), 0, 0, view(), TQ_SLOT(arrowHeadFormat()),
65 actionCollection(), "formatConnector");
66
67 m_mode = stmNone;
68 m_pResizingStencil = NULL;
69 m_pCustomDraggingStencil = NULL;
70
71 m_lstOldGeometry.setAutoDelete(true);
72
73 m_customDragID = 0;
74}
75
76SelectTool::~SelectTool()
77{
78}
79
80
87bool SelectTool::processEvent(TQEvent* e)
88{
89 KivioCanvas* canvas = view()->canvasWidget();
90 TQMouseEvent *m;
91
92 switch (e->type())
93 {
94 case TQEvent::MouseButtonDblClick:
95 m = (TQMouseEvent *)e;
96
97 if( m->button() == TQt::LeftButton ) {
98 leftDoubleClick(m->pos());
99 }
100
101 canvas->setFocus();
102 return true;
103 break;
104
105 case TQEvent::MouseButtonPress:
106 m = (TQMouseEvent *)e;
107
108 if( m->button() == TQt::RightButton ) {
109 showPopupMenu(m->globalPos());
110 } else if( m->button() == TQt::LeftButton ) {
111 if(m->state() & ControlButton) {
112 m_controlKey = true;
113 } else {
114 m_controlKey = false;
115 }
116
117 mousePress( m->pos() );
118 }
119
120 canvas->setFocus();
121 return true;
122 break;
123
124 case TQEvent::MouseButtonRelease:
125 mouseRelease( ((TQMouseEvent *)e)->pos() );
126 canvas->setFocus();
127 return true;
128 break;
129
130 case TQEvent::MouseMove:
131 mouseMove( static_cast<TQMouseEvent*>(e));
132 return true;
133 break;
134
135 case TQEvent::KeyPress:
136 if((static_cast<TQKeyEvent*>(e)->key() >= Key_Left) && (static_cast<TQKeyEvent*>(e)->key() <= Key_Down)) {
137 keyPress(static_cast<TQKeyEvent*>(e));
138 return true;
139 }
140 break;
141
142 default:
143 break;
144 }
145
146 return false;
147}
148
149void SelectTool::setActivated(bool a)
150{
151 if(a) {
152 m_selectAction->setChecked(true);
153 view()->canvasWidget()->unsetCursor();
154 m_mode = stmNone;
155 emit activated(this);
156 } else if(m_selectAction->isChecked()) {
157 m_selectAction->setChecked(false);
158 view()->canvasWidget()->activePage()->setPaintSelected(true);
159 }
160}
161
165void SelectTool::select(const TQRect &r)
166{
167 // Calculate the start and end clicks in terms of page coordinates
168 KoPoint startPoint = view()->canvasWidget()->mapFromScreen( TQPoint( r.x(), r.y() ) );
169 KoPoint releasePoint = view()->canvasWidget()->mapFromScreen( TQPoint( r.x() + r.width(), r.y() + r.height() ) );
170
171
172 double x, y, w, h;
173
174 // Calculate the x,y position of the selection box
175 x = startPoint.x() < releasePoint.x() ? startPoint.x() : releasePoint.x();
176 y = startPoint.y() < releasePoint.y() ? startPoint.y() : releasePoint.y();
177
178 // Calculate the w/h of the selection box
179 w = releasePoint.x() - startPoint.x();
180
181 if( w < 0.0 ) {
182 w *= -1.0;
183 }
184
185 h = releasePoint.y() - startPoint.y();
186
187 if( h < 0.0 ) {
188 h *= -1.0;
189 }
190
191 // Tell the page to select all stencils in this box
192 view()->activePage()->selectStencils( x, y, w, h );
193}
194
195void SelectTool::mousePress(const TQPoint &pos)
196{
197 // Last point is used for undrawing at the last position and calculating the distance the mouse has moved
198 m_lastPoint = view()->canvasWidget()->mapFromScreen(pos);
199 m_origPoint = m_lastPoint;
200
201 // Check if we nailed a custom drag point on a selected stencil
202 if( startCustomDragging(pos, true) )
203 {
204 m_mode = stmCustomDragging;
205 return;
206 }
207
208 // Check if we are resizing
209 if( startResizing(pos) )
210 {
211 m_mode = stmResizing;
212 return;
213 }
214
215
216 // Check if we nailed a custom drag point on any other stencil
217 if( startCustomDragging(pos, false) )
218 {
219 m_mode = stmCustomDragging;
220 return;
221 }
222
223 // Check if we can drag a stencil
224 if( startDragging(pos, false) )
225 {
226 m_mode = stmDragging;
227 return;
228 }
229
230 // This should always be the last 'start' call since it always returns true
231 if( startRubberBanding(pos) )
232 {
233 m_mode = stmDrawRubber;
234 return;
235 }
236}
237
238
242bool SelectTool::startRubberBanding(const TQPoint &pos)
243{
244 KivioCanvas* canvas = view()->canvasWidget();
245 // We didn't find a stencil, so unselect everything if we aren't holding the control key down
246 if( !m_controlKey )
247 canvas->activePage()->unselectAllStencils();
248
249 canvas->startRectDraw( pos, KivioCanvas::Rubber );
250 canvas->repaint();
251
252 return true;
253}
254
255
259bool SelectTool::startDragging(const TQPoint &pos, bool onlySelected)
260{
261 KivioCanvas* canvas = view()->canvasWidget();
262 KivioPage *pPage = canvas->activePage();
263 KivioStencil *pStencil;
264 int colType;
265
266 // Figure out how big 4 pixels is in terms of points
267 double threshold = view()->zoomHandler()->unzoomItY(4);
268
269 KoPoint pagePoint = canvas->mapFromScreen( pos );
270
271 pStencil = pPage->checkForStencil( &pagePoint, &colType, threshold, onlySelected );
272
273 if( !pStencil )
274 return false;
275
276 canvas->setEnabled(false);
277
278 if( pStencil->isSelected() )
279 {
280 // If we are clicking an already selected stencil, and the control
281 // key down, then unselect this stencil
282 if( m_controlKey==true ) {
283 pPage->unselectStencil( pStencil );
284 }
285
286 // Otherwise, it means we are just moving
287 }
288 else
289 {
290 // Clicking a new stencil, and the control key is not down
291 if( !m_controlKey )
292 pPage->unselectAllStencils();
293
294 pPage->selectStencil( pStencil );
295 // Update the auto guidelines
296 view()->canvasWidget()->updateAutoGuideLines();
297 }
298
299 // Create a new painter object
300 canvas->beginUnclippedSpawnerPainter();
301
302 // Build the list of old geometry
303 KivioSelectDragData *pData;
304 m_lstOldGeometry.clear();
305 pStencil = canvas->activePage()->selectedStencils()->first();
306
307 while( pStencil )
308 {
309 pData = new KivioSelectDragData;
310 pData->rect = pStencil->rect();
311 m_lstOldGeometry.append(pData);
312
313 pStencil = canvas->activePage()->selectedStencils()->next();
314 }
315
316 m_selectedRect = view()->activePage()->getRectForAllSelectedStencils();
317 changeMouseCursor(pos);
318 // Set the mode
319 m_mode = stmDragging;
320 m_firstTime = true;
321 canvas->setEnabled(true);
322 return true;
323}
324
325bool SelectTool::startCustomDragging(const TQPoint &pos, bool selectedOnly )
326{
327 KivioCanvas* canvas = view()->canvasWidget();
328 KivioPage *pPage = canvas->activePage();
329 KivioStencil *pStencil;
330 int colType;
331
332 KoPoint pagePoint = canvas->mapFromScreen( pos );
333
334 // Figure out how big 4 pixels is in terms of points
335 double threshold = view()->zoomHandler()->unzoomItY(4);
336
337 pStencil = pPage->checkForStencil( &pagePoint, &colType, threshold, selectedOnly );
338
339 if( !pStencil || colType < kctCustom ) {
340 return false;
341 }
342
343
344 if(pStencil->isSelected()) {
345 // If we are clicking an already selected stencil, and the control
346 // key down, then unselect this stencil
347 if(m_controlKey) {
348 pPage->unselectStencil(pStencil);
349 }
350 } else {
351 // Clicking a new stencil, and the control key is not down
352 if(!m_controlKey) {
353 pPage->unselectAllStencils();
354 }
355
356 pPage->selectStencil( pStencil );
357 }
358
359 m_pCustomDraggingStencil = pStencil;
360
361 // Set the mode
362 m_mode = stmCustomDragging;
363
364 m_customDragID = colType;
365 m_customDragOrigPoint = pStencil->customIDPoint(m_customDragID);
366
367 view()->canvasWidget()->setShowConnectorTargets(true);
368 view()->canvasWidget()->repaint();
369
370 // Create a new painter object
371 canvas->beginUnclippedSpawnerPainter();
372 m_firstTime = true;
373
374 return true;
375}
376
380bool SelectTool::startResizing(const TQPoint &pos)
381{
382 KivioCanvas* canvas = view()->canvasWidget();
383 KoPoint pagePoint = canvas->mapFromScreen(pos);
384 KivioSelectDragData *pData;
385
386 double x = pagePoint.x();
387 double y = pagePoint.y();
388
389 // Search selected stencils to see if we have a resizing point
390 KivioStencil *pStencil = canvas->activePage()->selectedStencils()->first();
391 while( pStencil )
392 {
393 m_resizeHandle = isOverResizeHandle(pStencil, x, y);
394 if( m_resizeHandle > 0 )
395 {
396 switch( m_resizeHandle )
397 {
398 case 1: // top left
399 m_origPoint.setCoords(pStencil->x(), pStencil->y());
400 break;
401
402 case 2:
403 m_origPoint.setCoords((pStencil->x() + pStencil->w()) / 2.0, pStencil->y());
404 break;
405
406 case 3:
407 m_origPoint.setCoords(pStencil->x() + pStencil->w(), pStencil->y());
408 break;
409
410 case 4:
411 m_origPoint.setCoords(pStencil->x() + pStencil->w(), (pStencil->y() + pStencil->h()) / 2.0);
412 break;
413
414 case 5:
415 m_origPoint.setCoords(pStencil->x() + pStencil->w(), pStencil->y() + pStencil->h());
416 break;
417
418 case 6:
419 m_origPoint.setCoords((pStencil->x() + pStencil->w()) / 2.0, pStencil->y() + pStencil->h());
420 break;
421
422 case 7:
423 m_origPoint.setCoords(pStencil->x(), pStencil->y() + pStencil->h());
424 break;
425
426 case 8:
427 m_origPoint.setCoords(pStencil->x(), (pStencil->y() + pStencil->h()) / 2.0);
428 break;
429 }
430
431 m_lstOldGeometry.clear();
432 pData = new KivioSelectDragData;
433 pData->rect = pStencil->rect();
434 m_lstOldGeometry.append(pData);
435
436 m_pResizingStencil = pStencil;
437
438 // Create a new painter object
439 canvas->beginUnclippedSpawnerPainter();
440 m_firstTime = true;
441
442 return true;
443 }
444
445 pStencil = canvas->activePage()->selectedStencils()->next();
446 }
447
448 return false;
449}
450
451
452
453void SelectTool::mouseMove(TQMouseEvent* e)
454{
455 TQPoint pos = e->pos();
456 bool ignoreGridGuides = e->state() & ShiftButton;
457
458 switch( m_mode )
459 {
460 case stmDrawRubber:
461 continueRubberBanding(pos);
462 break;
463
464 case stmDragging:
465 continueDragging(pos, ignoreGridGuides);
466 break;
467
468 case stmCustomDragging:
469 continueCustomDragging(pos);
470 break;
471
472 case stmResizing:
473 continueResizing(pos, ignoreGridGuides);
474 break;
475
476 default:
477 changeMouseCursor(pos);
478 break;
479 }
480
481 m_lastPoint = view()->canvasWidget()->mapFromScreen(pos);
482}
483
484void SelectTool::continueRubberBanding(const TQPoint &pos)
485{
486 view()->canvasWidget()->continueRectDraw( pos, KivioCanvas::Rubber );
487}
488
489
497void SelectTool::continueDragging(const TQPoint &pos, bool ignoreGridGuides)
498{
499 KivioCanvas* canvas = view()->canvasWidget();
500 KoPoint pagePoint = canvas->mapFromScreen( pos );
501
502 double dx = pagePoint.x() - m_origPoint.x();
503 double dy = pagePoint.y() - m_origPoint.y();
504
505 bool snappedX;
506 bool snappedY;
507
508 double newX, newY;
509
510 // Undraw the old stencils
511 if(!m_firstTime) {
512 canvas->drawSelectedStencilsXOR();
513 } else {
514 canvas->activePage()->setPaintSelected(false);
515 canvas->repaint();
516 m_firstTime = false;
517 }
518
519 // Translate to the new position
520 KoPoint p;
521
522 newX = m_selectedRect.x() + dx;
523 newY = m_selectedRect.y() + dy;
524
525 if(!ignoreGridGuides) {
526 // First attempt a snap-to-grid
527 p.setCoords(newX, newY);
528
529 p = canvas->snapToGrid(p);
530
531 newX = p.x();
532 newY = p.y();
533
534 // Now the guides override the grid so we attempt to snap to them
535 // The bottom
536 p.setCoords(m_selectedRect.x() + dx + m_selectedRect.width(), m_selectedRect.y() + dy + m_selectedRect.height());
537 p = canvas->snapToGuides(p, snappedX, snappedY);
538
539 if(snappedX) {
540 newX = p.x() - m_selectedRect.width();
541 }
542
543 if(snappedY) {
544 newY = p.y() - m_selectedRect.height();
545 }
546
547 // The middle
548 p.setCoords(m_selectedRect.x() + dx + (m_selectedRect.width() / 2.0),
549 m_selectedRect.y() + dy + (m_selectedRect.height() / 2.0));
550 p = canvas->snapToGuides(p, snappedX, snappedY);
551
552 if(snappedX) {
553 newX = p.x() - (m_selectedRect.width() / 2.0);
554 }
555
556 if(snappedY) {
557 newY = p.y() - (m_selectedRect.height() / 2.0);
558 }
559
560 // The top
561 p.setCoords(m_selectedRect.x() + dx, m_selectedRect.y() + dy);
562 p = canvas->snapToGuides(p, snappedX, snappedY);
563
564 if(snappedX) {
565 newX = p.x();
566 }
567
568 if(snappedY) {
569 newY = p.y();
570 }
571 }
572
573 dx = newX - m_selectedRect.x();
574 dy = newY - m_selectedRect.y();
575
576 KivioSelectDragData *pData;
577 KivioStencil *pStencil = canvas->activePage()->selectedStencils()->first();
578 pData = m_lstOldGeometry.first();
579
580 while( pStencil && pData )
581 {
582 newX = pData->rect.x() + dx;
583 newY = pData->rect.y() + dy;
584
585 if( pStencil->protection()->at( kpX ) == false ) {
586 pStencil->setX(newX);
587 }
588 if( pStencil->protection()->at( kpY ) == false ) {
589 pStencil->setY(newY);
590 }
591
592 pData = m_lstOldGeometry.next();
593 pStencil = canvas->activePage()->selectedStencils()->next();
594 }
595
596 // Draw the stencils
597 canvas->drawSelectedStencilsXOR();
598 view()->updateToolBars();
599}
600
601void SelectTool::continueCustomDragging(const TQPoint &pos)
602{
603 KivioCanvas* canvas = view()->canvasWidget();
604 KoPoint pagePoint = canvas->mapFromScreen(pos);
605 bool hit = false;
606
607 if(m_pCustomDraggingStencil->type() == kstConnector){
608 pagePoint = canvas->activePage()->snapToTarget(pagePoint, 8.0, hit);
609 }
610
611 if(!hit) {
612 pagePoint = canvas->snapToGridAndGuides( pagePoint );
613 }
614
615 KivioCustomDragData data;
616 data.page = canvas->activePage();
617 data.dx = pagePoint.x() - m_lastPoint.x();
618 data.dy = pagePoint.y() - m_lastPoint.y();
619 data.x = pagePoint.x();
620 data.y = pagePoint.y();
621 data.id = m_customDragID;
622 data.scale = view()->zoomHandler()->zoomedResolutionY();
623
624
625 if(m_pCustomDraggingStencil->type() != kstConnector){
626 // Undraw the old stencils
627 if(!m_firstTime) {
628 canvas->drawStencilXOR(m_pCustomDraggingStencil);
629 } else {
630 m_pCustomDraggingStencil->setHidden(true);
631 canvas->repaint();
632 m_firstTime = false;
633 }
634 }
635
636 // Custom dragging can only occur on one stencil
637 if( m_pCustomDraggingStencil )
638 m_pCustomDraggingStencil->customDrag( &data );
639
640 // Draw the stencils
641 if(m_pCustomDraggingStencil->type() != kstConnector){
642 canvas->drawStencilXOR(m_pCustomDraggingStencil);
643 } else {
644 view()->canvasWidget()->repaint();
645 }
646
647 view()->updateToolBars();
648}
649
650
651void SelectTool::continueResizing(const TQPoint &pos, bool ignoreGridGuides)
652{
653 KivioCanvas* canvas = view()->canvasWidget();
654 KoPoint pagePoint = canvas->mapFromScreen(pos);
655
656 if(!ignoreGridGuides) {
657 pagePoint = canvas->snapToGridAndGuides( pagePoint );
658 }
659
660 KivioSelectDragData *pData = m_lstOldGeometry.first();
661
662/* TQWMatrix m;
663 double w2 = m_pResizingStencil->w() / 2.0;
664 double h2 = m_pResizingStencil->h() / 2.0;
665 m.translate(m_pResizingStencil->x(), m_pResizingStencil->y());
666 m.translate(m_pResizingStencil->pinPoint().x(), m_pResizingStencil->pinPoint().y());
667 m.rotate(-m_pResizingStencil->rotation());
668 m.translate(-m_pResizingStencil->pinPoint().x(), -m_pResizingStencil->pinPoint().y());
669 m.translate(-m_pResizingStencil->x(), -m_pResizingStencil->y());
670 m.invert();
671
672 double x = pagePoint.x() * m.m11() + pagePoint.y() * m.m21() + m.dx();
673 double y = pagePoint.x() * m.m12() + pagePoint.y() * m.m22() + m.dy();*/
674
675 if( !pData )
676 {
677 kdDebug(43000) << "SelectTool::continueResizing() - Original geometry not found" << endl;
678 return;
679 }
680
681 double dx = pagePoint.x() - m_origPoint.x();
682 double dy = pagePoint.y() - m_origPoint.y();
683
684 if((dx > 0) || (dy > 0) || (dx < 0) || (dy < 0)) { // Do we really need to redraw?
685 // Undraw the old outline
686 if(!m_firstTime) {
687 canvas->drawStencilXOR( m_pResizingStencil );
688 } else {
689 m_pResizingStencil->setHidden(true);
690 canvas->repaint();
691 m_firstTime = false;
692 }
693
694 double sx = pData->rect.x();
695 double sy = pData->rect.y();
696 double sw = pData->rect.width();
697 double sh = pData->rect.height();
698 double ratio = sw / sh;
699
700 switch( m_resizeHandle )
701 {
702 case 1: // top left
703 if( m_pResizingStencil->protection()->testBit( kpWidth )==false &&
704 m_pResizingStencil->protection()->testBit( kpHeight )==false )
705 {
706 if((dx > dy) && (dx != 0)) {
707 dy = dx / ratio;
708 } else {
709 dx = dy * ratio;
710 }
711
712 m_pResizingStencil->setX( sx + dx );
713 m_pResizingStencil->setW( sw - dx );
714
715 m_pResizingStencil->setY( sy + dy );
716 m_pResizingStencil->setH( sh - dy );
717 }
718 break;
719
720 case 2: // top
721 if( m_pResizingStencil->protection()->testBit( kpHeight )==false )
722 {
723 m_pResizingStencil->setY( sy + dy );
724 m_pResizingStencil->setH( sh - dy );
725 }
726 break;
727
728 case 3: // top right
729 if( m_pResizingStencil->protection()->testBit( kpHeight )==false &&
730 m_pResizingStencil->protection()->testBit( kpWidth )==false )
731 {
732 if((dx > dy) && (dx != 0)) {
733 dy = -(dx / ratio);
734 } else {
735 dx = -(dy * ratio);
736 }
737
738 m_pResizingStencil->setY( sy + dy );
739 m_pResizingStencil->setH( sh - dy );
740
741 m_pResizingStencil->setW( sw + dx );
742 }
743 break;
744
745 case 4: // right
746 if( m_pResizingStencil->protection()->testBit( kpWidth )==false )
747 {
748 // see old kivio source when snaptogrid gets implemented
749 //setX( SnapToGrid(sx+sw+dx)-sx )
750 m_pResizingStencil->setW( sw + dx );
751 }
752 break;
753
754 case 5: // bottom right
755 if( m_pResizingStencil->protection()->testBit( kpWidth )==false &&
756 m_pResizingStencil->protection()->testBit( kpHeight )==false )
757 {
758 if((dx > dy) && (dx != 0)) {
759 dy = dx / ratio;
760 } else {
761 dx = dy * ratio;
762 }
763
764 m_pResizingStencil->setW( sw + dx );
765 m_pResizingStencil->setH( sh + dy );
766 }
767 break;
768
769 case 6: // bottom
770 if( m_pResizingStencil->protection()->testBit( kpHeight )==false )
771 {
772 m_pResizingStencil->setH( sh + dy );
773 }
774 break;
775
776 case 7: // bottom left
777 if( m_pResizingStencil->protection()->testBit( kpWidth )==false &&
778 m_pResizingStencil->protection()->testBit( kpHeight )==false )
779 {
780 if((dx > dy) && (dx != 0)) {
781 dy = -(dx / ratio);
782 } else {
783 dx = -(dy * ratio);
784 }
785
786 m_pResizingStencil->setX( sx + dx );
787 m_pResizingStencil->setW( sw - dx );
788
789 m_pResizingStencil->setH( sh + dy );
790 }
791 break;
792
793 case 8: // left
794 if( m_pResizingStencil->protection()->testBit( kpWidth )==false )
795 {
796 KoPoint pinPoint = m_pResizingStencil->pinPoint();
797 m_pResizingStencil->setPinPoint(KoPoint(pinPoint.x() - (dx / 2.0), pinPoint.y()));
798 m_pResizingStencil->setX( sx + dx );
799 m_pResizingStencil->setW( sw - dx );
800 }
801 break;
802
803 default:
804 kdDebug(43000) << "SelectTool::continueResizing() - unknown resize handle: " << m_resizeHandle << endl;
805 break;
806 }
807
808 canvas->drawStencilXOR( m_pResizingStencil );
809 view()->updateToolBars();
810 }
811}
812
813
817void SelectTool::changeMouseCursor(const TQPoint &pos)
818{
819 KivioCanvas* canvas = view()->canvasWidget();
820 KoPoint pagePoint = canvas->mapFromScreen(pos);
821 KivioStencil *pStencil;
822 double threshold = view()->zoomHandler()->unzoomItY(4);
823 int cursorType;
824
825 // Iterate through all the selected stencils
826 pStencil = canvas->activePage()->selectedStencils()->first();
827 while( pStencil )
828 {
829 cursorType = isOverResizeHandle(pStencil, pagePoint.x(), pagePoint.y());
830 switch( cursorType )
831 {
832 case 1: // top left
833 canvas->setCursor( sizeFDiagCursor );
834 return;
835
836 case 2: // top
837 canvas->setCursor( sizeVerCursor );
838 return;
839
840 case 3: // top right
841 canvas->setCursor( sizeBDiagCursor );
842 return;
843
844 case 4: // right
845 canvas->setCursor( sizeHorCursor );
846 return;
847
848 case 5: // bottom right
849 canvas->setCursor( sizeFDiagCursor );
850 return;
851
852 case 6: // bottom
853 canvas->setCursor( sizeVerCursor );
854 return;
855
856 case 7: // bottom left
857 canvas->setCursor( sizeBDiagCursor );
858 return;
859
860 case 8: // left
861 canvas->setCursor( sizeHorCursor );
862 return;
863
864 default:
865 if( pStencil->checkForCollision( &pagePoint, threshold )!= kctNone )
866 {
867 canvas->setCursor( sizeAllCursor );
868 return;
869 }
870 break;
871
872 }
873
874
875 pStencil = canvas->activePage()->selectedStencils()->next();
876 }
877
878 canvas->unsetCursor();
879}
880
881
885#define RESIZE_BOX_TEST( x, y, bx, by ) \
886x >= bx-three_pixels && \
887x <= bx+three_pixels && \
888y >= by-three_pixels && \
889y <= by+three_pixels
890
894int SelectTool::isOverResizeHandle( KivioStencil *pStencil, const double x, const double y )
895{
896 double three_pixels = 4.0;
897
898 int available;
899
900 TQWMatrix m;
901 double w = pStencil->w();
902 double h = pStencil->h();
903 double w2 = pStencil->w() / 2.0;
904 double h2 = pStencil->h() / 2.0;
905 m.translate(pStencil->x(), pStencil->y());
906 m.translate(w2, h2);
907 m.rotate(pStencil->rotation());
908 m.translate(-w2, -h2);
909
910 // FIXME: this needs to be optimized!!!!
911 KoPoint tl(0 * m.m11() + 0 * m.m21() + m.dx(), 0 * m.m12() + 0 * m.m22() + m.dy());
912 KoPoint t(w2 * m.m11() + 0 * m.m21() + m.dx(), w2 * m.m12() + 0 * m.m22() + m.dy());
913 KoPoint tr(w * m.m11() + 0 * m.m21() + m.dx(), w * m.m12() + 0 * m.m22() + m.dy());
914 KoPoint r(w * m.m11() + h2 * m.m21() + m.dx(), w * m.m12() + h2 * m.m22() + m.dy());
915 KoPoint br(w * m.m11() + h * m.m21() + m.dx(), w * m.m12() + h * m.m22() + m.dy());
916 KoPoint b(w2 * m.m11() + h * m.m21() + m.dx(), w2 * m.m12() + h * m.m22() + m.dy());
917 KoPoint bl(0 * m.m11() + h * m.m21() + m.dx(), 0 * m.m12() + h * m.m22() + m.dy());
918 KoPoint l(0 * m.m11() + h2 * m.m21() + m.dx(), 0 * m.m12() + h2 * m.m22() + m.dy());
919
920 available = pStencil->resizeHandlePositions();
921
922 // Quick reject
923 if( !available )
924 return 0;
925
926
927 // Top left
928 if( available & krhpNW &&
929 RESIZE_BOX_TEST( x, y, tl.x(), tl.y() ) )
930 return 1;
931
932 // Top
933 if( available & krhpN &&
934 RESIZE_BOX_TEST( x, y, t.x(), t.y() ) )
935 return 2;
936
937 // Top right
938 if( available & krhpNE &&
939 RESIZE_BOX_TEST( x, y, tr.x(), tr.y() ) )
940 return 3;
941
942 // Right
943 if( available & krhpE &&
944 RESIZE_BOX_TEST( x, y, r.x(), r.y() ) )
945 return 4;
946
947 // Bottom right
948 if( available & krhpSE &&
949 RESIZE_BOX_TEST( x, y, br.x(), br.y() ) )
950 return 5;
951
952 // Bottom
953 if( available & krhpS &&
954 RESIZE_BOX_TEST( x, y, b.x(), b.y() ) )
955 return 6;
956
957 // Bottom left
958 if( available & krhpSW &&
959 RESIZE_BOX_TEST( x, y, bl.x(), bl.y() ) )
960 return 7;
961
962 // Left
963 if( available & krhpW &&
964 RESIZE_BOX_TEST( x, y, l.x(), l.y() ) )
965 return 8;
966
967 // Nothing found
968 return 0;
969}
970
971
972void SelectTool::mouseRelease(const TQPoint &pos)
973{
974 m_releasePoint = pos;
975
976 switch( m_mode )
977 {
978 case stmDrawRubber:
979 endRubberBanding(pos);
980 break;
981
982 case stmCustomDragging:
983 endCustomDragging(pos);
984 break;
985
986 case stmDragging:
987 endDragging(pos);
988 break;
989
990 case stmResizing:
991 endResizing(pos);
992 break;
993 }
994
995 m_mode = stmNone;
996
997 view()->canvasWidget()->guideLines().repaintAfterSnapping();
998 view()->doc()->updateView(view()->activePage());
999}
1000
1001void SelectTool::endRubberBanding(const TQPoint &pos)
1002{
1003 KivioCanvas* canvas = view()->canvasWidget();
1004 // End the rubber-band drawing
1005 canvas->endRectDraw();
1006
1007 KoPoint p = canvas->mapFromScreen(pos);
1008
1009 // We can't select if the start and end points are the same
1010 if( m_origPoint.x() != p.x() && m_origPoint.y() != p.y() )
1011 {
1012 select(canvas->rect());
1013 }
1014
1015 view()->updateToolBars();
1016}
1017
1018void SelectTool::endDragging(const TQPoint&)
1019{
1020 KivioCanvas* canvas = view()->canvasWidget();
1021 canvas->activePage()->setPaintSelected(true);
1022 KMacroCommand *macro=new KMacroCommand( i18n("Move Stencil"));
1023 KivioStencil *pStencil = canvas->activePage()->selectedStencils()->first();
1024 KivioSelectDragData *pData = m_lstOldGeometry.first();
1025 bool moved = false;
1026
1027 while( pStencil && pData )
1028 {
1029 if((pData->rect.x() != pStencil->rect().x()) || (pData->rect.y() != pStencil->rect().y())) {
1030 KivioMoveStencilCommand * cmd = new KivioMoveStencilCommand( i18n("Move Stencil"),
1031 pStencil, pData->rect, pStencil->rect(), canvas->activePage());
1032 macro->addCommand( cmd);
1033
1034 if(pStencil->type() == kstConnector) {
1035 pStencil->searchForConnections(view()->activePage(), view()->zoomHandler()->unzoomItY(4));
1036 }
1037
1038 moved = true;
1039 }
1040
1041 pData = m_lstOldGeometry.next();
1042 pStencil = canvas->activePage()->selectedStencils()->next();
1043 }
1044
1045 if(moved) {
1046 canvas->doc()->addCommand( macro );
1047 } else {
1048 delete macro;
1049 }
1050
1051 canvas->drawSelectedStencilsXOR();
1052 canvas->endUnclippedSpawnerPainter();
1053 // Clear the list of old geometry
1054 m_lstOldGeometry.clear();
1055}
1056
1057void SelectTool::endCustomDragging(const TQPoint&)
1058{
1059 KivioCanvas* canvas = view()->canvasWidget();
1060 m_pCustomDraggingStencil->setHidden(false);
1061 KivioCustomDragCommand* cmd = new KivioCustomDragCommand(i18n("Move Connector Point"), view()->activePage(),
1062 m_pCustomDraggingStencil, m_customDragID, m_customDragOrigPoint,
1063 m_pCustomDraggingStencil->customIDPoint(m_customDragID));
1064 view()->doc()->addCommand(cmd);
1065 m_customDragID = 0;
1066 KivioStencil *pStencil = canvas->activePage()->selectedStencils()->first();
1067
1068 while( pStencil )
1069 {
1070 if(pStencil->type() == kstConnector) {
1071 pStencil->searchForConnections(view()->activePage(), view()->zoomHandler()->unzoomItY(4));
1072 }
1073
1074 pStencil = canvas->activePage()->selectedStencils()->next();
1075 }
1076
1077 canvas->endUnclippedSpawnerPainter();
1078
1079 canvas->setShowConnectorTargets(false);
1080 canvas->repaint();
1081}
1082
1083void SelectTool::endResizing(const TQPoint&)
1084{
1085 KivioCanvas* canvas = view()->canvasWidget();
1086 m_pResizingStencil->setHidden(false);
1087 KivioResizeStencilCommand * cmd = new KivioResizeStencilCommand( i18n("Resize Stencil"),
1088 m_pResizingStencil, m_lstOldGeometry.first()->rect, m_pResizingStencil->rect(), view()->activePage());
1089 canvas->doc()->addCommand( cmd );
1090 // Undraw the last outline
1091 canvas->drawStencilXOR( m_pResizingStencil );
1092
1093 if(m_pResizingStencil->type() == kstConnector) {
1094 m_pResizingStencil->searchForConnections(view()->activePage(), view()->zoomHandler()->unzoomItY(4));
1095 }
1096
1097 // Deallocate the painter object
1098 canvas->endUnclippedSpawnerPainter();
1099
1100 // Set the class vars to nothing
1101 m_pResizingStencil = NULL;
1102 m_resizeHandle = 0;
1103}
1104
1108void SelectTool::showPopupMenu( const TQPoint &pos )
1109{
1110 TDEPopupMenu* menu = 0;
1111
1112 if(view()->activePage()->selectedStencils()->count() < 1) {
1113 menu = static_cast<TDEPopupMenu*>(view()->factory()->container("PagePopup", view()));
1114 } else {
1115 menu = static_cast<TDEPopupMenu*>(view()->factory()->container("StencilPopup", view()));
1116 m_arrowHeadAction->setEnabled(view()->activePage()->checkForStencilTypeInSelection(kstConnector));
1117
1118 if(view()->activePage()->checkForTextBoxesInSelection()) {
1119 m_textEditAction->setEnabled(true);
1120 } else {
1121 m_textEditAction->setEnabled(false);
1122 }
1123 }
1124
1125 if(menu) {
1126 m_lastPoint = view()->canvasWidget()->mapFromScreen(pos);
1127 menu->popup(pos);
1128 } else {
1129 kdDebug(43000) << "What no popup! *ARGH*!" << endl;
1130 }
1131}
1132
1133
1141void SelectTool::leftDoubleClick(const TQPoint& pos)
1142{
1143 if( view()->activePage()->selectedStencils()->count() <= 0 )
1144 return;
1145
1146 KoPoint pagePoint = view()->canvasWidget()->mapFromScreen(pos);
1147 // Figure out how big 4 pixels is in terms of points
1148 double threshold = view()->zoomHandler()->unzoomItY(4);
1149 int colType;
1150 KivioPage *page = view()->activePage();
1151 KivioStencil* stencil = page->checkForStencil( &pagePoint, &colType, threshold, false);
1152
1153 if(stencil) {
1154 // Locate the text tool. If not found, bail with an error
1155 Kivio::Plugin *p = view()->pluginManager()->findPlugin("Text Mouse Tool");
1156
1157 if( !p )
1158 {
1159 kdDebug(43000) << "SelectTool::leftDoubleClick() - unable to locate Text Tool" << endl;
1160 return;
1161 }
1162
1163 static_cast<Kivio::MouseTool*>(p)->applyToolAction(stencil, pagePoint);
1164 }
1165}
1166
1167void SelectTool::editText(TQPtrList<KivioStencil>* stencils)
1168{
1169 // Locate the text tool. If not found, bail with an error
1170 Kivio::Plugin *p = view()->pluginManager()->findPlugin("Text Mouse Tool");
1171 if( !p )
1172 {
1173 kdDebug(43000) << "SelectTool::leftDoubleClick() - unable to locate Text Tool" << endl;
1174 return;
1175 }
1176
1177 // Select the text tool (which makes the text dialog pop up)
1178 static_cast<Kivio::MouseTool*>(p)->applyToolAction(stencils);
1179}
1180
1181void SelectTool::showProperties()
1182{
1183 //FIXME: This needs to be implemented ;)
1184 if(view()->activePage()->selectedStencils()->count() == 0) {
1185 view()->paperLayoutDlg();
1186 }
1187}
1188
1189void SelectTool::editStencilText()
1190{
1191 editText(view()->activePage()->selectedStencils());
1192}
1193
1194void SelectTool::keyPress(TQKeyEvent* e)
1195{
1196 KivioCanvas* canvas = view()->canvasWidget();
1197
1198 canvas->setEnabled(false);
1199
1200 // Create a new painter object
1201 canvas->beginUnclippedSpawnerPainter();
1202
1203 // Build the list of old geometry
1204 KivioSelectDragData *pData;
1205 m_lstOldGeometry.clear();
1206 KivioStencil* pStencil = canvas->activePage()->selectedStencils()->first();
1207
1208 while( pStencil )
1209 {
1210 pData = new KivioSelectDragData;
1211 pData->rect = pStencil->rect();
1212 m_lstOldGeometry.append(pData);
1213
1214
1215 pStencil = canvas->activePage()->selectedStencils()->next();
1216 }
1217
1218 m_selectedRect = view()->activePage()->getRectForAllSelectedStencils();
1219 // Set the mode
1220 m_mode = stmDragging;
1221 canvas->setEnabled(true);
1222 m_origPoint = m_selectedRect.topLeft();
1223 KivioGridData gd = view()->doc()->grid();
1224 bool ignoreGridGuides = e->state() & ShiftButton;
1225 double distX, distY;
1226
1227 if(ignoreGridGuides || !view()->doc()->grid().isSnap) {
1228 distX = view()->zoomHandler()->unzoomItX(1);
1229 distY = view()->zoomHandler()->unzoomItY(1);
1230 } else {
1231 distX = gd.freq.width();
1232 distY = gd.freq.height();
1233 }
1234
1235 switch(e->key()) {
1236 case Key_Left:
1237 continueDragging(canvas->mapToScreen(KoPoint(m_selectedRect.x() - distX,
1238 m_selectedRect.y())), ignoreGridGuides);
1239 break;
1240 case Key_Up:
1241 continueDragging(canvas->mapToScreen(KoPoint(m_selectedRect.x(),
1242 m_selectedRect.y() - distY)), ignoreGridGuides);
1243 break;
1244 case Key_Right:
1245 continueDragging(canvas->mapToScreen(KoPoint(m_selectedRect.x() + distX,
1246 m_selectedRect.y())), ignoreGridGuides);
1247 break;
1248 case Key_Down:
1249 continueDragging(canvas->mapToScreen(KoPoint(m_selectedRect.x(),
1250 m_selectedRect.y() + distY)), ignoreGridGuides);
1251 break;
1252 default:
1253 break;
1254 }
1255
1256 endDragging(TQPoint());
1257 canvas->guideLines().repaintAfterSnapping();
1258 canvas->setFocus();
1259}
1260
1261#include "tool_select.moc"
Baseclass for mouse tools (like eg the select tool)
This class provides the base for all plugins in Kivio.