1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16
17 #include "canvasmode_edit.h"
18
19 #include <QApplication>
20 #include <QButtonGroup>
21 #include <QCheckBox>
22 #include <QCursor>
23 #include <QDebug>
24 #include <QEvent>
25 #include <QMessageBox>
26 #include <QMouseEvent>
27 #include <QPainterPath>
28 #include <QPoint>
29 #include <QPointF>
30 #include <QRect>
31 #include <QTimer>
32 #include <QWidgetAction>
33
34 #include "appmodes.h"
35 #include "canvas.h"
36 #include "fpoint.h"
37 #include "fpointarray.h"
38 #include "hyphenator.h"
39 #include "iconmanager.h"
40 #include "pageitem_noteframe.h"
41 #include "pageitem_textframe.h"
42 #include "prefscontext.h"
43 #include "prefsfile.h"
44 #include "prefsmanager.h"
45 #include "sccolorengine.h"
46 #include "scmimedata.h"
47 #include "scribus.h"
48 #include "scribusXml.h"
49 #include "scribusdoc.h"
50 #include "scribusview.h"
51 #include "selection.h"
52 #include "ui/aligndistribute.h"
53 #include "ui/contextmenu.h"
54 #include "ui/hruler.h"
55 #include "ui/insertTable.h"
56 #include "ui/pageselector.h"
57 #include "ui/propertiespalette.h"
58 #include "undomanager.h"
59 #include "units.h"
60 #include "util.h"
61 #include "util_math.h"
62
63
CanvasMode_Edit(ScribusView * view)64 CanvasMode_Edit::CanvasMode_Edit(ScribusView* view) : CanvasMode(view), m_ScMW(view->m_ScMW)
65 {
66 m_blinker = new QTimer(view);
67 connect(m_blinker, SIGNAL(timeout()), this, SLOT(blinkTextCursor()));
68 connect(view->horizRuler, SIGNAL(MarkerMoved(double,double)), this, SLOT(rulerPreview(double,double)));
69 }
70
GetItem(PageItem ** pi)71 inline bool CanvasMode_Edit::GetItem(PageItem** pi)
72 {
73 *pi = m_doc->m_Selection->itemAt(0);
74 return (*pi) != nullptr;
75 }
76
77
blinkTextCursor()78 void CanvasMode_Edit::blinkTextCursor()
79 {
80 PageItem* currItem;
81 if (m_doc->appMode == modeEdit && GetItem(&currItem))
82 {
83 QRectF brect = QRectF(0, 0, currItem->width(), currItem->height());
84 QTransform m = currItem->getTransform();
85 brect = m.mapRect(brect);
86 m_canvas->update(QRectF(m_canvas->canvasToLocal(brect.topLeft()), QSizeF(brect.width(),brect.height())*m_canvas->scale()).toRect());
87 }
88 }
89
keyPressEvent(QKeyEvent * e)90 void CanvasMode_Edit::keyPressEvent(QKeyEvent *e)
91 {
92 if (m_keyRepeat)
93 return;
94 m_keyRepeat = true;
95 e->accept();
96
97 if (e->key() == Qt::Key_Escape)
98 {
99 // Go back to normal mode.
100 m_view->requestMode(modeNormal);
101 m_keyRepeat = false;
102 return;
103 }
104
105 PageItem* currItem;
106 if (!GetItem(&currItem))
107 {
108 m_keyRepeat = false;
109 return;
110 }
111
112 if (currItem->isImageFrame() && !currItem->locked())
113 {
114 currItem->handleModeEditKey(e, m_keyRepeat);
115 }
116 if (currItem->isTextFrame())
117 {
118 bool oldKeyRepeat = m_keyRepeat;
119
120 m_cursorVisible = true;
121 switch (e->key())
122 {
123 case Qt::Key_PageUp:
124 case Qt::Key_PageDown:
125 case Qt::Key_Up:
126 case Qt::Key_Down:
127 case Qt::Key_Home:
128 case Qt::Key_End:
129 m_longCursorTime=true;
130 break;
131 default:
132 m_longCursorTime=false;
133 break;
134 }
135 blinkTextCursor();
136 if (!currItem->isTextFrame() || (currItem->isAutoNoteFrame() && currItem->asNoteFrame()->notesList().isEmpty()))
137 m_ScMW->slotDocCh(false);
138 currItem->handleModeEditKey(e, m_keyRepeat);
139 if (currItem->isAutoNoteFrame() && currItem->asNoteFrame()->notesList().isEmpty())
140 {
141 PageItem_NoteFrame* noteFrame = currItem->asNoteFrame();
142 if (!noteFrame->isEndNotesFrame() && noteFrame->masterFrame())
143 {
144 PageItem_TextFrame* masterFrame = noteFrame->masterFrame();
145 masterFrame->invalidateLayout(false);
146 masterFrame->updateLayout();
147 }
148 else if (!noteFrame->isEndNotesFrame() && !noteFrame->masterFrame())
149 qDebug() << "Broken note frame without master frame detected";
150 }
151 m_keyRepeat = oldKeyRepeat;
152 m_doc->regionsChanged()->update(QRectF());
153 }
154 m_keyRepeat = false;
155 }
156
157
158
rulerPreview(double base,double xp)159 void CanvasMode_Edit::rulerPreview(double base, double xp)
160 {
161 PageItem* currItem;
162 if (m_doc->appMode == modeEdit && GetItem(&currItem))
163 {
164 QTransform mm = currItem->getTransform();
165 QPointF itPos = mm.map(QPointF(0, currItem->yPos()));
166 QPoint oldP = m_canvas->canvasToLocal(QPointF(mRulerGuide, itPos.y()));
167 mRulerGuide = base + xp;
168 QPoint p = m_canvas->canvasToLocal(QPointF(mRulerGuide, itPos.y() + currItem->height() * mm.m22()));
169 m_canvas->update(QRect(oldP.x()-2, oldP.y(), p.x()+2, p.y()));
170 }
171 }
172
173
drawControls(QPainter * p)174 void CanvasMode_Edit::drawControls(QPainter* p)
175 {
176 commonDrawControls(p, false);
177 PageItem* currItem;
178 if (GetItem(&currItem))
179 {
180 QPen pp = QPen(Qt::blue, 1.0 / m_canvas->scale(), Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
181 pp.setCosmetic(true);
182 PageItem_TextFrame* textframe = currItem->asTextFrame();
183 if (textframe)
184 {
185 if (mRulerGuide >= 0)
186 {
187 QTransform mm = currItem->getTransform();
188 QPointF itPos = mm.map(QPointF(0, currItem->yPos()));
189 p->save();
190 p->setTransform(mm, true);
191 p->setPen(QPen(Qt::blue, 1.0 / m_canvas->scale(), Qt::DashLine, Qt::FlatCap, Qt::MiterJoin));
192 p->setClipRect(QRectF(0.0, 0.0, currItem->width(), currItem->height()));
193 p->setBrush(Qt::NoBrush);
194 p->setRenderHint(QPainter::Antialiasing);
195 p->drawLine(mRulerGuide - itPos.x(), 0, mRulerGuide - itPos.x(), currItem->height() * mm.m22());
196 p->restore();
197 }
198 drawTextCursor(p, textframe);
199 }
200 else if (currItem->isImageFrame())
201 {
202 QTransform mm = currItem->getTransform();
203 p->save();
204 p->setTransform(mm, true);
205 p->setClipRect(QRectF(0.0, 0.0, currItem->width(), currItem->height()));
206 p->setPen(pp);
207 p->setBrush(QColor(0,0,255,10));
208 p->setRenderHint(QPainter::Antialiasing);
209 if (currItem->imageFlippedH())
210 {
211 p->translate(currItem->width(), 0);
212 p->scale(-1.0, 1.0);
213 }
214 if (currItem->imageFlippedV())
215 {
216 p->translate(0, currItem->height());
217 p->scale(1.0, -1.0);
218 }
219 p->translate(currItem->imageXOffset()*currItem->imageXScale(), currItem->imageYOffset()*currItem->imageYScale());
220 p->rotate(currItem->imageRotation());
221 p->drawRect(0, 0, currItem->OrigW*currItem->imageXScale(), currItem->OrigH*currItem->imageYScale());
222 p->translate(currItem->OrigW*currItem->imageXScale() / 2, currItem->OrigH*currItem->imageYScale() / 2);
223 p->scale(1.0 / m_canvas->scale(), 1.0 / m_canvas->scale());
224 QPen pps = QPen(Qt::blue, 1.0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
225 pps.setCosmetic(true);
226 p->setPen(pps);
227 p->drawLine(-10, 0, 10, 0);
228 p->drawLine(0, -10, 0, 10);
229 p->setBrush(QColor(0,0,255,70));
230 p->drawEllipse(QPointF(0.0, 0.0), 10.0, 10.0);
231 p->restore();
232 }
233 }
234 }
235
236
drawTextCursor(QPainter * p,PageItem_TextFrame * textframe)237 void CanvasMode_Edit::drawTextCursor ( QPainter *p, PageItem_TextFrame* textframe )
238 {
239 if ((!m_longCursorTime && m_blinkTime.elapsed() > qApp->cursorFlashTime() / 2 ) ||
240 (m_longCursorTime && m_blinkTime.elapsed() > qApp->cursorFlashTime() )
241 )
242 {
243 m_cursorVisible = !m_cursorVisible;
244 m_blinkTime.restart();
245 m_longCursorTime=false;
246 }
247 if ( m_cursorVisible )
248 {
249 commonDrawTextCursor(p, textframe, QPointF());
250 }
251 }
252
enterEvent(QEvent * e)253 void CanvasMode_Edit::enterEvent(QEvent *e)
254 {
255 if (!m_canvas->m_viewMode.m_MouseButtonPressed)
256 {
257 setModeCursor();
258 }
259 }
260
leaveEvent(QEvent * e)261 void CanvasMode_Edit::leaveEvent(QEvent *e)
262 {
263 }
264
activate(bool fromGesture)265 void CanvasMode_Edit::activate(bool fromGesture)
266 {
267 CanvasMode::activate(fromGesture);
268
269 m_canvas->m_viewMode.m_MouseButtonPressed = false;
270 m_canvas->resetRenderMode();
271 m_doc->DragP = false;
272 m_doc->leaveDrag = false;
273 m_canvas->m_viewMode.operItemMoving = false;
274 m_canvas->m_viewMode.operItemResizing = false;
275 m_view->MidButt = false;
276 Mxp = Myp = -1;
277 Dxp = Dyp = -1;
278 SeRx = SeRy = -1;
279 oldCp = Cp = -1;
280 frameResizeHandle = -1;
281 setModeCursor();
282 if (fromGesture)
283 {
284 m_view->update();
285 }
286 mRulerGuide = -1;
287 PageItem * it(nullptr);
288 if (GetItem(&it))
289 {
290 if (it->isTextFrame())
291 {
292 m_canvas->setupEditHRuler(it, true);
293 if (m_doc->appMode == modeEdit)
294 {
295 m_blinker->start(200);
296 m_blinkTime.start();
297 m_cursorVisible = true;
298 blinkTextCursor();
299 }
300 }
301 }
302 }
303
deactivate(bool forGesture)304 void CanvasMode_Edit::deactivate(bool forGesture)
305 {
306 m_view->setRedrawMarkerShown(false);
307 if (!forGesture)
308 {
309 mRulerGuide = -1;
310 m_blinker->stop();
311 }
312 CanvasMode::deactivate(forGesture);
313 }
314
mouseDoubleClickEvent(QMouseEvent * m)315 void CanvasMode_Edit::mouseDoubleClickEvent(QMouseEvent *m)
316 {
317 m->accept();
318 m_canvas->m_viewMode.m_MouseButtonPressed = false;
319 m_canvas->resetRenderMode();
320 PageItem *currItem = nullptr;
321 if (GetItem(&currItem) && (m_doc->appMode == modeEdit) && currItem->isTextFrame())
322 {
323 //CB if annotation, open the annotation dialog
324 if (currItem->isAnnotation())
325 {
326 // qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
327 m_view->requestMode(submodeAnnotProps);
328 }
329 //otherwise, select between the whitespace
330 else
331 {
332 if (m->modifiers() & Qt::ControlModifier)
333 {
334 int start=0, stop=0;
335
336 if (m->modifiers() & Qt::ShiftModifier)
337 {//Double click with Ctrl+Shift in a frame to select few paragraphs
338 uint oldPar = currItem->itemText.nrOfParagraph(oldCp);
339 uint newPar = currItem->itemText.nrOfParagraph();
340 if (oldPar < newPar)
341 {
342 start = currItem->itemText.startOfParagraph(oldPar);
343 stop = currItem->itemText.endOfParagraph(newPar);
344 }
345 else
346 {
347 start = currItem->itemText.startOfParagraph(newPar);
348 stop = currItem->itemText.endOfParagraph(oldPar);
349 }
350 }
351 else
352 {//Double click with Ctrl in a frame to select a paragraph
353 oldCp = currItem->itemText.cursorPosition();
354 uint nrPar = currItem->itemText.nrOfParagraph(oldCp);
355 start = currItem->itemText.startOfParagraph(nrPar);
356 stop = currItem->itemText.endOfParagraph(nrPar);
357 }
358 currItem->itemText.deselectAll();
359 currItem->itemText.extendSelection(start, stop);
360 currItem->itemText.setCursorPosition(stop);
361 }
362 else if ((currItem->itemText.cursorPosition() < currItem->itemText.length()) && (currItem->itemText.hasMark(currItem->itemText.cursorPosition())))
363 { //invoke edit marker dialog
364 m_ScMW->slotEditMark();
365 return;
366 }
367 else
368 { //Double click in a frame to select a word
369 oldCp = currItem->itemText.cursorPosition();
370 bool validPos = (oldCp >= 0 && oldCp < currItem->itemText.length());
371 if (validPos && currItem->itemText.hasObject(oldCp))
372 {
373 currItem->itemText.select(oldCp, 1, true);
374 InlineFrame iItem = currItem->itemText.object(oldCp);
375 m_ScMW->editInlineStart(iItem.getInlineCharID());
376 }
377 else
378 {
379 currItem->itemText.selectWord(oldCp);
380 }
381 }
382 currItem->HasSel = currItem->itemText.hasSelection();
383 }
384 }
385 else
386 {
387 mousePressEvent(m);
388 return;
389 }
390 }
391
392
mouseMoveEvent(QMouseEvent * m)393 void CanvasMode_Edit::mouseMoveEvent(QMouseEvent *m)
394 {
395 // const double mouseX = m->globalX();
396 // const double mouseY = m->globalY();
397 const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
398
399 double newX, newY;
400 PageItem *currItem;
401 //bool erf = false;
402 m->accept();
403 if (commonMouseMove(m))
404 return;
405 if (GetItem(&currItem))
406 {
407 newX = qRound(mousePointDoc.x()); //m_view->translateToDoc(m->x(), m->y()).x());
408 newY = qRound(mousePointDoc.y()); //m_view->translateToDoc(m->x(), m->y()).y());
409 if (m_doc->DragP)
410 return;
411 if (m_canvas->m_viewMode.m_MouseButtonPressed && (m_doc->appMode == modeEdit))
412 {
413 if (currItem->isImageFrame())
414 {
415 if (m->modifiers() & Qt::ShiftModifier)
416 {
417 m_view->setCursor(IconManager::instance().loadCursor("Rotieren2.png"));
418 QTransform p = currItem->getTransform();
419 p.translate(currItem->imageXOffset()*currItem->imageXScale(), currItem->imageYOffset()*currItem->imageYScale());
420 QPointF rotP = p.map(QPointF(0.0, 0.0));
421 double itemRotation = xy2Deg(mousePointDoc.x() - rotP.x(), mousePointDoc.y() - rotP.y());
422 currItem->setImageRotation(itemRotation);
423 m_canvas->displayRotHUD(m->globalPos(), itemRotation);
424 }
425 else
426 {
427 m_view->setCursor(IconManager::instance().loadCursor("handc.png"));
428 QTransform mm1 = currItem->getTransform();
429 QTransform mm2 = mm1.inverted();
430 QPointF rota = mm2.map(QPointF(newX, newY)) - mm2.map(QPointF(Mxp, Myp));
431 currItem->moveImageInFrame(rota.x() / currItem->imageXScale(), rota.y() / currItem->imageYScale());
432 m_canvas->displayXYHUD(m->globalPos(), currItem->imageXOffset() * currItem->imageXScale(), currItem->imageYOffset() * currItem->imageYScale());
433 }
434 currItem->update();
435 Mxp = newX;
436 Myp = newY;
437 }
438 if (currItem->isTextFrame())
439 {
440 int refStartSel(currItem->asTextFrame()->itemText.startOfSelection());
441 int refEndSel(currItem->asTextFrame()->itemText.endOfSelection());
442 currItem->itemText.deselectAll();
443 currItem->HasSel = false;
444 m_view->slotSetCurs(m->globalPos().x(), m->globalPos().y());
445 //Make sure we don't go here if the old cursor position was not set
446 if (oldCp!=-1 && currItem->itemText.length() > 0)
447 {
448 if (currItem->itemText.cursorPosition() < oldCp)
449 {
450 currItem->itemText.select(currItem->itemText.cursorPosition(), oldCp - currItem->itemText.cursorPosition());
451 currItem->HasSel = true;
452 }
453 if (currItem->itemText.cursorPosition() > oldCp)
454 {
455 currItem->itemText.select(oldCp, currItem->itemText.cursorPosition() - oldCp);
456 currItem->HasSel = true;
457 }
458 }
459 m_ScMW->setCopyCutEnabled(currItem->HasSel);
460 if (currItem->HasSel)
461 {
462 m_canvas->m_viewMode.operTextSelecting = true;
463 if ((refStartSel != currItem->asTextFrame()->itemText.startOfSelection()) ||
464 (refEndSel != currItem->asTextFrame()->itemText.endOfSelection()))
465 {
466 QRectF br(currItem->getBoundingRect());
467 m_canvas->update(QRectF(m_canvas->canvasToLocal(br.topLeft()), br.size() * m_canvas->scale()).toRect());
468 }
469 // We have to call this unconditionally because slotSetCurs() doesn't know selection
470 // when it is called
471 m_doc->scMW()->setTBvals(currItem);
472 }
473 }
474 }
475 if (!m_canvas->m_viewMode.m_MouseButtonPressed)
476 {
477 if (m_doc->m_Selection->isMultipleSelection())
478 {
479 setModeCursor();
480 return;
481 }
482 for (int a = 0; a < m_doc->m_Selection->count(); ++a)
483 {
484 currItem = m_doc->m_Selection->itemAt(a);
485 if (currItem->locked())
486 break;
487 int hitTest = m_canvas->frameHitTest(QPointF(mousePointDoc.x(),mousePointDoc.y()), currItem);
488 if (hitTest >= 0)
489 {
490 if (hitTest == Canvas::INSIDE)
491 {
492 if (currItem->isTextFrame())
493 m_view->setCursor(QCursor(Qt::IBeamCursor));
494 if (currItem->isImageFrame())
495 {
496 if (m->modifiers() & Qt::ShiftModifier)
497 m_view->setCursor(IconManager::instance().loadCursor("Rotieren2.png"));
498 else
499 m_view->setCursor(IconManager::instance().loadCursor("handc.png"));
500 }
501 }
502 }
503 else
504 {
505 // setModeCursor();
506 m_view->setCursor(QCursor(Qt::ArrowCursor));
507 }
508 }
509 }
510 }
511 else
512 {
513 if ((m_canvas->m_viewMode.m_MouseButtonPressed) && (m->buttons() & Qt::LeftButton))
514 {
515 newX = qRound(mousePointDoc.x()); //m_view->translateToDoc(m->x(), m->y()).x());
516 newY = qRound(mousePointDoc.y()); //m_view->translateToDoc(m->x(), m->y()).y());
517 SeRx = newX;
518 SeRy = newY;
519 QPoint startP = m_canvas->canvasToGlobal(QPointF(Mxp, Myp));
520 m_view->redrawMarker->setGeometry(QRect(m_view->mapFromGlobal(startP), m_view->mapFromGlobal(m->globalPos())).normalized());
521 m_view->setRedrawMarkerShown(true);
522 m_view->HaveSelRect = true;
523 return;
524 }
525 }
526 }
527
mousePressEvent(QMouseEvent * m)528 void CanvasMode_Edit::mousePressEvent(QMouseEvent *m)
529 {
530 if (UndoManager::undoEnabled())
531 {
532 SimpleState *ss = dynamic_cast<SimpleState*>(undoManager->getLastUndo());
533 if (ss)
534 ss->set("ETEA", QString(""));
535 else
536 {
537 TransactionState *ts = dynamic_cast<TransactionState*>(undoManager->getLastUndo());
538 if (ts)
539 ss = dynamic_cast<SimpleState*>(ts->last());
540 if (ss)
541 ss->set("ETEA", QString(""));
542 }
543 }
544 // const double mouseX = m->globalX();
545 // const double mouseY = m->globalY();
546 const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
547
548 bool inText;
549 PageItem *currItem;
550 m_canvas->PaintSizeRect(QRect());
551 FPoint npf, npf2;
552 QTransform pm;
553 m_canvas->m_viewMode.m_MouseButtonPressed = true;
554 m_canvas->m_viewMode.operItemMoving = false;
555 m_view->HaveSelRect = false;
556 m_doc->DragP = false;
557 m_doc->leaveDrag = false;
558 // oldClip = 0;
559 m->accept();
560 m_view->registerMousePress(m->globalPos());
561 Mxp = mousePointDoc.x(); //qRound(m->x()/m_canvas->scale() + 0*m_doc->minCanvasCoordinate.x());
562 Myp = mousePointDoc.y(); //qRound(m->y()/m_canvas->scale() + 0*m_doc->minCanvasCoordinate.y());
563 // QRect mpo(m->x()-m_doc->guidesPrefs().grabRad, m->y()-m_doc->guidesPrefs().grabRad, m_doc->guidesPrefs().grabRad*2, m_doc->guidesPrefs().grabRad*2);
564 // mpo.moveBy(qRound(m_doc->minCanvasCoordinate.x() * m_canvas->scale()), qRound(m_doc->minCanvasCoordinate.y() * m_canvas->scale()));
565 SeRx = Mxp;
566 SeRy = Myp;
567 if (m->button() == Qt::MidButton)
568 {
569 m_view->MidButt = true;
570 if (m->modifiers() & Qt::ControlModifier)
571 m_view->DrawNew();
572 return;
573 }
574
575 frameResizeHandle = 0;
576 int oldP=0;
577 if (GetItem(&currItem))
578 {
579 // m_view->slotDoCurs(false);
580 if ((!currItem->locked() || currItem->isTextFrame()) && !currItem->isLine())
581 {
582 FPoint canvasPoint = m_canvas->globalToCanvas(m->globalPos());
583 if (m_canvas->frameHitTest(QPointF(canvasPoint.x(), canvasPoint.y()), currItem) < 0)
584 {
585 m_doc->m_Selection->delaySignalsOn();
586 m_view->deselectItems(true);
587 bool wantNormal = true;
588 if (SeleItem(m))
589 {
590 currItem = m_doc->m_Selection->itemAt(0);
591 if ((currItem->isTextFrame()) || (currItem->isImageFrame()))
592 {
593 m_view->requestMode(modeEdit);
594 wantNormal = false;
595 }
596 else
597 {
598 m_view->requestMode(submodePaintingDone);
599 m_view->setCursor(QCursor(Qt::ArrowCursor));
600 }
601 if (currItem->isTextFrame())
602 {
603 m_view->slotSetCurs(m->globalPos().x(), m->globalPos().y());
604 oldCp = currItem->itemText.cursorPosition();
605 }
606 }
607 else
608 {
609 m_view->requestMode(submodePaintingDone);
610 m_view->setCursor(QCursor(Qt::ArrowCursor));
611 }
612 m_doc->m_Selection->delaySignalsOff();
613 if (wantNormal)
614 {
615 m_view->requestMode(modeNormal);
616 m_view->canvasMode()->mousePressEvent(m);
617 }
618 return;
619 }
620 }
621 oldP = currItem->itemText.cursorPosition();
622 //CB Where we set the cursor for a click in text frame
623 if (currItem->isTextFrame())
624 {
625 inText = m_view->slotSetCurs(m->globalPos().x(), m->globalPos().y());
626 //CB If we clicked outside a text frame to go out of edit mode and deselect the frame
627 if (!inText)
628 {
629 currItem->invalidateLayout();
630 m_view->deselectItems(true);
631 //m_view->slotDoCurs(true);
632 m_view->requestMode(modeNormal);
633 m_view->canvasMode()->mousePressEvent(m);
634 return;
635 }
636
637 if (m->button() != Qt::RightButton)
638 {
639 //currItem->asTextFrame()->deselectAll();
640 //<<CB Add in shift select to text frames
641 if (m->modifiers() & Qt::ShiftModifier)
642 {
643 if (currItem->itemText.hasSelection())
644 {
645 if (currItem->itemText.cursorPosition() < (currItem->itemText.startOfSelection() + currItem->itemText.endOfSelection()) / 2)
646 {
647 if (m->modifiers() & Qt::ControlModifier)
648 currItem->itemText.setCursorPosition(currItem->itemText.startOfParagraph());
649 oldP = currItem->itemText.startOfSelection();
650 }
651 else
652 {
653 if (m->modifiers() & Qt::ControlModifier)
654 currItem->itemText.setCursorPosition(currItem->itemText.endOfParagraph());
655 oldP = currItem->itemText.endOfSelection();
656 }
657 currItem->asTextFrame()->itemText.extendSelection(oldP, currItem->itemText.cursorPosition());
658 oldCp = currItem->itemText.cursorPosition();
659 }
660 else
661 {
662 int dir=1;
663 if (oldCp > currItem->itemText.cursorPosition())
664 dir=-1;
665 if (m->modifiers() & Qt::ControlModifier) //no selection but Ctrl+Shift+click still select paragraphs
666 {
667 if (dir == 1)
668 currItem->itemText.setCursorPosition(currItem->itemText.endOfParagraph());
669 else
670 currItem->itemText.setCursorPosition(currItem->itemText.startOfParagraph());
671 }
672 currItem->asTextFrame()->ExpandSel(oldP);
673 oldCp = oldP;
674 }
675 }
676 else //>>CB
677 {
678 oldCp = currItem->itemText.cursorPosition();
679 currItem->itemText.deselectAll();
680 currItem->HasSel = false;
681 }
682 currItem->emitAllToGUI();
683 if (m->button() == Qt::MidButton)
684 {
685 m_canvas->m_viewMode.m_MouseButtonPressed = false;
686 m_view->MidButt = false;
687 QString cc;
688 cc = QApplication::clipboard()->text(QClipboard::Selection);
689 if (cc.isNull())
690 cc = QApplication::clipboard()->text(QClipboard::Clipboard);
691 if (!cc.isNull())
692 {
693 // K.I.S.S.:
694 currItem->itemText.insertChars(0, cc, true);
695 if (m_doc->docHyphenator->AutoCheck)
696 m_doc->docHyphenator->slotHyphenate(currItem);
697 m_ScMW->BookMarkTxT(currItem);
698 // m_ScMW->outlinePalette->BuildTree();
699 }
700 else
701 {
702 if (ScMimeData::clipboardHasScribusText())
703 m_ScMW->slotEditPaste();
704 }
705 currItem->update();
706 }
707 }
708 }
709 else if (!currItem->isImageFrame() || m_canvas->frameHitTest(QPointF(mousePointDoc.x(),mousePointDoc.y()), currItem) < 0)
710 {
711 m_view->deselectItems(true);
712 if (SeleItem(m))
713 {
714 currItem = m_doc->m_Selection->itemAt(0);
715 if ((currItem->isTextFrame()) || (currItem->isImageFrame()))
716 {
717 m_view->requestMode(modeEdit);
718 }
719 else
720 {
721 m_view->requestMode(submodePaintingDone);
722 m_view->setCursor(QCursor(Qt::ArrowCursor));
723 }
724 }
725 else
726 {
727 m_view->requestMode(submodePaintingDone);
728 m_view->setCursor(QCursor(Qt::ArrowCursor));
729 }
730 }
731 }
732 }
733
734
735
mouseReleaseEvent(QMouseEvent * m)736 void CanvasMode_Edit::mouseReleaseEvent(QMouseEvent *m)
737 {
738 #ifdef GESTURE_FRAME_PREVIEW
739 clearPixmapCache();
740 #endif // GESTURE_FRAME_PREVIEW
741 const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
742 PageItem *currItem;
743 m_canvas->m_viewMode.m_MouseButtonPressed = false;
744 m_canvas->resetRenderMode();
745 m->accept();
746 // m_view->stopDragTimer();
747 if ((GetItem(&currItem)) && (m->button() == Qt::RightButton) && (!m_doc->DragP))
748 {
749 createContextMenu(currItem, mousePointDoc.x(), mousePointDoc.y());
750 return;
751 }
752 if (m_view->moveTimerElapsed() && (GetItem(&currItem)))
753 {
754 // m_view->stopDragTimer();
755 m_canvas->setRenderModeUseBuffer(false);
756 if (!m_doc->m_Selection->isMultipleSelection())
757 {
758 m_doc->setRedrawBounding(currItem);
759 currItem->OwnPage = m_doc->OnPage(currItem);
760 m_canvas->m_viewMode.operItemResizing = false;
761 if (currItem->isLine())
762 m_view->updateContents();
763 }
764 if (m_canvas->m_viewMode.operItemMoving)
765 {
766 m_view->updatesOn(false);
767 if (m_doc->m_Selection->isMultipleSelection())
768 {
769 if (!m_view->groupTransactionStarted())
770 {
771 m_view->startGroupTransaction(Um::Move, "", Um::IMove);
772 }
773 double gx, gy, gh, gw;
774 m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
775 double nx = gx;
776 double ny = gy;
777 if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny,true))
778 {
779 FPoint npx = m_doc->ApplyGridF(FPoint(gx, gy));
780 FPoint npw = m_doc->ApplyGridF(FPoint(gx + gw, gy + gh));
781 if ((fabs(gx - npx.x())) > (fabs((gx + gw) - npw.x())))
782 nx = npw.x() - gw;
783 else
784 nx = npx.x();
785 if ((fabs(gy - npx.y())) > (fabs((gy + gh) - npw.y())))
786 ny = npw.y() - gh;
787 else
788 ny = npx.y();
789 }
790 m_doc->moveGroup(nx - gx, ny - gy);
791 m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
792 nx = gx + gw;
793 ny = gy + gh;
794 if (m_doc->ApplyGuides(&nx, &ny) || m_doc->ApplyGuides(&nx,&ny,true))
795 m_doc->moveGroup(nx - (gx + gw), ny - (gy + gh));
796 m_doc->m_Selection->setGroupRect();
797 }
798 else
799 {
800 currItem = m_doc->m_Selection->itemAt(0);
801 if (m_doc->SnapGrid)
802 {
803 double nx = currItem->xPos();
804 double ny = currItem->yPos();
805 if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny,true))
806 {
807 double gx, gy, gh, gw;
808 m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
809 FPoint npx = m_doc->ApplyGridF(FPoint(gx, gy));
810 FPoint npw = m_doc->ApplyGridF(FPoint(gx + gw, gy + gh));
811 if ((fabs(gx - npx.x())) > (fabs((gx + gw) - npw.x())))
812 nx = npw.x() - gw;
813 else
814 nx = npx.x();
815 if ((fabs(gy - npx.y())) > (fabs((gy + gh) - npw.y())))
816 ny = npw.y() - gh;
817 else
818 ny = npx.y();
819 }
820 m_doc->moveItem(nx-currItem->xPos(), ny-currItem->yPos(), currItem);
821 }
822 else
823 m_doc->moveItem(0, 0, currItem);
824 }
825 m_canvas->m_viewMode.operItemMoving = false;
826 if (m_doc->m_Selection->isMultipleSelection())
827 {
828 double gx, gy, gh, gw;
829 m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
830 FPoint maxSize(gx + gw + m_doc->scratch()->right(), gy + gh + m_doc->scratch()->bottom());
831 FPoint minSize(gx - m_doc->scratch()->left(), gy - m_doc->scratch()->top());
832 m_doc->adjustCanvas(minSize, maxSize);
833 }
834 m_doc->setRedrawBounding(currItem);
835 currItem->OwnPage = m_doc->OnPage(currItem);
836 if (currItem->OwnPage != -1)
837 {
838 m_doc->setCurrentPage(m_doc->Pages->at(currItem->OwnPage));
839 m_view->m_ScMW->slotSetCurrentPage(currItem->OwnPage);
840 }
841 //CB done with emitAllToGUI
842 //emit HaveSel();
843 //EmitValues(currItem);
844 //CB need this for? a moved item will send its new data with the new xpos/ypos emits
845 //CB TODO And what if we have dragged to a new page. Items X&Y are not updated anyway now
846 //currItem->emitAllToGUI();
847 m_view->updatesOn(true);
848 m_view->updateContents();
849 }
850 }
851 //CB Drag selection performed here
852 if ((m_doc->m_Selection->isEmpty()) && (m_view->HaveSelRect) && (!m_view->MidButt))
853 {
854 QRectF Sele = QRectF(Dxp, Dyp, SeRx-Dxp, SeRy-Dyp).normalized();
855 if (!m_doc->masterPageMode())
856 {
857 uint docPagesCount=m_doc->Pages->count();
858 uint docCurrPageNo=m_doc->currentPageNumber();
859 for (uint i = 0; i < docPagesCount; ++i)
860 {
861 if (QRectF(m_doc->Pages->at(i)->xOffset(), m_doc->Pages->at(i)->yOffset(), m_doc->Pages->at(i)->width(), m_doc->Pages->at(i)->height()).intersects(Sele))
862 {
863 if (docCurrPageNo != i)
864 {
865 m_doc->setCurrentPage(m_doc->Pages->at(i));
866 m_view->m_ScMW->slotSetCurrentPage(i);
867 }
868 break;
869 }
870 }
871 m_view->setRulerPos(m_view->contentsX(), m_view->contentsY());
872 }
873 int docItemCount=m_doc->Items->count();
874 if (docItemCount != 0)
875 {
876 m_doc->m_Selection->delaySignalsOn();
877 for (int a = 0; a < docItemCount; ++a)
878 {
879 PageItem* docItem = m_doc->Items->at(a);
880 QTransform p;
881 m_canvas->Transform(docItem, p);
882 QRegion apr = QRegion(docItem->Clip * p);
883 QRect apr2(docItem->getRedrawBounding(1.0));
884 if ((m_doc->masterPageMode()) && (docItem->OnMasterPage != m_doc->currentPage()->pageName()))
885 continue;
886 if (((Sele.contains(apr.boundingRect())) || (Sele.contains(apr2))) && m_doc->canSelectItemOnLayer(docItem->m_layerID))
887 {
888 bool redrawSelection=false;
889 m_view->selectItemByNumber(a, redrawSelection);
890 }
891 }
892 m_doc->m_Selection->delaySignalsOff();
893 if (m_doc->m_Selection->count() > 1)
894 {
895 double x, y, w, h;
896 m_doc->m_Selection->getGroupRect(&x, &y, &w, &h);
897 m_view->getGroupRectScreen(&x, &y, &w, &h);
898 }
899 }
900 m_view->HaveSelRect = false;
901 m_view->setRedrawMarkerShown(false);
902 m_view->updateContents();
903 }
904 if (GetItem(&currItem))
905 {
906 if (m_doc->m_Selection->count() > 1)
907 {
908 double x, y, w, h;
909 m_doc->m_Selection->getGroupRect(&x, &y, &w, &h);
910 m_canvas->m_viewMode.operItemMoving = false;
911 m_canvas->m_viewMode.operItemResizing = false;
912 m_view->updateContents(QRect(static_cast<int>(x-5), static_cast<int>(y-5), static_cast<int>(w+10), static_cast<int>(h+10)));
913 }
914 /*else
915 currItem->emitAllToGUI();*/
916 }
917 m_canvas->setRenderModeUseBuffer(false);
918 m_doc->DragP = false;
919 m_doc->leaveDrag = false;
920 m_canvas->m_viewMode.operItemMoving = false;
921 m_canvas->m_viewMode.operItemResizing = false;
922 m_view->MidButt = false;
923 if (m_view->groupTransactionStarted())
924 {
925 for (int i = 0; i < m_doc->m_Selection->count(); ++i)
926 m_doc->m_Selection->itemAt(i)->checkChanges(true);
927 m_view->endGroupTransaction();
928 }
929 for (int i = 0; i < m_doc->m_Selection->count(); ++i)
930 m_doc->m_Selection->itemAt(i)->checkChanges(true);
931 //Commit drag created items to undo manager.
932 if (m_doc->m_Selection->itemAt(0)!=nullptr)
933 {
934 m_doc->itemAddCommit(m_doc->m_Selection->itemAt(0));
935 }
936 //Make sure the Zoom spinbox and page selector don't have focus if we click on the canvas
937 m_view->m_ScMW->zoomSpinBox->clearFocus();
938 m_view->m_ScMW->pageSelector->clearFocus();
939 if (m_doc->m_Selection->itemAt(0) != nullptr) // is there the old clip stored for the undo action
940 {
941 currItem = m_doc->m_Selection->itemAt(0);
942 m_doc->nodeEdit.finishTransaction(currItem);
943 }
944 if (GetItem(&currItem) && currItem->isTextFrame())
945 m_ScMW->setCopyCutEnabled(currItem->itemText.hasSelection());
946 }
947
948 //CB-->Doc/Fix
SeleItem(QMouseEvent * m)949 bool CanvasMode_Edit::SeleItem(QMouseEvent *m)
950 {
951 const unsigned SELECT_IN_GROUP = Qt::AltModifier;
952 const unsigned SELECT_MULTIPLE = Qt::ShiftModifier;
953 const unsigned SELECT_BENEATH = Qt::ControlModifier;
954 QTransform p;
955 QRectF mpo;
956 PageItem *currItem;
957 m_canvas->m_viewMode.m_MouseButtonPressed = true;
958 FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
959 Mxp = mousePointDoc.x(); //m->x()/m_canvas->scale());
960 Myp = mousePointDoc.y(); //m->y()/m_canvas->scale());
961 double grabRadius = m_doc->guidesPrefs().grabRadius / m_canvas->scale();
962 int MxpS = static_cast<int>(mousePointDoc.x()); //m->x()/m_canvas->scale() + 0*m_doc->minCanvasCoordinate.x());
963 int MypS = static_cast<int>(mousePointDoc.y()); //m->y()/m_canvas->scale() + 0*m_doc->minCanvasCoordinate.y());
964 mpo = QRectF(Mxp-grabRadius, Myp-grabRadius, grabRadius*2, grabRadius*2);
965 // mpo.translate(m_doc->minCanvasCoordinate.x() * m_canvas->scale(), m_doc->minCanvasCoordinate.y() * m_canvas->scale());
966 m_doc->nodeEdit.deselect();
967 // int a;
968 if (!m_doc->masterPageMode())
969 {
970 int pgNum = -1;
971 int docPageCount = static_cast<int>(m_doc->Pages->count() - 1);
972 MarginStruct pageBleeds;
973 bool drawBleed = false;
974 if (!m_doc->bleeds()->isNull() && m_doc->guidesPrefs().showBleed)
975 drawBleed = true;
976 for (int a = docPageCount; a > -1; a--)
977 {
978 if (drawBleed)
979 m_doc->getBleeds(a, pageBleeds);
980 int x = static_cast<int>(m_doc->Pages->at(a)->xOffset() - pageBleeds.left());
981 int y = static_cast<int>(m_doc->Pages->at(a)->yOffset() - pageBleeds.top());
982 int w = static_cast<int>(m_doc->Pages->at(a)->width() + pageBleeds.left() + pageBleeds.right());
983 int h = static_cast<int>(m_doc->Pages->at(a)->height() + pageBleeds.bottom() + pageBleeds.top());
984 if (QRect(x, y, w, h).contains(MxpS, MypS))
985 {
986 pgNum = static_cast<int>(a);
987 if (drawBleed) // check again if its really on the correct page
988 {
989 for (int a2 = docPageCount; a2 > -1; a2--)
990 {
991 int xn = static_cast<int>(m_doc->Pages->at(a2)->xOffset());
992 int yn = static_cast<int>(m_doc->Pages->at(a2)->yOffset());
993 int wn = static_cast<int>(m_doc->Pages->at(a2)->width());
994 int hn = static_cast<int>(m_doc->Pages->at(a2)->height());
995 if (QRect(xn, yn, wn, hn).contains(MxpS, MypS))
996 {
997 pgNum = static_cast<int>(a2);
998 break;
999 }
1000 }
1001 }
1002 break;
1003 }
1004 }
1005 if (pgNum >= 0)
1006 {
1007 if (m_doc->currentPageNumber() != pgNum)
1008 {
1009 m_doc->setCurrentPage(m_doc->Pages->at(pgNum));
1010 m_view->m_ScMW->slotSetCurrentPage(pgNum);
1011 m_view->DrawNew();
1012 }
1013 }
1014 m_view->setRulerPos(m_view->contentsX(), m_view->contentsY());
1015 }
1016
1017 currItem = nullptr;
1018 if ((m->modifiers() & SELECT_BENEATH) != 0)
1019 {
1020 for (int i = 0; i < m_doc->m_Selection->count(); ++i)
1021 {
1022 if (m_canvas->frameHitTest(QPointF(mousePointDoc.x(), mousePointDoc.y()), m_doc->m_Selection->itemAt(i)) >= 0)
1023 {
1024 currItem = m_doc->m_Selection->itemAt(i);
1025 m_doc->m_Selection->removeItem(currItem);
1026 break;
1027 }
1028 }
1029 }
1030 else if ( (m->modifiers() & SELECT_MULTIPLE) == Qt::NoModifier)
1031 {
1032 m_view->deselectItems(false);
1033 }
1034 currItem = m_canvas->itemUnderCursor(m->globalPos(), currItem, (m->modifiers() & SELECT_IN_GROUP));
1035 if (currItem)
1036 {
1037 m_doc->m_Selection->delaySignalsOn();
1038 if (m_doc->m_Selection->containsItem(currItem))
1039 {
1040 m_doc->m_Selection->removeItem(currItem);
1041 }
1042 else
1043 {
1044 //CB: If we have a selection but the user clicks with control on another item that is not below the current
1045 //then clear and select the new item
1046 if ((m->modifiers() == SELECT_BENEATH) && m_canvas->frameHitTest(QPointF(mousePointDoc.x(),mousePointDoc.y()), currItem) >= 0)
1047 m_doc->m_Selection->clear();
1048 //CB: #7186: This was prependItem, does not seem to need to be anymore with current select code
1049 m_doc->m_Selection->addItem(currItem);
1050 if ( (m->modifiers() & SELECT_IN_GROUP) && (!currItem->isGroup()))
1051 {
1052 currItem->isSingleSel = true;
1053 }
1054 }
1055 m_canvas->update();
1056 m_doc->m_Selection->delaySignalsOff();
1057 if (m_doc->m_Selection->count() > 1)
1058 {
1059 double x, y, w, h;
1060 m_doc->m_Selection->getGroupRect(&x, &y, &w, &h);
1061 m_view->getGroupRectScreen(&x, &y, &w, &h);
1062 }
1063 if (m_doc->m_Selection->count() == 1)
1064 {
1065 frameResizeHandle = m_canvas->frameHitTest(QPointF(mousePointDoc.x(),mousePointDoc.y()), currItem);
1066 if ((frameResizeHandle == Canvas::INSIDE) && (!currItem->locked()))
1067 m_view->setCursor(QCursor(Qt::SizeAllCursor));
1068 }
1069 else
1070 {
1071 m_view->setCursor(QCursor(Qt::SizeAllCursor));
1072 m_canvas->m_viewMode.operItemResizing = false;
1073 }
1074 return true;
1075 }
1076 m_doc->m_Selection->connectItemToGUI();
1077 if ( !(m->modifiers() & SELECT_MULTIPLE))
1078 m_view->deselectItems(true);
1079 return false;
1080 }
1081
createContextMenu(PageItem * currItem,double mx,double my)1082 void CanvasMode_Edit::createContextMenu(PageItem* currItem, double mx, double my)
1083 {
1084 ContextMenu* cmen=nullptr;
1085 m_view->setCursor(QCursor(Qt::ArrowCursor));
1086 m_view->setObjectUndoMode();
1087 Mxp = mx;
1088 Myp = my;
1089 if (currItem!=nullptr)
1090 cmen = new ContextMenu(*(m_doc->m_Selection), m_ScMW, m_doc);
1091 else
1092 cmen = new ContextMenu(m_ScMW, m_doc, mx, my);
1093 if (cmen)
1094 cmen->exec(QCursor::pos());
1095 m_view->setGlobalUndoMode();
1096 delete cmen;
1097 }
1098