mirror of
git://projects.qi-hardware.com/nn-usb-fpga.git
synced 2025-01-10 01:00:14 +02:00
348 lines
11 KiB
C++
348 lines
11 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
** All rights reserved.
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
**
|
|
** This file is part of the examples of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
** Commercial Usage
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and Nokia.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 2.1 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3.0 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU General Public License version 3.0 requirements will be
|
|
** met: http://www.gnu.org/copyleft/gpl.html.
|
|
**
|
|
** If you have questions regarding the use of this file, please contact
|
|
** Nokia at qt-info@nokia.com.
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include <QtGui>
|
|
|
|
#include "arrow.h"
|
|
#include <math.h>
|
|
|
|
const qreal Pi = 3.14;
|
|
|
|
Arrow::Arrow(DiagramTextItem *startItem, DiagramTextItem *endItem,
|
|
QGraphicsItem *parent, QGraphicsScene *scene)
|
|
: QGraphicsPathItem(parent, scene)
|
|
{
|
|
myStartItem = startItem;
|
|
myEndItem = endItem;
|
|
arrowSize = 10;
|
|
moving=0;
|
|
//setFlag(QGraphicsItem::ItemIsMovable, true);
|
|
setFlag(QGraphicsItem::ItemIsSelectable, true);
|
|
myColor = Qt::black;
|
|
setPen(QPen(myColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
|
myOwnerScene = scene;
|
|
lineItem *newLine= new lineItem(QPointF(0,0),QPointF(0,0),this);
|
|
myOwnerScene->addItem(newLine);
|
|
addLine(newLine);
|
|
}
|
|
|
|
void Arrow::removeLine(lineItem *line)
|
|
{
|
|
int index = myLines.indexOf(line);
|
|
int cIndex = myCLines.indexOf(line);
|
|
if(cIndex!=-1) index = cIndex; //Prevent segmentation fault
|
|
|
|
if (index != -1){
|
|
//Adjust the corners
|
|
if(myLines.count()>1)
|
|
{
|
|
if(index==0)
|
|
{
|
|
myCorners.removeAt(0);
|
|
myOwnerScene->removeItem(myCLines.at(0));
|
|
myCLines.removeAt(0);
|
|
}
|
|
else if(index>0)
|
|
{
|
|
myCorners.removeAt(index-1);
|
|
myOwnerScene->removeItem(myCLines.at(index-1));
|
|
myCLines.removeAt(index-1);
|
|
}
|
|
}
|
|
myLines.removeAt(index);
|
|
}
|
|
|
|
//If lines is empty the arrow is removed
|
|
if (myLines.isEmpty())
|
|
{
|
|
this->startItem()->ownerItem()->removeArrow(this);
|
|
this->endItem()->ownerItem()->removeArrow(this);
|
|
this->myOwnerScene->removeItem(this);
|
|
}
|
|
}
|
|
|
|
void Arrow::removeLines()
|
|
{
|
|
foreach (lineItem *line, myLines) {
|
|
scene()->removeItem(line);
|
|
delete line;
|
|
}
|
|
foreach (lineItem *line, myCLines) {
|
|
scene()->removeItem(line);
|
|
delete line;
|
|
}
|
|
}
|
|
|
|
bool Arrow::addLine(lineItem *line)
|
|
{
|
|
myLines.append(line);
|
|
return 1;
|
|
}
|
|
|
|
QRectF Arrow::boundingRect() const
|
|
{
|
|
qreal extra = (pen().width() + arrowSize*2) / 2.0;
|
|
|
|
return QGraphicsPathItem::boundingRect()
|
|
.normalized()
|
|
.adjusted(-extra, -extra, extra, extra);
|
|
}
|
|
|
|
QPainterPath Arrow::shape() const
|
|
{
|
|
QPainterPath path = QGraphicsPathItem::shape();
|
|
return path; //FIXME, Arrow heads must to be include
|
|
}
|
|
|
|
void Arrow::updatePosition()
|
|
{
|
|
QPainterPath myPath;
|
|
myPath.moveTo(myStartItem->ownerItem()->pos()+myStartItem->offset()+
|
|
QPointF(arrowSize,0));
|
|
if(!myCorners.isEmpty())
|
|
foreach(QPointF corner, myCorners){
|
|
myPath.lineTo(corner);
|
|
}
|
|
myPath.lineTo(myEndItem->ownerItem()->pos()+myEndItem->offset()-
|
|
QPointF(arrowSize,0));
|
|
|
|
setPath(myPath);
|
|
|
|
}
|
|
//! [3]
|
|
|
|
void Arrow::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
|
|
QWidget *)
|
|
{
|
|
QPen myPen = pen();
|
|
myPen.setColor(myColor);
|
|
painter->setPen(myPen);
|
|
painter->setBrush(myColor);
|
|
|
|
QPointF endPos=myEndItem->ownerItem()->pos()+myEndItem->offset()-
|
|
QPointF(arrowSize,0);
|
|
QPointF startPos=myStartItem->ownerItem()->pos()+myStartItem->offset()+
|
|
QPointF(arrowSize,0);
|
|
|
|
if(myCorners.isEmpty())
|
|
{
|
|
myLines.first()->setLine(QLineF(startPos,endPos));
|
|
}
|
|
else
|
|
{
|
|
myLines.first()->setLine(QLineF(startPos,myCorners.first()));
|
|
for(int i=0; i<myCorners.count()-1;i++)
|
|
myLines.at(i+1)->setLine(QLineF(myCorners.at(i),myCorners.at(i+1)));
|
|
myLines.last()->setLine(QLineF(myCorners.last(),endPos));
|
|
}
|
|
|
|
//Drawing arrow selected
|
|
for(int i=0; i<myLines.count();i++)
|
|
if (isSelected())
|
|
{
|
|
painter->setPen(QPen(Qt::gray, 2, Qt::SolidLine));
|
|
QLineF myLine = myLines.at(i)->line();
|
|
painter->drawLine(myLine);
|
|
foreach (lineItem *line, myLines) { line->setColor(Qt::gray);}
|
|
foreach (lineItem *line, myCLines) { line->setColor(Qt::gray);}
|
|
}
|
|
else
|
|
{
|
|
foreach (lineItem *line, myLines) { line->setColor(myColor);}
|
|
foreach (lineItem *line, myCLines) { line->setColor(myColor);}
|
|
}
|
|
|
|
//End arrow head
|
|
QPointF arrowP1=QPointF(endPos+QPointF(0,arrowSize));
|
|
QPointF arrowP2=QPointF(endPos+QPointF(0,-arrowSize));
|
|
|
|
arrowHeadEnd.clear();
|
|
arrowHeadEnd << endPos+QPointF(arrowSize,0) << arrowP1 << arrowP2;
|
|
|
|
painter->drawPolygon(arrowHeadEnd);
|
|
//Start arrow head
|
|
arrowP1=QPointF(startPos+QPointF(-arrowSize,arrowSize));
|
|
arrowP2=QPointF(startPos+QPointF(-arrowSize,-arrowSize));
|
|
|
|
arrowHeadStart.clear();
|
|
arrowHeadStart << startPos << arrowP1 << arrowP2;
|
|
painter->drawPolygon(arrowHeadStart);
|
|
|
|
//Set visible corners
|
|
bool anySelected = 0;
|
|
|
|
foreach(lineItem *line,myLines){ if(line->isSelected())anySelected=1;}
|
|
foreach(lineItem *line,myCLines){ if(line->isSelected())anySelected=1;}
|
|
if(isSelected()) anySelected=1;
|
|
|
|
if(anySelected)
|
|
setVisibleCorners(1);
|
|
else
|
|
setVisibleCorners(0);
|
|
}
|
|
|
|
void Arrow::createCorner(QPointF cornerPos, lineItem *inLine)
|
|
{
|
|
createCorner(cornerPos,myLines.indexOf(inLine));
|
|
}
|
|
|
|
void Arrow::createCorner(QPointF cornerPos, int index)
|
|
{
|
|
if (index != -1)
|
|
{
|
|
myCorners.insert(index,cornerPos);
|
|
lineItem *newLine= new lineItem(QPointF(0,0),QPointF(0,0),this);
|
|
myOwnerScene->addItem(newLine);
|
|
newLine->setZValue(this->zValue());
|
|
addLine(newLine);
|
|
newLine= new lineItem(cornerPos+QPointF(-0.5,-0.5) ,
|
|
cornerPos+QPointF(0.5,0.5),this,6,1);
|
|
myOwnerScene->addItem(newLine);
|
|
newLine->setZValue(this->zValue()+0.1);
|
|
myCLines.insert(index,newLine);
|
|
}
|
|
}
|
|
|
|
void Arrow::moveCorner(QPointF cornerPos, lineItem *inLine)
|
|
{
|
|
int index = myCLines.indexOf(inLine);
|
|
|
|
if (index != -1)
|
|
{
|
|
cornerPos=mapFromItem(inLine,cornerPos);
|
|
myCorners.replace(index,cornerPos);
|
|
updatePosition();
|
|
}
|
|
}
|
|
|
|
void Arrow::setVisibleCorners(bool visible)
|
|
{
|
|
foreach (lineItem *line, myCLines) {
|
|
line->setVisible(visible);
|
|
}
|
|
}
|
|
|
|
QDomElement Arrow::toXml(QDomDocument &document,
|
|
QList<DiagramItem*> sceneItems) const
|
|
{
|
|
QDomElement diagramArrow = document.createElement("Arrow");
|
|
|
|
//Set attibutes; startItem
|
|
diagramArrow.setAttribute("start-x",startOffset().x());
|
|
diagramArrow.setAttribute("start-y",startOffset().y());
|
|
diagramArrow.setAttribute("start-Owner",
|
|
sceneItems.indexOf(startOwner()));
|
|
diagramArrow.setAttribute("start-ID",this->startItem()->textID());
|
|
|
|
//Set attibutes; endItem
|
|
diagramArrow.setAttribute("end-x",endOffset().x());
|
|
diagramArrow.setAttribute("end-y",endOffset().y());
|
|
diagramArrow.setAttribute("end-Owner",
|
|
sceneItems.indexOf(endOwner()));
|
|
diagramArrow.setAttribute("end-ID",this->endItem()->textID());
|
|
|
|
diagramArrow.setAttribute("color",myColor.name());
|
|
|
|
//Corners list
|
|
int i=0;
|
|
if(!myCorners.isEmpty())
|
|
{
|
|
QDomElement arrowCorners = document.createElement("arrowCorners");
|
|
foreach(QPointF corner, myCorners)
|
|
{
|
|
QDomElement arrowCorner = document.createElement("arrowCorner");
|
|
arrowCorner.setAttribute("x",corner.x());
|
|
arrowCorner.setAttribute("y",corner.y());
|
|
i++;
|
|
arrowCorners.appendChild(arrowCorner);
|
|
}
|
|
|
|
diagramArrow.appendChild(arrowCorners);
|
|
}
|
|
return (diagramArrow);
|
|
}
|
|
|
|
void Arrow::snapToGrid(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
//TODO implement polygon drag
|
|
QPointF diffPos= event->scenePos()-previousPos;
|
|
//Update corners:
|
|
for(int i=0; i < myCorners.count();i++)
|
|
{
|
|
myCLines.at(i)->setLine(QLineF(myCLines.at(i)->line().p1()+diffPos,
|
|
myCLines.at(i)->line().p2()+diffPos));
|
|
QPointF itemPos = myCLines.at(i)->line().p1()+QPointF(0.5,0.5);
|
|
moveCorner(itemPos,myCLines.at(i));
|
|
}
|
|
updatePosition();
|
|
}
|
|
|
|
void Arrow::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
//if(this->isSelected())
|
|
{
|
|
previousPos = event->scenePos();
|
|
moving=1;
|
|
}
|
|
QGraphicsPathItem::mousePressEvent(event);
|
|
}
|
|
|
|
void Arrow::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
if(moving && isSelected())
|
|
{
|
|
snapToGrid(event);
|
|
previousPos = event->scenePos();
|
|
}
|
|
moving=0;
|
|
QGraphicsPathItem::mouseReleaseEvent(event);
|
|
}
|
|
|
|
void Arrow::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
if(moving && isSelected())
|
|
{
|
|
snapToGrid(event);
|
|
previousPos = event->scenePos();
|
|
}
|
|
QGraphicsPathItem::mouseMoveEvent(event);
|
|
}
|