1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2010-06-21
7 * Description : Demo test program for FacesEngine
8 *
9 * Copyright (C) 2009-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 * Copyright (C) 2010 by Alex Jironkin <alexjironkin at gmail dot com>
11 * Copyright (C) 2010 by Aditya Bhatt <adityabhatt1991 at gmail dot com>
12 *
13 * This program is free software; you can redistribute it
14 * and/or modify it under the terms of the GNU General
15 * Public License as published by the Free Software Foundation;
16 * either version 2, or (at your option)
17 * any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * ============================================================ */
25
26 #include "demofaceitem.h"
27
28 // Qt includes
29
30 #include <QWidget>
31 #include <QPainter>
32 #include <QGraphicsOpacityEffect>
33 #include <QTextDocument>
34 #include <QGraphicsScene>
35 #include <QColor>
36 #include <QIcon>
37 #include <qmath.h>
38
39 // Local includes
40
41 #include "digikam_debug.h"
42 #include "demomarquee.h"
43 #include "demofancyrect.h"
44
45 namespace FaceEngineDemo
46 {
47
48 class Q_DECL_HIDDEN FaceItem::Private
49 {
50 public:
51
Private()52 explicit Private()
53 : suggestionMode(false),
54 sceneWidth(0),
55 sceneHeight(0),
56 x1(0),
57 x2(0),
58 y1(0),
59 y2(0),
60 name(),
61 faceMarquee(nullptr),
62 faceName(nullptr),
63 nameRect(nullptr),
64 origRect(),
65 origScale(0.0),
66 scale(0.0),
67 rejectButton(nullptr),
68 acceptButton(nullptr),
69 suggestionRejectButton(nullptr),
70 suggestionAcceptButton(nullptr)
71 {
72 }
73
74 bool suggestionMode;
75
76 int sceneWidth, sceneHeight;
77 int x1, x2, y1, y2;
78
79 QString name;
80 Marquee* faceMarquee;
81
82 QGraphicsTextItem* faceName;
83 QGraphicsRectItem* nameRect;
84
85 QRect origRect;
86 double origScale;
87 double scale;
88
89 Button* rejectButton;
90 Button* acceptButton;
91
92 Button* suggestionRejectButton;
93 Button* suggestionAcceptButton;
94 };
95
FaceItem(QGraphicsItem * const parent,QGraphicsScene * const scene,const QRect & rect,double scale,const QString & name,double originalscale)96 FaceItem::FaceItem(QGraphicsItem* const parent,
97 QGraphicsScene* const scene,
98 const QRect& rect,
99 double scale,
100 const QString& name,
101 double originalscale)
102 : QGraphicsObject(parent),
103 d(new Private)
104 {
105 setAcceptHoverEvents(true);
106
107 d->origScale = originalscale;
108 d->scale = scale;
109 d->origRect = rect;
110 d->sceneWidth = scene->width();
111 d->sceneHeight = scene->height();
112
113 // Scale all coordinates to fit the initial size of the scene
114
115 d->x1 = rect.topLeft().x() * scale;
116 d->y1 = rect.topLeft().y() * scale;
117 d->x2 = rect.bottomRight().x() * scale;
118 d->y2 = rect.bottomRight().y() * scale;
119
120 // A QRect containing coordinates for the face rectangle
121
122 QRect scaledRect;
123 scaledRect.setTopLeft(QPoint(d->x1, d->y1));
124 scaledRect.setBottomRight(QPoint(d->x2, d->y2));
125
126 // marquee
127
128 FancyRect* const fancy = new FancyRect(scaledRect);
129 d->faceMarquee = new Marquee(fancy);
130 scene->addItem(d->faceMarquee);
131
132 // Make a new QGraphicsTextItem for writing the name text, and a new QGraphicsRectItem to draw a good-looking, semi-transparent bounding box.
133
134 d->nameRect = new QGraphicsRectItem(nullptr);
135 scene->addItem(d->nameRect);
136
137 d->faceName = new QGraphicsTextItem(name, nullptr);
138 scene->addItem(d->faceName);
139
140 // Make the bounding box for the name update itself to cover all the text whenever contents are changed
141
142 QTextDocument* const doc = d->faceName->document();
143 QTextOption o;
144 o.setAlignment(Qt::AlignCenter);
145 doc->setDefaultTextOption(o);
146
147 // Get coordinates of the name relative to the scene
148
149 QRectF r = d->faceName->mapRectToScene(d->faceName->boundingRect());
150
151 // Draw the bounding name rectangle with the scene coordinates
152
153 d->nameRect->setRect(r);
154 QPen p(QColor(QLatin1String("white")));
155 p.setWidth(3);
156 d->nameRect->setPen(p);
157 d->nameRect->setBrush(QBrush(QColor(QLatin1String("black"))));
158 d->nameRect->setOpacity(0.6);
159 d->nameRect->show();
160
161 // Draw the name input item
162
163 d->faceName->setDefaultTextColor(QColor(QLatin1String("white")));
164 d->faceName->setFont(QFont(QLatin1String("Helvetica"), 9));
165 d->faceName->setTextInteractionFlags(Qt::TextEditorInteraction);
166 d->faceName->setOpacity(1);
167
168 //---------------------
169
170 QPixmap rejectPix = QIcon::fromTheme(QLatin1String("window-close")).pixmap(16, 16);
171 d->rejectButton = new Button( rejectPix, rejectPix);
172 scene->addItem(d->rejectButton);
173 d->rejectButton->show();
174
175 QPixmap acceptPix = QIcon::fromTheme(QLatin1String("dialog-ok-apply")).pixmap(16, 16);
176 d->acceptButton = new Button( acceptPix, acceptPix);
177 scene->addItem(d->acceptButton);
178 /*
179 d->acceptButton->show();
180 */
181 d->suggestionRejectButton = new Button(rejectPix, rejectPix);
182 scene->addItem(d->suggestionRejectButton);
183 //d->suggestionAcceptButton->hide();
184
185 d->suggestionAcceptButton = new Button(acceptPix, acceptPix);
186 scene->addItem(d->suggestionAcceptButton);
187 /*
188 d->suggestionRejectButton->hide();
189 */
190 update();
191
192 switchToEditMode();
193
194 d->acceptButton->hide();
195
196 connect(d->rejectButton, &Button::clicked,
197 this, &FaceItem::reject);
198
199 connect(d->acceptButton, &Button::clicked,
200 this, &FaceItem::accepted);
201
202 connect(d->suggestionAcceptButton, &Button::clicked,
203 this, &FaceItem::slotSuggestionAccepted);
204
205 connect(d->suggestionRejectButton, &Button::clicked, this,
206 &FaceItem::slotSuggestionRejected);
207
208 connect(doc, SIGNAL(contentsChanged()),
209 this, SLOT(update()));
210
211 connect(d->faceMarquee, &Marquee::changed,
212 this, &FaceItem::update);
213 }
214
~FaceItem()215 FaceItem::~FaceItem()
216 {
217 delete d;
218 }
219
boundingRect() const220 QRectF FaceItem::boundingRect() const
221 {
222 qreal adjust = 0.5;
223
224 return QRectF(-18 - adjust,
225 -22 - adjust,
226 36 + adjust,
227 60 + adjust);
228 }
229
setText(const QString & newName)230 void FaceItem::setText(const QString& newName)
231 {
232 d->faceName->setHtml(newName);
233 }
234
text() const235 QString FaceItem::text() const
236 {
237 return d->faceName->toPlainText().remove(QLatin1String("?"));
238 }
239
update()240 void FaceItem::update()
241 {
242 if (text().isEmpty())
243 {
244 d->faceName->setDefaultTextColor(QColor("white"));
245 d->nameRect->setPen(QPen(QColor("white")));
246 d->acceptButton->hide();
247 d->name.clear();
248 }
249 else
250 {
251 d->nameRect->setPen(QPen(QColor("yellow")));
252 d->faceName->setDefaultTextColor(QColor("yellow"));
253
254 if (!d->suggestionMode)
255 {
256 d->acceptButton->show();
257 d->name = text();
258 }
259 }
260
261 QPointF bl = d->faceMarquee->mapRectToScene(d->faceMarquee->boundingRect()).bottomLeft();
262 QPointF br = d->nameRect->mapRectToScene(d->nameRect->boundingRect()).bottomRight();
263 d->faceName->setPos(bl.x() + 5, bl.y() + 5);
264
265 d->rejectButton->setPos(bl.x() - 16, bl.y() + 9);
266 d->acceptButton->setPos(br.x() + 4, bl.y() + 11);
267
268 d->suggestionAcceptButton->setPos(br.x() + 4, bl.y() + 11);
269 d->suggestionRejectButton->setPos(br.x() + 20, bl.y() + 11);
270
271 QRectF r = d->faceName->mapRectToScene(d->faceName->boundingRect());
272 d->nameRect->setRect(r);
273 QRect newRect = this->d->faceMarquee->mapRectToScene(d->faceMarquee->boundingRect()).toRect();
274 qCDebug(DIGIKAM_TESTS_LOG) << "Origscale is : " << d->origScale << " and scale is " << d->scale;
275
276 QSize s(newRect.size());
277 s.scale(newRect.width() * qSqrt(d->origScale), newRect.height() * qSqrt(d->origScale), Qt::KeepAspectRatio);
278 newRect.setSize(s);
279 /*
280 newRect.setRect(x,y,w,h);
281 */
282 qCDebug(DIGIKAM_TESTS_LOG) << "Orig before" << d->origRect;
283 /*
284 d->origRect = newRect;
285 */
286 qCDebug(DIGIKAM_TESTS_LOG) << "Orig after" << d->origRect;
287 }
288
setVisible(bool visible)289 void FaceItem::setVisible(bool visible)
290 {
291 d->faceMarquee->setVisible(visible);
292 setControlsVisible(visible);
293 }
294
setControlsVisible(bool visible)295 void FaceItem::setControlsVisible(bool visible)
296 {
297 d->nameRect->setVisible(visible);
298 d->faceName->setVisible(visible);
299
300 if (d->suggestionMode)
301 {
302 d->suggestionAcceptButton->setVisible(visible);
303 d->suggestionRejectButton->setVisible(visible);
304 }
305 else
306 {
307 d->rejectButton->setVisible(visible);
308 d->acceptButton->setVisible(visible);
309 }
310 }
311
clearText()312 void FaceItem::clearText()
313 {
314 d->faceName->setPlainText(QString());
315 }
316
clearAndHide()317 void FaceItem::clearAndHide()
318 {
319 clearText();
320 setVisible(false);
321 }
322
accepted()323 void FaceItem::accepted()
324 {
325 d->acceptButton->hide();
326 d->faceName->setDefaultTextColor(QColor("white"));
327 d->nameRect->setPen(QPen(QColor("white")));
328 emit acceptButtonClicked(this->text(), this->originalRect());
329 }
330
originalRect() const331 QRect FaceItem::originalRect() const
332 {
333 return d->origRect;
334 }
335
originalScale() const336 double FaceItem::originalScale() const
337 {
338 return d->origScale;
339 }
340
reject()341 void FaceItem::reject()
342 {
343 emit rejectButtonClicked(this->text(), this->originalRect());
344 clearAndHide();
345 }
346
suggest(const QString & name)347 void FaceItem::suggest(const QString& name)
348 {
349 qCDebug(DIGIKAM_TESTS_LOG) << "suggested name is " << name;
350 d->name = name;
351 this->switchToSuggestionMode();
352 }
353
switchToEditMode()354 void FaceItem::switchToEditMode()
355 {
356 d->suggestionMode = false;
357 d->faceName->setEnabled(true);
358 d->faceName->setHtml(QLatin1String("<b>") + d->name + QLatin1String("</b>"));
359 d->acceptButton->show();
360 d->suggestionAcceptButton->hide();
361 d->suggestionRejectButton->hide();
362 }
363
switchToSuggestionMode()364 void FaceItem::switchToSuggestionMode()
365 {
366 d->suggestionMode = true;
367 d->faceName->setEnabled(false);
368 d->faceName->setHtml(QLatin1String("Is this <b>") + d->name + QLatin1String("</b> ?"));
369 d->acceptButton->hide();
370 d->suggestionAcceptButton->show();
371 d->suggestionRejectButton->show();
372 }
373
slotSuggestionAccepted()374 void FaceItem::slotSuggestionAccepted()
375 {
376 switchToEditMode();
377 d->faceName->setHtml(QLatin1String("<b>") + d->name + QLatin1String("</b>"));
378 accepted();
379 emit suggestionAcceptButtonClicked(this->text(), this->originalRect());
380 }
381
slotSuggestionRejected()382 void FaceItem::slotSuggestionRejected()
383 {
384 switchToEditMode();
385 d->faceName->setHtml(QLatin1String("<b>") + QString() + QLatin1String("</b>"));
386 emit suggestionRejectButtonClicked(this->text(), this->originalRect());
387 }
388
paint(QPainter *,const QStyleOptionGraphicsItem *,QWidget *)389 void FaceItem::paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
390 {
391 }
392
393 } // namespace FaceEngineDemo
394