File indexing completed on 2024-05-05 17:09:08

0001 /*
0002  * This file is part of the KDE project
0003  *
0004  * Copyright (C) 2013 Dan Leinir Turthra Jensen <admin@leinir.dk>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  *
0021  */
0022 
0023 #include "CQLinkArea.h"
0024 
0025 #include <QGraphicsSceneMouseEvent>
0026 #include <QPainter>
0027 
0028 struct LinkLayerLink
0029 {
0030     QRectF linkRect;
0031     QUrl linkTarget;
0032 };
0033 
0034 class CQLinkArea::Private
0035 {
0036 public:
0037     Private()
0038         : clickInProgress(false)
0039         , wiggleFactor(4)
0040     {}
0041     QVariantList links;
0042     QList<LinkLayerLink> realLinks;
0043 
0044     bool clickInProgress;
0045     QPointF clickLocation;
0046     int wiggleFactor;
0047 
0048     QSizeF sourceSize;
0049 
0050     QColor linkColor;
0051 };
0052 
0053 CQLinkArea::CQLinkArea(QDeclarativeItem* parent)
0054     : QDeclarativeItem(parent)
0055     , d(new Private)
0056 {
0057     setFlag(QGraphicsItem::ItemHasNoContents, false);
0058     setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton | Qt::MidButton);
0059     setAcceptTouchEvents(true);
0060 }
0061 
0062 CQLinkArea::~CQLinkArea()
0063 {
0064     delete d;
0065 }
0066 
0067 void CQLinkArea::paint(QPainter* painter, const QStyleOptionGraphicsItem* , QWidget* )
0068 {
0069     painter->save();
0070     painter->setPen(Qt::transparent);
0071     painter->setBrush(QBrush(d->linkColor));
0072     foreach(const LinkLayerLink& link, d->realLinks) {
0073         QRectF target(
0074             (link.linkRect.y() / d->sourceSize.height()) * height(),
0075             (link.linkRect.x() / d->sourceSize.width()) * width(),
0076             (link.linkRect.height() / d->sourceSize.height()) * height(),
0077             (link.linkRect.width() / d->sourceSize.width()) * width());
0078         painter->drawRect(target);
0079     }
0080     painter->restore();
0081 }
0082 
0083 QVariantList CQLinkArea::links() const
0084 {
0085     return d->links;
0086 }
0087 
0088 void CQLinkArea::setLinks(const QVariantList& newLinks)
0089 {
0090     d->links = newLinks;
0091     // run through the new data and cache a data list with the information
0092     // so we don't have to interpret the QObjects all the time
0093     d->realLinks.clear();
0094     foreach(const QVariant& var, newLinks) {
0095         QObject* obj = var.value<QObject*>();
0096         if (!obj) {
0097             continue;
0098         }
0099         LinkLayerLink link;
0100         link.linkRect = obj->property("linkRect").toRectF().adjusted(-d->wiggleFactor, -d->wiggleFactor, d->wiggleFactor, d->wiggleFactor);
0101         link.linkTarget = obj->property("linkTarget").toUrl();
0102         d->realLinks.append(link);
0103     }
0104     emit linksChanged();
0105 }
0106 
0107 QSizeF CQLinkArea::sourceSize() const
0108 {
0109     return d->sourceSize;
0110 }
0111 
0112 void CQLinkArea::setSourceSize(const QSizeF& size)
0113 {
0114     if (size != d->sourceSize) {
0115         d->sourceSize = size;
0116         emit sourceSizeChanged();
0117         update();
0118     }
0119 }
0120 
0121 QColor CQLinkArea::linkColor() const
0122 {
0123     return d->linkColor;
0124 }
0125 
0126 void CQLinkArea::setLinkColor(const QColor& color)
0127 {
0128     if (color != d->linkColor) {
0129         d->linkColor = color;
0130         d->linkColor.setAlphaF( 0.25 );
0131         emit linkColorChanged();
0132         update();
0133     }
0134 }
0135 
0136 void CQLinkArea::mousePressEvent(QGraphicsSceneMouseEvent* event)
0137 {
0138     d->clickInProgress = true;
0139     d->clickLocation = event->pos();
0140 }
0141 
0142 void CQLinkArea::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
0143 {
0144     d->clickInProgress = false;
0145     // Don't activate anything if the finger has moved too far
0146     QRect rect((d->clickLocation - QPointF(d->wiggleFactor, d->wiggleFactor)).toPoint(), QSize(d->wiggleFactor * 2, d->wiggleFactor * 2));
0147     if (!rect.contains(event->pos().toPoint())) {
0148         return;
0149     }
0150     QUrl url;
0151     QPointF inverted(event->pos().y(), event->pos().x());
0152     foreach(const LinkLayerLink& link, d->realLinks) {
0153         QRectF scaledTarget(
0154             (link.linkRect.x() / d->sourceSize.width()) * width(),
0155             (link.linkRect.y() / d->sourceSize.height()) * height(),
0156             (link.linkRect.width() / d->sourceSize.width()) * width(),
0157             (link.linkRect.height() / d->sourceSize.height()) * height() );
0158 
0159         if (scaledTarget.contains(inverted)) {
0160             url = link.linkTarget;
0161             break;
0162         }
0163     }
0164     if (url.isEmpty()) {
0165         emit clicked();
0166     } else {
0167         emit linkClicked(url);
0168     }
0169 }
0170 
0171 void CQLinkArea::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
0172 {
0173     Q_UNUSED(event)
0174     emit doubleClicked();
0175 }