1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2005-02-14
7  * Description : a widget to insert a text over an image.
8  *
9  * Copyright (C) 2005-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C) 2006-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
11  *
12  * This program is free software; you can redistribute it
13  * and/or modify it under the terms of the GNU General
14  * Public License as published by the Free Software Foundation;
15  * either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * ============================================================ */
24 
25 #include "inserttextwidget.h"
26 
27 // Qt includes
28 
29 #include <QFont>
30 #include <QFontMetrics>
31 #include <QMouseEvent>
32 #include <QPaintEvent>
33 #include <QPainter>
34 #include <QPixmap>
35 #include <QResizeEvent>
36 
37 namespace DigikamEditorInsertTextToolPlugin
38 {
39 
40 class Q_DECL_HIDDEN InsertTextWidget::Private
41 {
42 public:
43 
Private()44     explicit Private()
45       : currentMoving   (false),
46         textBorder      (false),
47         textTransparent (false),
48         alignMode       (0),
49         textOpacity     (0),
50         h               (0),
51         textRotation    (0),
52         transparency    (0),
53         w               (0),
54         xpos            (0),
55         ypos            (0),
56         pixmap          (nullptr),
57         iface           (nullptr)
58     {
59     }
60 
61     bool        currentMoving;
62     bool        textBorder;
63     bool        textTransparent;
64 
65     int         alignMode;
66     int         textOpacity;
67     int         h;
68     int         textRotation;
69     int         transparency;
70     int         w;
71     int         xpos;
72     int         ypos;
73 
74     QColor      backgroundColor;   // For text
75     QColor      bgColor;           // For Pixmap
76     QColor      textColor;
77 
78     QFont       textFont;
79 
80     QPixmap*    pixmap;
81 
82     QRect       positionHint;
83     QRect       rect;
84     QRect       textRect;
85 
86     QString     textString;
87 
88     ImageIface* iface;
89 };
90 
InsertTextWidget(int w,int h,QWidget * const parent)91 InsertTextWidget::InsertTextWidget(int w, int h, QWidget* const parent)
92     : QWidget(parent),
93       d      (new Private)
94 {
95     d->currentMoving   = false;
96     d->bgColor         = palette().color(QPalette::Window);
97     d->backgroundColor = QColor(0xCC, 0xCC, 0xCC);
98     d->transparency    = 210;
99 
100     d->iface  = new ImageIface(QSize(w, h));
101     d->w      = d->iface->previewSize().width();
102     d->h      = d->iface->previewSize().height();
103     d->pixmap = new QPixmap(w, h);
104     d->pixmap->fill(d->bgColor);
105 
106     setMinimumSize(w, h);
107     setMouseTracking(true);
108     setAttribute(Qt::WA_DeleteOnClose);
109 
110     d->rect     = QRect(width()/2-d->w/2, height()/2-d->h/2, d->w, d->h);
111     d->textRect = QRect();
112 }
113 
~InsertTextWidget()114 InsertTextWidget::~InsertTextWidget()
115 {
116     delete d->iface;
117     delete d->pixmap;
118     delete d;
119 }
120 
imageIface() const121 ImageIface* InsertTextWidget::imageIface() const
122 {
123     return d->iface;
124 }
125 
resetEdit()126 void InsertTextWidget::resetEdit()
127 {
128     // signal this needs to be filled by makePixmap
129 
130     d->textRect = QRect();
131     makePixmap();
132     repaint();
133 }
134 
setText(const QString & text,const QFont & font,const QColor & color,int opacity,int alignMode,bool border,bool transparent,int rotation)135 void InsertTextWidget::setText(const QString& text, const QFont& font, const QColor& color, int opacity,
136                                int alignMode, bool border, bool transparent, int rotation)
137 {
138     d->textString      = text;
139     d->textColor       = color;
140     d->textOpacity     = opacity;
141     d->textBorder      = border;
142     d->textTransparent = transparent;
143     d->textRotation    = rotation;
144 
145     switch (alignMode)
146     {
147         case ALIGN_LEFT:
148             d->alignMode = Qt::AlignLeft;
149             break;
150 
151         case ALIGN_RIGHT:
152             d->alignMode = Qt::AlignRight;
153             break;
154 
155         case ALIGN_CENTER:
156             d->alignMode = Qt::AlignHCenter;
157             break;
158 
159         case ALIGN_BLOCK:
160             d->alignMode = Qt::AlignJustify;
161             break;
162     }
163 
164     // Center text if top left corner text area is not visible.
165 
166 /*
167     if (d->textFont.pointSize() != font.pointSize() &&
168         !rect().contains( d->textRect.x(), d->textRect.y()))
169     {
170         d->textFont = font;
171         resetEdit();
172         return;
173     }
174 */
175 
176     d->textFont = font;
177 
178     makePixmap();
179     repaint();
180 }
181 
setBackgroundColor(const QColor & bg)182 void InsertTextWidget::setBackgroundColor(const QColor& bg)
183 {
184     d->bgColor = bg;
185     makePixmap();
186     repaint();
187 }
188 
setPositionHint(const QRect & hint)189 void InsertTextWidget::setPositionHint(const QRect& hint)
190 {
191     // interpreted by composeImage
192 
193     d->positionHint = hint;
194 
195     if (d->textRect.isValid())
196     {
197         // invalidate current position so that hint is certainly interpreted
198 
199         d->textRect = QRect();
200         makePixmap();
201         repaint();
202     }
203 }
204 
getPositionHint() const205 QRect InsertTextWidget::getPositionHint() const
206 {
207     QRect hint;
208 
209     if (d->textRect.isValid())
210     {
211         // We normalize on the size of the image, but we store as int. Precision loss is no problem.
212 
213         hint.setX(     (int) ((float)(d->textRect.x() - d->rect.x())     / (float)d->rect.width()  * 10000.0));
214         hint.setY(     (int) ((float)(d->textRect.y() - d->rect.y())     / (float)d->rect.height() * 10000.0));
215         hint.setWidth( (int) ((float)d->textRect.width()  / (float)d->rect.width()  * 10000.0));
216         hint.setHeight((int) ((float)d->textRect.height() / (float)d->rect.height() * 10000.0));
217     }
218 
219     return hint;
220 }
221 
makeInsertText()222 DImg InsertTextWidget::makeInsertText()
223 {
224     int orgW     = d->iface->originalSize().width();
225     int orgH     = d->iface->originalSize().height();
226     float ratioW = (float)orgW/(float)d->w;
227     float ratioH = (float)orgH/(float)d->h;
228 
229     int x, y;
230 
231     if (d->textRect.isValid())
232     {
233         // convert from widget to image coordinates, then to original size
234 
235         x = qRound((d->textRect.x() - d->rect.x()) * ratioW);
236         y = qRound((d->textRect.y() - d->rect.y()) * ratioH);
237     }
238     else
239     {
240         x = -1;
241         y = -1;
242     }
243 
244     // Get original image
245 
246     DImg image      = d->iface->original()->copy();
247     int borderWidth = qMax(1, qRound(ratioW));
248 
249     // compose and draw result on image
250 
251     composeImage(&image, nullptr, x, y,
252                  d->textFont, d->textFont.pointSizeF(),
253                  d->textRotation, d->textColor, d->textOpacity,
254                  d->alignMode, d->textString, d->textTransparent, d->backgroundColor,
255                  d->textBorder ? BORDER_NORMAL : BORDER_NONE, borderWidth, borderWidth);
256 
257     return image;
258 }
259 
makePixmap()260 void InsertTextWidget::makePixmap()
261 {
262     int orgW = d->iface->originalSize().width();
263     int orgH = d->iface->originalSize().height();
264     float ratioW = (float)d->w / (float)orgW;
265     float ratioH = (float)d->h / (float)orgH;
266 
267     int x, y;
268 
269     if (d->textRect.isValid())
270     {
271         // convert from widget to image coordinates
272 
273         x = d->textRect.x() - d->rect.x();
274         y = d->textRect.y() - d->rect.y();
275     }
276     else
277     {
278         x = -1;
279         y = -1;
280     }
281 
282     // get preview image data
283 
284     DImg image = d->iface->preview();
285     image.setIccProfile(d->iface->original()->getIccProfile());
286 
287     // paint pixmap for drawing this widget
288     // First, fill with background color
289 
290     d->pixmap->fill(d->bgColor);
291     QPainter p(d->pixmap);
292 
293     // Convert image to pixmap and draw it
294 
295     QPixmap imagePixmap = d->iface->convertToPixmap(image);
296     p.drawPixmap(d->rect.x(), d->rect.y(),
297                  imagePixmap, 0, 0, imagePixmap.width(), imagePixmap.height());
298 
299     // prepare painter for use by compose image
300 
301     p.setClipRect(d->rect);
302     p.translate(d->rect.x(), d->rect.y());
303 
304     int borderWidth = qMax(1, qRound(ratioW));
305 
306     // compose image and draw result directly on pixmap, with correct offset
307 
308     QRect textRect = composeImage(&image, &p, x, y,
309                                   d->textFont, d->textFont.pointSizeF(),
310                                   d->textRotation, d->textColor, d->textOpacity,
311                                   d->alignMode, d->textString, d->textTransparent, d->backgroundColor,
312                                   d->textBorder ? BORDER_NORMAL : BORDER_SUPPORT, borderWidth, borderWidth,
313                                   (ratioW > ratioH) ? ratioW : ratioH);
314 
315     p.end();
316 
317     // store new text rectangle
318     // convert from image to widget coordinates
319 
320     d->textRect.setX(textRect.x() + d->rect.x());
321     d->textRect.setY(textRect.y() + d->rect.y());
322     d->textRect.setSize(textRect.size());
323 }
324 
325 /**
326    Take data from image, draw text at x|y with specified parameters.
327    If destPainter is null, draw to image,
328    if destPainter is not null, draw directly using the painter.
329    Returns modified area of image.
330 */
composeImage(DImg * const image,QPainter * const destPainter,int x,int y,QFont font,float pointSize,int textRotation,QColor textColor,int textOpacity,int alignMode,const QString & textString,bool transparentBackground,QColor backgroundColor,BorderMode borderMode,int borderWidth,int spacing,float fontScale)331 QRect InsertTextWidget::composeImage(DImg* const image, QPainter* const destPainter,
332                                      int x, int y,
333                                      QFont font, float pointSize, int textRotation, QColor textColor,
334                                      int textOpacity, int alignMode, const QString& textString,
335                                      bool transparentBackground, QColor backgroundColor,
336                                      BorderMode borderMode, int borderWidth, int spacing, float fontScale)
337 {
338     /*
339         The problem we have to solve is that we have no pixel access to font rendering,
340         we have to let Qt do the drawing. On the other hand we need to support 16 bit, which
341         cannot be done with QPixmap.
342         The current solution cuts out the text area, lets Qt do its drawing, converts back and blits to original.
343     */
344 
345     int maxWidth, maxHeight;
346 
347     if (x == -1 && y == -1)
348     {
349         maxWidth  = image->width();
350         maxHeight = image->height();
351     }
352     else
353     {
354         maxWidth  = image->width()  - x;
355         maxHeight = image->height() - y;
356     }
357 
358     fontScale = qMax(0.01f, fontScale);
359 
360     // find out size of the area that we are drawing to
361 
362     font.setPointSizeF(pointSize);
363     QFontMetrics fontMt(font);
364     QRect fontRect = fontMt.boundingRect(0, 0,
365                                          qRound(maxWidth  / fontScale),
366                                          qRound(maxHeight / fontScale),
367                                          alignMode, textString);
368 
369     fontRect.setWidth(qRound(fontRect.width()   * fontScale));
370     fontRect.setHeight(qRound(fontRect.height() * fontScale));
371 
372     if (!fontRect.isValid())
373     {
374         return QRect();
375     }
376 
377     int fontWidth, fontHeight;
378 
379     switch (textRotation)
380     {
381         case ROTATION_NONE:
382         case ROTATION_180:
383         default:
384             fontWidth = fontRect.width();
385             fontHeight = fontRect.height();
386             break;
387 
388         case ROTATION_90:
389         case ROTATION_270:
390             fontWidth = fontRect.height();
391             fontHeight = fontRect.width();
392             break;
393     }
394 
395     // x, y == -1 means that we have to find a good initial position for the text here
396 
397     if ((x == -1) && (y == -1))
398     {
399         int boxWidth  = fontWidth  + 2 * borderWidth + 2 * spacing;
400         int boxHeight = fontHeight + 2 * borderWidth + 2 * spacing;
401 
402         // was a valid position hint stored from last use?
403 
404         if (d->positionHint.isValid())
405         {
406             // We assume that people tend to orient text along the edges,
407             // so we do some guessing so that positions such as "in the lower right corner"
408             // will be remembered across different image sizes.
409 
410             // get relative positions
411 
412             float fromTop    =       (float)d->positionHint.top()    / 10000.0;
413             float fromBottom = 1.0 - (float)d->positionHint.bottom() / 10000.0;
414             float fromLeft   =       (float)d->positionHint.left()   / 10000.0;
415             float fromRight  = 1.0 - (float)d->positionHint.right()  / 10000.0;
416 
417             // calculate horizontal position
418 
419             if (fromLeft < fromRight)
420             {
421                 x = qRound(fromLeft * maxWidth);
422 
423                 // we are placing from the smaller distance,
424                 // so if now the larger distance is actually too small,
425                 // fall back to standard placement, nothing to lose.
426 
427                 if ((x + boxWidth) > maxWidth)
428                 {
429                     x = qMax( (maxWidth - boxWidth) / 2, 0);
430                 }
431             }
432             else
433             {
434                 x = maxWidth - qRound(fromRight * maxWidth) - boxWidth;
435 
436                 if (x < 0)
437                 {
438                     x = qMax( (maxWidth - boxWidth) / 2, 0);
439                 }
440             }
441 
442             // calculate vertical position
443 
444             if (fromTop < fromBottom)
445             {
446                 y = qRound(fromTop * maxHeight);
447 
448                 if (y + boxHeight > maxHeight)
449                 {
450                     y = qMax( (maxHeight - boxHeight) / 2, 0);
451                 }
452             }
453             else
454             {
455                 y = maxHeight - qRound(fromBottom * maxHeight) - boxHeight;
456 
457                 if (y < 0)
458                 {
459                     y = qMax( (maxHeight - boxHeight) / 2, 0);
460                 }
461             }
462 
463             if (!QRect(x, y, boxWidth, boxHeight).
464                  intersects(QRect(0, 0, maxWidth, maxHeight)))
465             {
466                 // emergency fallback - nothing is visible
467 
468                 x = qMax( (maxWidth - boxWidth)   / 2, 0);
469                 y = qMax( (maxHeight - boxHeight) / 2, 0);
470             }
471 
472             // invalidate position hint, use only once
473 
474             d->positionHint = QRect();
475         }
476         else
477         {
478             // use standard position
479 
480             x = qMax( (maxWidth - boxWidth)   / 2, 0);
481             y = qMax( (maxHeight - boxHeight) / 2, 0);
482         }
483     }
484 
485     // create a rectangle relative to image
486 
487     QRect drawRect(x, y, fontWidth + 2 * borderWidth + 2 * spacing, fontHeight + 2 * borderWidth  + 2 * spacing);
488 
489     // create a rectangle relative to textArea, excluding the border
490 
491     QRect textAreaBackgroundRect(borderWidth, borderWidth, fontWidth + 2 * spacing, fontHeight + 2 * spacing);
492 
493     // create a rectangle relative to textArea, excluding the border and spacing
494 
495     QRect textAreaTextRect(borderWidth + spacing, borderWidth + spacing, fontWidth, fontHeight);
496 
497     // create a rectangle relative to textArea, including the border,
498     // for drawing the rectangle, taking into account that the width of the QPen goes in and out in equal parts
499 
500     QRect textAreaDrawRect(borderWidth / 2, borderWidth / 2, fontWidth + borderWidth + 2 * spacing,
501                            fontHeight + borderWidth + 2 * spacing);
502 
503     // cut out the text area
504 
505     DImg textArea = image->copy(drawRect);
506 
507     if (textArea.isNull())
508     {
509         return QRect();
510     }
511 
512     // compose semi-transparent background over textArea
513 
514     DColorComposer* const composer = DColorComposer::getComposer(DColorComposer::PorterDuffNone);
515 
516     if (transparentBackground)
517     {
518         DImg transparentLayer(textAreaBackgroundRect.width(), textAreaBackgroundRect.height(), textArea.sixteenBit(), true);
519         DColor transparent(backgroundColor);
520         transparent.setAlpha(d->transparency);
521 
522         if (image->sixteenBit())
523         {
524             transparent.convertToSixteenBit();
525         }
526 
527         transparentLayer.fill(transparent);
528         textArea.bitBlendImage(composer, &transparentLayer, 0, 0, transparentLayer.width(), transparentLayer.height(),
529                                textAreaBackgroundRect.x(), textAreaBackgroundRect.y());
530     }
531 
532     DImg textNotDrawn;
533 
534     if (textArea.sixteenBit())
535     {
536         textNotDrawn = textArea.copy();
537         textNotDrawn.convertToEightBit();
538     }
539     else
540     {
541         textNotDrawn = textArea;
542     }
543 
544     // We have no direct pixel access to font rendering, so now we need to use Qt/X11 for the drawing
545 
546     // convert text area to pixmap
547 
548     QPixmap pixmap;
549 
550     if (destPainter)
551     {
552         // We working on tool preview, deal with CM as well
553 
554         pixmap = d->iface->convertToPixmap(textNotDrawn);
555     }
556     else
557     {
558         // We working on target image. Do no apply double CM adjustment here.
559 
560         pixmap = textNotDrawn.convertToPixmap();
561     }
562 
563     int fontScaleWidth  = qRound(fontWidth  / fontScale);
564     int fontScaleHeight = qRound(fontHeight / fontScale);
565 
566     QPixmap textPixmap(fontScaleWidth, fontScaleHeight);
567     textPixmap.fill(Qt::transparent);
568 
569     QPainter tp(&textPixmap);
570     tp.setOpacity((qreal)textOpacity / 100.0);
571     tp.setPen(QPen(textColor, 1));
572     tp.setFont(font);
573 
574     switch (textRotation)
575     {
576         case ROTATION_NONE:
577             tp.drawText(0, 0, fontScaleWidth, fontScaleHeight,
578                          alignMode, textString);
579             break;
580         case ROTATION_90:
581             tp.translate(fontScaleWidth, 0);
582             tp.rotate(90.0);
583             tp.drawText(0, 0, fontScaleHeight, fontScaleWidth,
584                         alignMode, textString);
585             break;
586         case ROTATION_180:
587             tp.translate(fontScaleWidth, fontScaleHeight);
588             tp.rotate(180.0);
589             tp.drawText(0, 0, fontScaleWidth, fontScaleHeight,
590                         alignMode, textString);
591             break;
592         case ROTATION_270:
593             tp.translate(0, fontScaleHeight);
594             tp.rotate(270.0);
595             tp.drawText(0, 0, fontScaleHeight, fontScaleWidth,
596                         alignMode, textString);
597             break;
598     }
599 
600     tp.end();
601 
602     // paint on pixmap
603 
604     QPainter p(&pixmap);
605 
606     p.drawPixmap(textAreaTextRect, textPixmap.scaled(fontWidth,
607                                                      fontHeight,
608                                                      Qt::IgnoreAspectRatio,
609                                                      Qt::SmoothTransformation));
610     // Drawing rectangle around text.
611 
612     if (borderMode == BORDER_NORMAL)      // Decorative border using text color.
613     {
614         p.setOpacity((qreal)textOpacity / 100.0);
615         p.setPen(QPen(textColor, borderWidth, Qt::SolidLine,
616                       Qt::SquareCap, Qt::RoundJoin));
617         p.drawRect(textAreaDrawRect);
618     }
619     else if (borderMode == BORDER_SUPPORT)  // Make simple dot line border to help user.
620     {
621         p.setPen(QPen(Qt::white, 1, Qt::SolidLine));
622         p.drawRect(textAreaDrawRect);
623         p.setPen(QPen(Qt::red, 1, Qt::DotLine));
624         p.drawRect(textAreaDrawRect);
625     }
626 
627     p.end();
628 
629     if (!destPainter)
630     {
631         // convert to QImage, then to DImg
632 
633         QImage pixmapImage = pixmap.toImage();
634         DImg textDrawn(pixmapImage.width(), pixmapImage.height(), false, true, pixmapImage.bits());
635 
636         // This does not work: during the conversion, colors are altered significantly (diffs of 1 to 10 in each component),
637         // so we cannot find out which pixels have actually been touched.
638 /*
639         // Compare the result of drawing with the previous version.
640         // Set all unchanged pixels to transparent
641         DColor color, ncolor;
642         uchar *ptr, *nptr;
643         ptr = textDrawn.bits();
644         nptr = textNotDrawn.bits();
645         int bytesDepth = textDrawn.bytesDepth();
646         int numPixels = textDrawn.width() * textDrawn.height();
647         for (int i = 0; i < numPixels; ++i, ptr+= bytesDepth, nptr += bytesDepth)
648         {
649             color.setColor(ptr, false);
650             ncolor.setColor(nptr, false);
651             if (color.red()   == ncolor.red()   &&
652                 color.green() == ncolor.green() &&
653                 color.blue()  == ncolor.blue())
654             {
655                 color.setAlpha(0);
656                 color.setPixel(ptr);
657             }
658         }
659         // convert to 16 bit if needed
660 */
661         textDrawn.convertToDepthOfImage(&textArea);
662 
663         // now compose to original: only pixels affected by drawing text and border are changed, not whole area
664 
665         textArea.bitBlendImage(composer, &textDrawn, 0, 0, textDrawn.width(), textDrawn.height(), 0, 0);
666 
667         // copy result to original image
668 
669         image->bitBltImage(&textArea, drawRect.x(), drawRect.y());
670     }
671     else
672     {
673         destPainter->drawPixmap(drawRect.x(), drawRect.y(), pixmap, 0, 0, pixmap.width(), pixmap.height());
674     }
675 
676     delete composer;
677 
678     return drawRect;
679 }
680 
paintEvent(QPaintEvent *)681 void InsertTextWidget::paintEvent(QPaintEvent*)
682 {
683     QPainter p(this);
684     p.drawPixmap(0, 0, *d->pixmap);
685     p.end();
686 }
687 
resizeEvent(QResizeEvent * e)688 void InsertTextWidget::resizeEvent(QResizeEvent* e)
689 {
690     blockSignals(true);
691     delete d->pixmap;
692 
693     int w     = e->size().width();
694     int h     = e->size().height();
695 
696     int textX = d->textRect.x() - d->rect.x();
697     int textY = d->textRect.y() - d->rect.y();
698     int old_w = d->w;
699     int old_h = d->h;
700     d->iface->setPreviewSize(QSize(w, h));
701     d->w      = d->iface->previewSize().width();
702     d->h      = d->iface->previewSize().height();
703 
704     d->pixmap = new QPixmap(w, h);
705     d->rect   = QRect(w/2-d->w/2, h/2-d->h/2, d->w, d->h);
706 
707     if (d->textRect.isValid())
708     {
709         int textWidth  = d->textRect.width();
710         int textHeight = d->textRect.height();
711 
712         textX      = qRound(textX      * (float)d->w / (float)old_w);
713         textY      = qRound(textY      * (float)d->h / (float)old_h);
714         textWidth  = qRound(textWidth  * (float)d->w / (float)old_w);
715         textHeight = qRound(textHeight * (float)d->h / (float)old_h);
716 
717         d->textRect.setX(textX + d->rect.x());
718         d->textRect.setY(textY + d->rect.y());
719         d->textRect.setWidth(textWidth);
720         d->textRect.setHeight(textHeight);
721         makePixmap();
722     }
723 
724     blockSignals(false);
725 }
726 
mousePressEvent(QMouseEvent * e)727 void InsertTextWidget::mousePressEvent(QMouseEvent* e)
728 {
729     if (e->button() == Qt::LeftButton &&
730         d->textRect.contains( e->x(), e->y()))
731     {
732         d->xpos = e->x();
733         d->ypos = e->y();
734         setCursor(Qt::SizeAllCursor);
735         d->currentMoving = true;
736     }
737 }
738 
mouseReleaseEvent(QMouseEvent *)739 void InsertTextWidget::mouseReleaseEvent(QMouseEvent*)
740 {
741     setCursor(Qt::ArrowCursor);
742     d->currentMoving = false;
743 }
744 
mouseMoveEvent(QMouseEvent * e)745 void InsertTextWidget::mouseMoveEvent(QMouseEvent* e)
746 {
747     if (rect().contains( e->x(), e->y()))
748     {
749         if      (e->buttons() == Qt::LeftButton && d->currentMoving)
750         {
751             uint newxpos = e->x();
752             uint newypos = e->y();
753 
754             d->textRect.translate(newxpos - d->xpos, newypos - d->ypos);
755 
756             if (d->textRect.x() - d->rect.x() < 0)
757             {
758                 d->textRect.setX(d->rect.x());
759             }
760 
761             if (d->textRect.y() - d->rect.y() < 0)
762             {
763                 d->textRect.setY(d->rect.y());
764             }
765 
766             makePixmap();
767             repaint();
768 
769             d->xpos = newxpos;
770             d->ypos = newypos;
771             setCursor(Qt::PointingHandCursor);
772         }
773         else if (d->textRect.contains( e->x(), e->y()))
774         {
775             setCursor(Qt::SizeAllCursor);
776         }
777         else
778         {
779             setCursor(Qt::ArrowCursor);
780         }
781     }
782 }
783 
784 } // namespace DigikamEditorInsertTextToolPlugin
785