File indexing completed on 2025-01-05 03:58:06

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2010-06-21
0007  * Description : Demo test program for FacesEngine
0008  *
0009  * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText:      2010 by Alex Jironkin <alexjironkin at gmail dot com>
0011  * SPDX-FileCopyrightText:      2010 by Aditya Bhatt <adityabhatt1991 at gmail dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "demofaceitem.h"
0018 
0019 // Qt includes
0020 
0021 #include <QWidget>
0022 #include <QPainter>
0023 #include <QGraphicsOpacityEffect>
0024 #include <QTextDocument>
0025 #include <QGraphicsScene>
0026 #include <QColor>
0027 #include <QIcon>
0028 #include <qmath.h>
0029 
0030 // Local includes
0031 
0032 #include "digikam_debug.h"
0033 #include "demomarquee.h"
0034 #include "demofancyrect.h"
0035 
0036 namespace FaceEngineDemo
0037 {
0038 
0039 class Q_DECL_HIDDEN FaceItem::Private
0040 {
0041 public:
0042 
0043     explicit Private()
0044       : suggestionMode(false),
0045         sceneWidth(0),
0046         sceneHeight(0),
0047         x1(0),
0048         x2(0),
0049         y1(0),
0050         y2(0),
0051         name(),
0052         faceMarquee(nullptr),
0053         faceName(nullptr),
0054         nameRect(nullptr),
0055         origRect(),
0056         origScale(0.0),
0057         scale(0.0),
0058         rejectButton(nullptr),
0059         acceptButton(nullptr),
0060         suggestionRejectButton(nullptr),
0061         suggestionAcceptButton(nullptr)
0062     {
0063     }
0064 
0065     bool               suggestionMode;
0066 
0067     int                sceneWidth, sceneHeight;
0068     int                x1, x2, y1, y2;
0069 
0070     QString            name;
0071     Marquee*           faceMarquee;
0072 
0073     QGraphicsTextItem* faceName;
0074     QGraphicsRectItem* nameRect;
0075 
0076     QRect              origRect;
0077     double             origScale;
0078     double             scale;
0079 
0080     Button*            rejectButton;
0081     Button*            acceptButton;
0082 
0083     Button*            suggestionRejectButton;
0084     Button*            suggestionAcceptButton;
0085 };
0086 
0087 FaceItem::FaceItem(QGraphicsItem* const parent,
0088                    QGraphicsScene* const scene,
0089                    const QRect& rect,
0090                    double scale,
0091                    const QString& name,
0092                    double originalscale)
0093         : QGraphicsObject(parent),
0094           d(new Private)
0095 {
0096     setAcceptHoverEvents(true);
0097 
0098     d->origScale     = originalscale;
0099     d->scale         = scale;
0100     d->origRect      = rect;
0101     d->sceneWidth    = scene->width();
0102     d->sceneHeight   = scene->height();
0103 
0104     // Scale all coordinates to fit the initial size of the scene
0105 
0106     d->x1 = rect.topLeft().x()     * scale;
0107     d->y1 = rect.topLeft().y()     * scale;
0108     d->x2 = rect.bottomRight().x() * scale;
0109     d->y2 = rect.bottomRight().y() * scale;
0110 
0111     // A QRect containing coordinates for the face rectangle
0112 
0113     QRect scaledRect;
0114     scaledRect.setTopLeft(QPoint(d->x1, d->y1));
0115     scaledRect.setBottomRight(QPoint(d->x2, d->y2));
0116 
0117     // marquee
0118 
0119     FancyRect* const fancy = new FancyRect(scaledRect);
0120     d->faceMarquee         = new Marquee(fancy);
0121     scene->addItem(d->faceMarquee);
0122 
0123     // Make a new QGraphicsTextItem for writing the name text, and a new QGraphicsRectItem to draw a good-looking, semi-transparent bounding box.
0124 
0125     d->nameRect = new QGraphicsRectItem(nullptr);
0126     scene->addItem(d->nameRect);
0127 
0128     d->faceName = new QGraphicsTextItem(name, nullptr);
0129     scene->addItem(d->faceName);
0130 
0131     // Make the bounding box for the name update itself to cover all the text whenever contents are changed
0132 
0133     QTextDocument* const doc = d->faceName->document();
0134     QTextOption o;
0135     o.setAlignment(Qt::AlignCenter);
0136     doc->setDefaultTextOption(o);
0137 
0138     // Get coordinates of the name relative to the scene
0139 
0140     QRectF r = d->faceName->mapRectToScene(d->faceName->boundingRect());
0141 
0142     // Draw the bounding name rectangle with the scene coordinates
0143 
0144     d->nameRect->setRect(r);
0145     QPen p(QColor(QLatin1String("white")));
0146     p.setWidth(3);
0147     d->nameRect->setPen(p);
0148     d->nameRect->setBrush(QBrush(QColor(QLatin1String("black"))));
0149     d->nameRect->setOpacity(0.6);
0150     d->nameRect->show();
0151 
0152     // Draw the name input item
0153 
0154     d->faceName->setDefaultTextColor(QColor(QLatin1String("white")));
0155     d->faceName->setFont(QFont(QLatin1String("Helvetica"), 9));
0156     d->faceName->setTextInteractionFlags(Qt::TextEditorInteraction);
0157     d->faceName->setOpacity(1);
0158 
0159     //---------------------
0160 
0161     QPixmap rejectPix  = QIcon::fromTheme(QLatin1String("window-close")).pixmap(16, 16);
0162     d->rejectButton    = new Button( rejectPix, rejectPix);
0163     scene->addItem(d->rejectButton);
0164     d->rejectButton->show();
0165 
0166     QPixmap acceptPix  = QIcon::fromTheme(QLatin1String("dialog-ok-apply")).pixmap(16, 16);
0167     d->acceptButton    = new Button( acceptPix, acceptPix);
0168     scene->addItem(d->acceptButton);
0169 /*
0170     d->acceptButton->show();
0171 */
0172     d->suggestionRejectButton = new Button(rejectPix, rejectPix);
0173     scene->addItem(d->suggestionRejectButton);
0174     //d->suggestionAcceptButton->hide();
0175 
0176     d->suggestionAcceptButton = new Button(acceptPix, acceptPix);
0177     scene->addItem(d->suggestionAcceptButton);
0178 /*
0179     d->suggestionRejectButton->hide();
0180 */
0181     update();
0182 
0183     switchToEditMode();
0184 
0185     d->acceptButton->hide();
0186 
0187     connect(d->rejectButton, &Button::clicked,
0188             this, &FaceItem::reject);
0189 
0190     connect(d->acceptButton, &Button::clicked,
0191             this, &FaceItem::accepted);
0192 
0193     connect(d->suggestionAcceptButton, &Button::clicked,
0194             this, &FaceItem::slotSuggestionAccepted);
0195 
0196     connect(d->suggestionRejectButton, &Button::clicked, this,
0197             &FaceItem::slotSuggestionRejected);
0198 
0199     connect(doc, SIGNAL(contentsChanged()),
0200             this, SLOT(update()));
0201 
0202     connect(d->faceMarquee, &Marquee::changed,
0203             this, &FaceItem::update);
0204 }
0205 
0206 FaceItem::~FaceItem()
0207 {
0208     delete d;
0209 }
0210 
0211 QRectF FaceItem::boundingRect() const
0212 {
0213     qreal adjust = 0.5;
0214 
0215     return QRectF(-18 - adjust,
0216                   -22 - adjust,
0217                    36 + adjust,
0218                    60 + adjust);
0219 }
0220 
0221 void FaceItem::setText(const QString& newName)
0222 {
0223     d->faceName->setHtml(newName);
0224 }
0225 
0226 QString FaceItem::text() const
0227 {
0228     return d->faceName->toPlainText().remove(QLatin1String("?"));
0229 }
0230 
0231 void FaceItem::update()
0232 {
0233     if (text().isEmpty())
0234     {
0235         d->faceName->setDefaultTextColor(QColor("white"));
0236         d->nameRect->setPen(QPen(QColor("white")));
0237         d->acceptButton->hide();
0238         d->name.clear();
0239     }
0240     else
0241     {
0242         d->nameRect->setPen(QPen(QColor("yellow")));
0243         d->faceName->setDefaultTextColor(QColor("yellow"));
0244 
0245         if (!d->suggestionMode)
0246         {
0247             d->acceptButton->show();
0248             d->name = text();
0249         }
0250     }
0251 
0252     QPointF bl = d->faceMarquee->mapRectToScene(d->faceMarquee->boundingRect()).bottomLeft();
0253     QPointF br = d->nameRect->mapRectToScene(d->nameRect->boundingRect()).bottomRight();
0254     d->faceName->setPos(bl.x() + 5, bl.y() + 5);
0255 
0256     d->rejectButton->setPos(bl.x() - 16, bl.y() + 9);
0257     d->acceptButton->setPos(br.x() + 4,  bl.y() + 11);
0258 
0259     d->suggestionAcceptButton->setPos(br.x() + 4,  bl.y() + 11);
0260     d->suggestionRejectButton->setPos(br.x() + 20, bl.y() + 11);
0261 
0262     QRectF r      = d->faceName->mapRectToScene(d->faceName->boundingRect());
0263     d->nameRect->setRect(r);
0264     QRect newRect = this->d->faceMarquee->mapRectToScene(d->faceMarquee->boundingRect()).toRect();
0265     qCDebug(DIGIKAM_TESTS_LOG) << "Origscale is : " << d->origScale << " and scale is " << d->scale;
0266 
0267     QSize s(newRect.size());
0268     s.scale(newRect.width() * qSqrt(d->origScale), newRect.height() * qSqrt(d->origScale), Qt::KeepAspectRatio);
0269     newRect.setSize(s);
0270 /*
0271     newRect.setRect(x,y,w,h);
0272 */
0273     qCDebug(DIGIKAM_TESTS_LOG) << "Orig before" << d->origRect;
0274 /*
0275     d->origRect = newRect;
0276 */
0277     qCDebug(DIGIKAM_TESTS_LOG) << "Orig after" << d->origRect;
0278 }
0279 
0280 void FaceItem::setVisible(bool visible)
0281 {
0282     d->faceMarquee->setVisible(visible);
0283     setControlsVisible(visible);
0284 }
0285 
0286 void FaceItem::setControlsVisible(bool visible)
0287 {
0288     d->nameRect->setVisible(visible);
0289     d->faceName->setVisible(visible);
0290 
0291     if (d->suggestionMode)
0292     {
0293         d->suggestionAcceptButton->setVisible(visible);
0294         d->suggestionRejectButton->setVisible(visible);
0295     }
0296     else
0297     {
0298         d->rejectButton->setVisible(visible);
0299         d->acceptButton->setVisible(visible);
0300     }
0301 }
0302 
0303 void FaceItem::clearText()
0304 {
0305     d->faceName->setPlainText(QString());
0306 }
0307 
0308 void FaceItem::clearAndHide()
0309 {
0310     clearText();
0311     setVisible(false);
0312 }
0313 
0314 void FaceItem::accepted()
0315 {
0316     d->acceptButton->hide();
0317     d->faceName->setDefaultTextColor(QColor("white"));
0318     d->nameRect->setPen(QPen(QColor("white")));
0319     Q_EMIT acceptButtonClicked(this->text(), this->originalRect());
0320 }
0321 
0322 QRect FaceItem::originalRect() const
0323 {
0324     return d->origRect;
0325 }
0326 
0327 double FaceItem::originalScale() const
0328 {
0329     return d->origScale;
0330 }
0331 
0332 void FaceItem::reject()
0333 {
0334     Q_EMIT rejectButtonClicked(this->text(), this->originalRect());
0335     clearAndHide();
0336 }
0337 
0338 void FaceItem::suggest(const QString& name)
0339 {
0340     qCDebug(DIGIKAM_TESTS_LOG) << "suggested name is " << name;
0341     d->name = name;
0342     this->switchToSuggestionMode();
0343 }
0344 
0345 void FaceItem::switchToEditMode()
0346 {
0347     d->suggestionMode = false;
0348     d->faceName->setEnabled(true);
0349     d->faceName->setHtml(QLatin1String("<b>") + d->name + QLatin1String("</b>"));
0350     d->acceptButton->show();
0351     d->suggestionAcceptButton->hide();
0352     d->suggestionRejectButton->hide();
0353 }
0354 
0355 void FaceItem::switchToSuggestionMode()
0356 {
0357     d->suggestionMode = true;
0358     d->faceName->setEnabled(false);
0359     d->faceName->setHtml(QLatin1String("Is this <b>") + d->name + QLatin1String("</b> ?"));
0360     d->acceptButton->hide();
0361     d->suggestionAcceptButton->show();
0362     d->suggestionRejectButton->show();
0363 }
0364 
0365 void FaceItem::slotSuggestionAccepted()
0366 {
0367     switchToEditMode();
0368     d->faceName->setHtml(QLatin1String("<b>") + d->name + QLatin1String("</b>"));
0369     accepted();
0370     Q_EMIT suggestionAcceptButtonClicked(this->text(), this->originalRect());
0371 }
0372 
0373 void FaceItem::slotSuggestionRejected()
0374 {
0375     switchToEditMode();
0376     d->faceName->setHtml(QLatin1String("<b>") + QString() + QLatin1String("</b>"));
0377     Q_EMIT suggestionRejectButtonClicked(this->text(), this->originalRect());
0378 }
0379 
0380 void FaceItem::paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
0381 {
0382 }
0383 
0384 } // namespace FaceEngineDemo
0385 
0386 #include "moc_demofaceitem.cpp"