00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "KoInteractionTool.h"
00023
00024 #include <QMouseEvent>
00025 #include <QPainter>
00026 #include <QPainterPath>
00027 #include <QBitmap>
00028
00029 #include "KoPointerEvent.h"
00030 #include "KoShape.h"
00031 #include "KoSelection.h"
00032 #include "KoShapeManager.h"
00033 #include "KoInteractionStrategy.h"
00034 #include "KoCanvasBase.h"
00035 #include "KoCommand.h"
00036
00037 #include <kcommand.h>
00038 #include <kcursor.h>
00039 #include <kstandarddirs.h>
00040 #include <kstaticdeleter.h>
00041 #include <kdebug.h>
00042
00043 #define HANDLE_DISTANCE 10
00044
00045 KoInteractionTool::KoInteractionTool( KoCanvasBase *canvas )
00046 : KoTool( canvas )
00047 , m_currentStrategy( 0 )
00048 , m_lastHandle(KoFlake::NoHandle)
00049 , m_mouseWasInsideHandles( false )
00050 , m_moveCommand(0)
00051 {
00052 QPixmap rotatePixmap, shearPixmap;
00053 rotatePixmap.load(KStandardDirs::locate("data", "koffice/icons/rotate.png"));
00054 shearPixmap.load(KStandardDirs::locate("data", "koffice/icons/shear.png"));
00055
00056 m_rotateCursors[0] = QCursor(rotatePixmap.transformed(QMatrix().rotate(45)));
00057 m_rotateCursors[1] = QCursor(rotatePixmap.transformed(QMatrix().rotate(90)));
00058 m_rotateCursors[2] = QCursor(rotatePixmap.transformed(QMatrix().rotate(135)));
00059 m_rotateCursors[3] = QCursor(rotatePixmap.transformed(QMatrix().rotate(180)));
00060 m_rotateCursors[4] = QCursor(rotatePixmap.transformed(QMatrix().rotate(225)));
00061 m_rotateCursors[5] = QCursor(rotatePixmap.transformed(QMatrix().rotate(270)));
00062 m_rotateCursors[6] = QCursor(rotatePixmap.transformed(QMatrix().rotate(315)));
00063 m_rotateCursors[7] = QCursor(rotatePixmap);
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 m_shearCursors[0] = QCursor(shearPixmap);
00075 m_shearCursors[1] = QCursor(shearPixmap.transformed(QMatrix().rotate(45)));
00076 m_shearCursors[2] = QCursor(shearPixmap.transformed(QMatrix().rotate(90)));
00077 m_shearCursors[3] = QCursor(shearPixmap.transformed(QMatrix().rotate(135)));
00078 m_shearCursors[4] = QCursor(shearPixmap.transformed(QMatrix().rotate(180)));
00079 m_shearCursors[5] = QCursor(shearPixmap.transformed(QMatrix().rotate(225)));
00080 m_shearCursors[6] = QCursor(shearPixmap.transformed(QMatrix().rotate(270)));
00081 m_shearCursors[7] = QCursor(shearPixmap.transformed(QMatrix().rotate(315)));
00082 m_sizeCursors[0] = KCursor::sizeVerCursor();
00083 m_sizeCursors[1] = KCursor::sizeBDiagCursor();
00084 m_sizeCursors[2] = KCursor::sizeHorCursor();
00085 m_sizeCursors[3] = KCursor::sizeFDiagCursor();
00086 m_sizeCursors[4] = KCursor::sizeVerCursor();
00087 m_sizeCursors[5] = KCursor::sizeBDiagCursor();
00088 m_sizeCursors[6] = KCursor::sizeHorCursor();
00089 m_sizeCursors[7] = KCursor::sizeFDiagCursor();
00090 }
00091
00092 KoInteractionTool::~KoInteractionTool()
00093 {
00094 delete m_currentStrategy;
00095 m_moveCommand = 0;
00096 }
00097
00098 bool KoInteractionTool::wantsAutoScroll()
00099 {
00100 return true;
00101 }
00102
00103 void KoInteractionTool::updateCursor() {
00104 QCursor cursor = Qt::ArrowCursor;
00105
00106 if(selection()->count() > 0) {
00107 bool editable=false;
00108 foreach(KoShape *shape, selection()->selectedShapes(KoFlake::StrippedSelection)) {
00109 if(!shape->isLocked())
00110 editable = true;
00111 }
00112
00113 if(selection()->count()>1)
00114 m_angle = selection()->rotation();
00115 else
00116 m_angle = selection()->firstSelectedShape()->rotation();
00117
00118 int rotOctant = 8 + int(8.5 + m_angle / 45);
00119
00120 if(!m_mouseWasInsideHandles) {
00121 switch(m_lastHandle) {
00122 case KoFlake::TopMiddleHandle:
00123 cursor = m_shearCursors[(0 +rotOctant)%8];
00124 break;
00125 case KoFlake::TopRightHandle:
00126 cursor = m_rotateCursors[(1 +rotOctant)%8];
00127 break;
00128 case KoFlake::RightMiddleHandle:
00129 cursor = m_shearCursors[(2 +rotOctant)%8];
00130 break;
00131 case KoFlake::BottomRightHandle:
00132 cursor = m_rotateCursors[(3 +rotOctant)%8];
00133 break;
00134 case KoFlake::BottomMiddleHandle:
00135 cursor = m_shearCursors[(4 +rotOctant)%8];
00136 break;
00137 case KoFlake::BottomLeftHandle:
00138 cursor = m_rotateCursors[(5 +rotOctant)%8];
00139 break;
00140 case KoFlake::LeftMiddleHandle:
00141 cursor = m_shearCursors[(6 +rotOctant)%8];
00142 break;
00143 case KoFlake::TopLeftHandle:
00144 cursor = m_rotateCursors[(7 +rotOctant)%8];
00145 break;
00146 case KoFlake::NoHandle:
00147 cursor = Qt::ArrowCursor;
00148 break;
00149 }
00150 }
00151 else {
00152 switch(m_lastHandle) {
00153 case KoFlake::TopMiddleHandle:
00154 cursor = m_sizeCursors[(0 +rotOctant)%8];
00155 break;
00156 case KoFlake::TopRightHandle:
00157 cursor = m_sizeCursors[(1 +rotOctant)%8];
00158 break;
00159 case KoFlake::RightMiddleHandle:
00160 cursor = m_sizeCursors[(2 +rotOctant)%8];
00161 break;
00162 case KoFlake::BottomRightHandle:
00163 cursor = m_sizeCursors[(3 +rotOctant)%8];
00164 break;
00165 case KoFlake::BottomMiddleHandle:
00166 cursor = m_sizeCursors[(4 +rotOctant)%8];
00167 break;
00168 case KoFlake::BottomLeftHandle:
00169 cursor = m_sizeCursors[(5 +rotOctant)%8];
00170 break;
00171 case KoFlake::LeftMiddleHandle:
00172 cursor = m_sizeCursors[(6 +rotOctant)%8];
00173 break;
00174 case KoFlake::TopLeftHandle:
00175 cursor = m_sizeCursors[(7 +rotOctant)%8];
00176 break;
00177 case KoFlake::NoHandle:
00178 cursor = Qt::SizeAllCursor;
00179 break;
00180 }
00181 }
00182 if( !editable)
00183 cursor = Qt::ArrowCursor;
00184 }
00185 useCursor(cursor);
00186 }
00187
00188 void KoInteractionTool::paint( QPainter &painter, KoViewConverter &converter) {
00189 if ( m_currentStrategy )
00190 m_currentStrategy->paint( painter, converter);
00191 else if(selection()->count() > 0) {
00192 SelectionDecorator decorator(m_mouseWasInsideHandles ? m_lastHandle : KoFlake::NoHandle,
00193 true, true);
00194 decorator.setSelection(selection());
00195 decorator.paint(painter, converter);
00196 }
00197 }
00198
00199 void KoInteractionTool::mousePressEvent( KoPointerEvent *event ) {
00200 Q_ASSERT(m_currentStrategy == 0);
00201 m_currentStrategy = KoInteractionStrategy::createStrategy(event, this, m_canvas);
00202 m_moveCommand = 0;
00203 updateCursor();
00204 }
00205
00206 void KoInteractionTool::mouseMoveEvent( KoPointerEvent *event ) {
00207 if(m_currentStrategy) {
00208 m_lastPoint = event->point;
00209 m_currentStrategy->handleMouseMove( m_lastPoint, event->modifiers() );
00210 }
00211 else {
00212 if(selection()->count() > 0) {
00213 QRectF bound = handlesSize();
00214 if(bound.contains(event->point)) {
00215 bool inside;
00216 KoFlake::SelectionHandle newDirection = handleAt(event->point, &inside);
00217 if(inside != m_mouseWasInsideHandles || m_lastHandle != newDirection) {
00218 m_lastHandle = newDirection;
00219 m_mouseWasInsideHandles = inside;
00220 repaintDecorations();
00221 }
00222 } else {
00223 if(m_lastHandle != KoFlake::NoHandle)
00224 repaintDecorations();
00225 m_lastHandle = KoFlake::NoHandle;
00226 m_mouseWasInsideHandles = false;
00227 }
00228 }
00229 event->ignore();
00230 }
00231 updateCursor();
00232 }
00233
00234 QRectF KoInteractionTool::handlesSize() {
00235 QRectF bound = selection()->boundingRect();
00236
00237 QPointF border = m_canvas->viewConverter()->viewToDocument(QPointF(HANDLE_DISTANCE, HANDLE_DISTANCE));
00238 bound.adjust(-border.x(), -border.y(), border.x(), border.y());
00239 return bound;
00240 }
00241
00242 void KoInteractionTool::mouseReleaseEvent( KoPointerEvent *event ) {
00243 Q_UNUSED(event);
00244 if ( m_currentStrategy )
00245 {
00246 m_currentStrategy->finishInteraction( event->modifiers() );
00247 KCommand *command = m_currentStrategy->createCommand();
00248 if(command)
00249 m_canvas->addCommand(command, false);
00250 delete m_currentStrategy;
00251 m_currentStrategy = 0;
00252 repaintDecorations();
00253 }
00254 else
00255 event->ignore();
00256 updateCursor();
00257 }
00258
00259 void KoInteractionTool::keyPressEvent(QKeyEvent *event) {
00260 if(m_currentStrategy &&
00261 (event->key() == Qt::Key_Control ||
00262 event->key() == Qt::Key_Alt || event->key() == Qt::Key_Shift ||
00263 event->key() == Qt::Key_Meta)) {
00264 m_currentStrategy->handleMouseMove( m_lastPoint, event->modifiers() );
00265 } else if(m_currentStrategy == 0) {
00266 double x=0.0, y=0.0;
00267 if(event->key() == Qt::Key_Left)
00268 x=-0.5;
00269 else if(event->key() == Qt::Key_Right)
00270 x=0.5;
00271 else if(event->key() == Qt::Key_Up)
00272 y=-0.5;
00273 else if(event->key() == Qt::Key_Down)
00274 y=0.5;
00275
00276 if(x != 0.0 || y != 0.0) {
00277 if((event->modifiers() & Qt::ShiftModifier) == 0) {
00278 x *= 10;
00279 y *= 10;
00280 }
00281
00282 QList<QPointF> prevPos;
00283 QList<QPointF> newPos;
00284 QList<KoShape*> shapes;
00285 foreach(KoShape* shape, selection()->selectedShapes(KoFlake::StrippedSelection)) {
00286 if(shape->isLocked())
00287 continue;
00288 shapes.append(shape);
00289 QPointF p = shape->position();
00290 prevPos.append(p);
00291 p.setX(p.x() + x);
00292 p.setY(p.y() + y);
00293 newPos.append(p);
00294 }
00295 if(shapes.count() > 0) {
00296 if(m_lastUsedMoveCommand.msecsTo(QTime::currentTime()) > 5000)
00297 m_moveCommand = 0;
00298 if(m_moveCommand)
00299 m_moveCommand->setNewPositions(newPos);
00300 else {
00301 kDebug() << "new command\n";
00302 m_moveCommand = new KoShapeMoveCommand(shapes, prevPos, newPos);
00303 m_canvas->addCommand(m_moveCommand, false);
00304 }
00305 m_moveCommand->execute();
00306 m_lastUsedMoveCommand = QTime::currentTime();
00307 }
00308 }
00309 }
00310 }
00311
00312 void KoInteractionTool::keyReleaseEvent(QKeyEvent *event) {
00313 if(m_currentStrategy == 0)
00314 ;
00315 else if(event->key() == Qt::Key_Escape) {
00316 m_currentStrategy->cancelInteraction();
00317 delete m_currentStrategy;
00318 m_currentStrategy = 0;
00319 event->accept();
00320 }
00321 else if(event->key() == Qt::Key_Control ||
00322 event->key() == Qt::Key_Alt || event->key() == Qt::Key_Shift ||
00323 event->key() == Qt::Key_Meta) {
00324 m_currentStrategy->handleMouseMove( m_lastPoint, event->modifiers() );
00325 }
00326 }
00327
00328 void KoInteractionTool::repaintDecorations() {
00329 if ( selection()->count() > 0 )
00330 m_canvas->updateCanvas(handlesSize());
00331 }
00332
00333 KoSelection *KoInteractionTool::selection() {
00334 return m_canvas->shapeManager()->selection();
00335 }
00336
00337 KoFlake::SelectionHandle KoInteractionTool::handleAt(const QPointF &point, bool *innerHandleMeaning) {
00338
00339 static const KoFlake::SelectionHandle handleOrder[] = {
00340 KoFlake::BottomRightHandle,
00341 KoFlake::TopLeftHandle,
00342 KoFlake::BottomLeftHandle,
00343 KoFlake::TopRightHandle,
00344 KoFlake::BottomMiddleHandle,
00345 KoFlake::RightMiddleHandle,
00346 KoFlake::LeftMiddleHandle,
00347 KoFlake::TopMiddleHandle,
00348 KoFlake::NoHandle
00349 };
00350
00351 if( selection()->count() == 0 )
00352 return KoFlake::NoHandle;
00353
00354 recalcSelectionBox();
00355 KoViewConverter *converter = m_canvas->viewConverter();
00356
00357 if(innerHandleMeaning != 0)
00358 {
00359 QPainterPath path;
00360 path.addPolygon(m_selectionOutline);
00361 *innerHandleMeaning = path.contains(point);
00362 }
00363 for ( int i = 0; i < KoFlake::NoHandle; ++i ) {
00364 KoFlake::SelectionHandle handle = handleOrder[i];
00365 QPointF pt = converter->documentToView(point) - converter->documentToView(m_selectionBox[handle]);
00366
00367
00368 if(qAbs(pt.x()) < HANDLE_DISTANCE &&
00369 qAbs(pt.y()) < HANDLE_DISTANCE) {
00370 if(innerHandleMeaning != 0)
00371 {
00372 if(qAbs(pt.x()) < 4 && qAbs(pt.y()) < 4)
00373 *innerHandleMeaning = true;
00374 }
00375 return handle;
00376 }
00377 }
00378 return KoFlake::NoHandle;
00379 }
00380
00381 void KoInteractionTool::recalcSelectionBox() {
00382 if(selection()->count()==0)
00383 return;
00384
00385 if(selection()->count()>1)
00386 {
00387 QMatrix matrix = selection()->transformationMatrix(0);
00388 m_selectionOutline = matrix.map(QPolygonF(QRectF(QPointF(0, 0), selection()->size())));
00389 m_angle = selection()->rotation();
00390 }
00391 else
00392 {
00393 QMatrix matrix = selection()->firstSelectedShape()->transformationMatrix(0);
00394 m_selectionOutline = matrix.map(QPolygonF(QRectF(QPointF(0, 0), selection()->firstSelectedShape()->size())));
00395 m_angle = selection()->firstSelectedShape()->rotation();
00396 }
00397 QPolygonF outline = m_selectionOutline;
00398 m_selectionBox[KoFlake::TopMiddleHandle] = (outline.value(0)+outline.value(1))/2;
00399 m_selectionBox[KoFlake::TopRightHandle] = outline.value(1);
00400 m_selectionBox[KoFlake::RightMiddleHandle] = (outline.value(1)+outline.value(2))/2;
00401 m_selectionBox[KoFlake::BottomRightHandle] = outline.value(2);
00402 m_selectionBox[KoFlake::BottomMiddleHandle] = (outline.value(2)+outline.value(3))/2;
00403 m_selectionBox[KoFlake::BottomLeftHandle] = outline.value(3);
00404 m_selectionBox[KoFlake::LeftMiddleHandle] = (outline.value(3)+outline.value(0))/2;
00405 m_selectionBox[KoFlake::TopLeftHandle] = outline.value(0);
00406 }
00407
00408 void KoInteractionTool::activate(bool temporary) {
00409 Q_UNUSED(temporary);
00410 m_mouseWasInsideHandles = false;
00411 m_lastHandle = KoFlake::NoHandle;
00412 useCursor(Qt::ArrowCursor, true);
00413 repaintDecorations();
00414 }
00415
00416
00417 QImage * SelectionDecorator::s_rotateCursor=0;
00418 static KStaticDeleter<QImage> staticRotateCursorDeleter;
00419
00420 SelectionDecorator::SelectionDecorator(KoFlake::SelectionHandle arrows,
00421 bool rotationHandles, bool shearHandles)
00422 : m_rotationHandles(rotationHandles)
00423 , m_shearHandles(shearHandles)
00424 , m_arrows(arrows)
00425 {
00426 if(SelectionDecorator::s_rotateCursor == 0) {
00427 staticRotateCursorDeleter.setObject(s_rotateCursor, new QImage());
00428 s_rotateCursor->load(KStandardDirs::locate("lib", "flake/rotate.png"));
00429 }
00430 }
00431
00432 void SelectionDecorator::setSelection(KoSelection *selection) {
00433 m_selection = selection;
00434 }
00435
00436 void SelectionDecorator::paint(QPainter &painter, KoViewConverter &converter) {
00437 QPen pen( Qt::green );
00438 QPolygonF outline;
00439
00440 painter.save();
00441 painter.setRenderHint( QPainter::Antialiasing, false );
00442 painter.setPen( pen );
00443 bool editable=false;
00444 foreach(KoShape *shape, m_selection->selectedShapes(KoFlake::StrippedSelection)) {
00445 QMatrix matrix = shape->transformationMatrix(0);
00446 outline = matrix.map(QPolygonF(QRectF(QPointF(0, 0), shape->size())));
00447 for(int i =0; i<outline.count(); i++)
00448 outline[i] = converter.documentToView(outline.value(i));
00449 painter.drawPolygon(outline);
00450 if(!shape->isLocked())
00451 editable = true;
00452 }
00453 painter.restore();
00454
00455 if(m_selection->count()>1)
00456 {
00457 QMatrix matrix = m_selection->transformationMatrix(0);
00458 outline = matrix.map(QPolygonF(QRectF(QPointF(0, 0), m_selection->size())));
00459 for(int i =0; i<outline.count(); i++)
00460 outline[i] = converter.documentToView(outline.value(i));
00461 pen = QPen( Qt::blue );
00462 painter.setPen(pen);
00463 painter.drawPolygon(outline);
00464 }
00465 else if( m_selection->firstSelectedShape() )
00466 {
00467 QMatrix matrix = m_selection->firstSelectedShape()->transformationMatrix(0);
00468 outline = matrix.map(QPolygonF(QRectF(QPointF(0, 0), m_selection->firstSelectedShape()->size())));
00469 for(int i =0; i<outline.count(); i++)
00470 outline[i] = converter.documentToView(outline.value(i));
00471 }
00472
00473 if( !editable)
00474 return;
00475
00476 pen = QPen( Qt::black );
00477 pen.setWidthF(1.2);
00478 painter.setPen(pen);
00479 painter.setBrush(Qt::yellow);
00480
00481
00482 pen.setWidthF(0);
00483 painter.setPen(pen);
00484 QRectF rect(outline.value(0)- QPointF(3,3), QSizeF(6, 6));
00485 painter.drawRect(rect);
00486 rect.moveTo(outline.value(1)- QPointF(3,3));
00487 painter.drawRect(rect);
00488 rect.moveTo(outline.value(2)- QPointF(3,3));
00489 painter.drawRect(rect);
00490 rect.moveTo(outline.value(3)- QPointF(3,3));
00491 painter.drawRect(rect);
00492 rect.moveTo((outline.value(0)+outline.value(1))/2 - QPointF(3,3));
00493 painter.drawRect(rect);
00494 rect.moveTo((outline.value(1)+outline.value(2))/2 - QPointF(3,3));
00495 painter.drawRect(rect);
00496 rect.moveTo((outline.value(2)+outline.value(3))/2 - QPointF(3,3));
00497 painter.drawRect(rect);
00498 rect.moveTo((outline.value(3)+outline.value(0))/2 - QPointF(3,3));
00499 painter.drawRect(rect);
00500
00501 #if 0
00502
00503 if(m_arrows != KoFlake::NoHandle && bounds.width() > 45 && bounds.height() > 45) {
00504 double x1,x2,y1,y2;
00505 switch(m_arrows) {
00506 case KoFlake::TopMiddleHandle:
00507 x1=bounds.center().x(); x2=x1; y2=bounds.y()+8; y1=y2+20;
00508 break;
00509 case KoFlake::TopRightHandle:
00510 x2=bounds.right()-8; x1=x2-20; y2=bounds.y()+8; y1=y2+20;
00511 break;
00512 case KoFlake::RightMiddleHandle:
00513 x2=bounds.right()-8; x1=x2-20; y1=bounds.center().y(); y2=y1;
00514 break;
00515 case KoFlake::BottomRightHandle:
00516 x2=bounds.right()-8; x1=x2-20; y2=bounds.bottom()-8; y1=y2-20;
00517 break;
00518 case KoFlake::BottomMiddleHandle:
00519 x1=bounds.center().x(); x2=x1; y2=bounds.bottom()-8; y1=y2-20;
00520 break;
00521 case KoFlake::BottomLeftHandle:
00522 x2=bounds.left()+8; x1=x2+20; y2=bounds.bottom()-8; y1=y2-20;
00523 break;
00524 case KoFlake::LeftMiddleHandle:
00525 x2=bounds.left()+8; x1=x2+20; y1=bounds.center().y(); y2=y1;
00526 break;
00527 default:
00528 case KoFlake::TopLeftHandle:
00529 x2=bounds.left()+8; x1=x2+20; y2=bounds.y()+8; y1=y2+20;
00530 break;
00531 }
00532 painter.drawLine(QLineF(x1, y1, x2, y2));
00533
00534
00535
00536 }
00537
00538 QPointF border(HANDLE_DISTANCE, HANDLE_DISTANCE);
00539 bounds.adjust(-border.x(), -border.y(), border.x(), border.y());
00540
00541 if(m_rotationHandles) {
00542 painter.save();
00543 painter.translate(bounds.x(), bounds.y());
00544 QRectF rect(QPointF(0,0), QSizeF(22, 22));
00545 painter.drawImage(rect, *s_rotateCursor, rect);
00546 painter.translate(bounds.width(), 0);
00547 painter.rotate(90);
00548 if(bounds.width() > 45 && bounds.height() > 45)
00549 painter.drawImage(rect, *s_rotateCursor, rect);
00550 painter.translate(bounds.height(), 0);
00551 painter.rotate(90);
00552 painter.drawImage(rect, *s_rotateCursor, rect);
00553 painter.translate(bounds.width(), 0);
00554 painter.rotate(90);
00555 if(bounds.width() > 45 && bounds.height() > 45)
00556 painter.drawImage(rect, *s_rotateCursor, rect);
00557 painter.restore();
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574 #endif
00575 }