File indexing completed on 2024-05-12 13:04:45

0001 /*
0002  * This file is part of the KDE project
0003  *
0004  * SPDX-FileCopyrightText: 2013 Dan Leinir Turthra Jensen <admin@leinir.dk>
0005  *
0006  * SPDX-License-Identifier: LGPL-2.0-or-later
0007  *
0008  */
0009 
0010 #include "CQLinkArea.h"
0011 
0012 #include <QGraphicsSceneMouseEvent>
0013 #include <QPainter>
0014 
0015 struct LinkLayerLink
0016 {
0017     QRectF linkRect;
0018     QUrl linkTarget;
0019 };
0020 
0021 class CQLinkArea::Private
0022 {
0023 public:
0024     Private()
0025         : clickInProgress(false)
0026         , wiggleFactor(4)
0027     {}
0028     QVariantList links;
0029     QList<LinkLayerLink> realLinks;
0030 
0031     bool clickInProgress;
0032     QPointF clickLocation;
0033     int wiggleFactor;
0034 
0035     QSizeF sourceSize;
0036 
0037     QColor linkColor;
0038 };
0039 
0040 CQLinkArea::CQLinkArea(QDeclarativeItem* parent)
0041     : QDeclarativeItem(parent)
0042     , d(new Private)
0043 {
0044     setFlag(QGraphicsItem::ItemHasNoContents, false);
0045     setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton | Qt::MidButton);
0046     setAcceptTouchEvents(true);
0047 }
0048 
0049 CQLinkArea::~CQLinkArea()
0050 {
0051     delete d;
0052 }
0053 
0054 void CQLinkArea::paint(QPainter* painter, const QStyleOptionGraphicsItem* , QWidget* )
0055 {
0056     painter->save();
0057     painter->setPen(Qt::transparent);
0058     painter->setBrush(QBrush(d->linkColor));
0059     foreach(const LinkLayerLink& link, d->realLinks) {
0060         QRectF target(
0061             (link.linkRect.y() / d->sourceSize.height()) * height(),
0062             (link.linkRect.x() / d->sourceSize.width()) * width(),
0063             (link.linkRect.height() / d->sourceSize.height()) * height(),
0064             (link.linkRect.width() / d->sourceSize.width()) * width());
0065         painter->drawRect(target);
0066     }
0067     painter->restore();
0068 }
0069 
0070 QVariantList CQLinkArea::links() const
0071 {
0072     return d->links;
0073 }
0074 
0075 void CQLinkArea::setLinks(const QVariantList& newLinks)
0076 {
0077     d->links = newLinks;
0078     // run through the new data and cache a data list with the information
0079     // so we don't have to interpret the QObjects all the time
0080     d->realLinks.clear();
0081     foreach(const QVariant& var, newLinks) {
0082         QObject* obj = var.value<QObject*>();
0083         if (!obj) {
0084             continue;
0085         }
0086         LinkLayerLink link;
0087         link.linkRect = obj->property("linkRect").toRectF().adjusted(-d->wiggleFactor, -d->wiggleFactor, d->wiggleFactor, d->wiggleFactor);
0088         link.linkTarget = obj->property("linkTarget").toUrl();
0089         d->realLinks.append(link);
0090     }
0091     emit linksChanged();
0092 }
0093 
0094 QSizeF CQLinkArea::sourceSize() const
0095 {
0096     return d->sourceSize;
0097 }
0098 
0099 void CQLinkArea::setSourceSize(const QSizeF& size)
0100 {
0101     if (size != d->sourceSize) {
0102         d->sourceSize = size;
0103         emit sourceSizeChanged();
0104         update();
0105     }
0106 }
0107 
0108 QColor CQLinkArea::linkColor() const
0109 {
0110     return d->linkColor;
0111 }
0112 
0113 void CQLinkArea::setLinkColor(const QColor& color)
0114 {
0115     if (color != d->linkColor) {
0116         d->linkColor = color;
0117         d->linkColor.setAlphaF( 0.25 );
0118         emit linkColorChanged();
0119         update();
0120     }
0121 }
0122 
0123 void CQLinkArea::mousePressEvent(QGraphicsSceneMouseEvent* event)
0124 {
0125     d->clickInProgress = true;
0126     d->clickLocation = event->pos();
0127 }
0128 
0129 void CQLinkArea::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
0130 {
0131     d->clickInProgress = false;
0132     // Don't activate anything if the finger has moved too far
0133     QRect rect((d->clickLocation - QPointF(d->wiggleFactor, d->wiggleFactor)).toPoint(), QSize(d->wiggleFactor * 2, d->wiggleFactor * 2));
0134     if (!rect.contains(event->pos().toPoint())) {
0135         return;
0136     }
0137     QUrl url;
0138     QPointF inverted(event->pos().y(), event->pos().x());
0139     foreach(const LinkLayerLink& link, d->realLinks) {
0140         QRectF scaledTarget(
0141             (link.linkRect.x() / d->sourceSize.width()) * width(),
0142             (link.linkRect.y() / d->sourceSize.height()) * height(),
0143             (link.linkRect.width() / d->sourceSize.width()) * width(),
0144             (link.linkRect.height() / d->sourceSize.height()) * height() );
0145 
0146         if (scaledTarget.contains(inverted)) {
0147             url = link.linkTarget;
0148             break;
0149         }
0150     }
0151     if (url.isEmpty()) {
0152         emit clicked();
0153     } else {
0154         emit linkClicked(url);
0155     }
0156 }
0157 
0158 void CQLinkArea::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
0159 {
0160     Q_UNUSED(event)
0161     emit doubleClicked();
0162 }