287 lines
8.9 KiB
C++
287 lines
8.9 KiB
C++
#ifndef GRAPHICSBASEITEM_H
|
||
#define GRAPHICSBASEITEM_H
|
||
|
||
#include "itemControlHandle.h"
|
||
|
||
#include <QObject>
|
||
#include <QGraphicsItem>
|
||
#include <QGraphicsSceneMouseEvent>
|
||
#include <QPen>
|
||
|
||
//基类采用模板形式,QGraphicsItem是默认值,也可以是别的类型,比如QGraphicsItemGroup,这样不同的基类继承可以共用一些高层的行为定义
|
||
template <typename BaseType = QGraphicsItem>
|
||
class AbstractShapeType : public BaseType
|
||
{
|
||
public:
|
||
explicit AbstractShapeType(QGraphicsItem *parent = 0)
|
||
: BaseType(parent)
|
||
{
|
||
m_pen = QPen(Qt::NoPen);
|
||
m_brush = QBrush(QColor(rand() % 32 * 8, rand() % 32 * 8, rand() % 32 * 8));
|
||
m_dWidth = m_dHeight = 0;
|
||
m_pOperationCopy = nullptr;
|
||
}
|
||
|
||
virtual ~AbstractShapeType()
|
||
{
|
||
for (size_t i = 0; i < m_vecHanle.size(); i++)
|
||
{
|
||
ItemControlHandle* pHandle = m_vecHanle[i];
|
||
if (pHandle)
|
||
{
|
||
delete pHandle;
|
||
pHandle = nullptr;
|
||
}
|
||
}
|
||
}
|
||
|
||
public:
|
||
QPen pen() { return m_pen; }
|
||
void setPen(const QPen &pen) { m_pen = pen; }
|
||
QColor penColor() { return m_pen.color(); }
|
||
void setPenColor(const QColor &color) { m_pen.setColor(color); }
|
||
|
||
QBrush brush() { return m_brush; }
|
||
void setBrush(const QBrush &brush) { m_brush = brush; }
|
||
QColor brushColor() { return m_brush.color(); }
|
||
void setBrushColor(const QColor &color) { m_brush.setColor(color); }
|
||
|
||
double width() { return m_dWidth; }
|
||
void setWidth(double width)
|
||
{
|
||
m_dWidth = width;
|
||
updateCoordinate();
|
||
}
|
||
|
||
double height() { return m_dHeight; }
|
||
void setHeight(double height)
|
||
{
|
||
m_dHeight = height;
|
||
updateCoordinate();
|
||
}
|
||
|
||
int collidesWithHandle(const QPointF& point)
|
||
{
|
||
for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++)
|
||
{
|
||
QPointF pt = (*it)->mapFromScene(point);
|
||
if((*it)->contains(pt))
|
||
return (*it)->getTag();
|
||
}
|
||
return HandleTag::H_none;
|
||
}
|
||
|
||
//操作副本相关
|
||
virtual void createOperationCopy() {}
|
||
virtual void removeOperationCopy() {}
|
||
virtual void moveOperationCopy(const QPointF&) {}
|
||
virtual void rotateOperationCopy(const double&) {}
|
||
|
||
virtual void resize(int,double, double, const QPointF&) {}
|
||
virtual void move(const QPointF&) {}
|
||
virtual void editShape(int, const QPointF&) {}
|
||
|
||
virtual void updateCoordinate() {}
|
||
|
||
//handle相关
|
||
virtual int handleCount() { return m_vecHanle.count(); }
|
||
virtual ItemControlHandle* getHandle(int nHandle)
|
||
{
|
||
ItemControlHandle* handle = nullptr;
|
||
for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++)
|
||
{
|
||
if((*it)->getTag() == nHandle)
|
||
{
|
||
handle = (*it);
|
||
return handle;
|
||
}
|
||
}
|
||
return handle;
|
||
}
|
||
virtual void setHandleVisible(bool bVisible)
|
||
{
|
||
for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++)
|
||
{
|
||
if(bVisible)
|
||
(*it)->show();
|
||
else
|
||
(*it)->hide();
|
||
}
|
||
}
|
||
virtual QPointF getSymmetricPointPos(int nHandle) //获取对称点的坐标位置,缩放的时候需要以对称点为锚点
|
||
{
|
||
QPointF pt;
|
||
//编号从1开始,因此下标需要-1
|
||
switch (nHandle)
|
||
{
|
||
case H_leftTop:
|
||
pt = m_vecHanle.at(H_rightBottom - 1)->pos();
|
||
break;
|
||
case H_top:
|
||
pt = m_vecHanle.at(H_bottom - 1)->pos();
|
||
break;
|
||
case H_rightTop:
|
||
pt = m_vecHanle.at(H_leftBottom - 1)->pos();
|
||
break;
|
||
case H_right:
|
||
pt = m_vecHanle.at(H_left - 1)->pos();
|
||
break;
|
||
case H_rightBottom:
|
||
pt = m_vecHanle.at(H_leftTop - 1)->pos();
|
||
break;
|
||
case H_bottom:
|
||
pt = m_vecHanle.at(H_top - 1)->pos();
|
||
break;
|
||
case H_leftBottom:
|
||
pt = m_vecHanle.at(H_rightTop - 1)->pos();
|
||
break;
|
||
case H_left:
|
||
pt = m_vecHanle.at(H_right - 1)->pos();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return pt;
|
||
}
|
||
virtual void updateHandles()
|
||
{
|
||
int nMargin = 5;
|
||
const QRectF& boundRect = this->boundingRect();
|
||
for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++)
|
||
{
|
||
switch ((*it)->getTag()) {
|
||
case H_leftTop:
|
||
(*it)->move(boundRect.x() - nMargin, boundRect.y() - nMargin);
|
||
break;
|
||
case H_top:
|
||
(*it)->move(boundRect.x() + boundRect.width() * 0.5, boundRect.y() - nMargin);
|
||
break;
|
||
case H_rightTop:
|
||
(*it)->move(boundRect.x() + boundRect.width() + nMargin, boundRect.y() - nMargin);
|
||
break;
|
||
case H_right:
|
||
(*it)->move(boundRect.x() + boundRect.width() + nMargin, boundRect.y() + boundRect.height() * 0.5 + nMargin);
|
||
break;
|
||
case H_rightBottom:
|
||
(*it)->move(boundRect.x() + boundRect.width() + nMargin, boundRect.y() + boundRect.height() + nMargin);
|
||
break;
|
||
case H_bottom:
|
||
(*it)->move(boundRect.x() + boundRect.width() * 0.5, boundRect.y() + boundRect.height()+ nMargin);
|
||
break;
|
||
case H_leftBottom:
|
||
(*it)->move(boundRect.x() - nMargin, boundRect.y() + boundRect.height() + nMargin);
|
||
break;
|
||
case H_left:
|
||
(*it)->move(boundRect.x() - nMargin, boundRect.y() + boundRect.height() * 0.5);
|
||
break;
|
||
case H_rotate_leftTop:
|
||
{
|
||
ItemControlHandle* handle = getHandle(H_leftTop);
|
||
if(handle)
|
||
{
|
||
int nSize = handle->getSize();
|
||
QPointF pt = handle->pos();
|
||
(*it)->move(pt.x() - nSize - 1, pt.y() - nSize - 1);
|
||
}
|
||
else
|
||
(*it)->setVisible(false);
|
||
|
||
break;
|
||
}
|
||
case H_rotate_rightTop:
|
||
{
|
||
ItemControlHandle* handle = getHandle(H_rightTop);
|
||
if(handle)
|
||
{
|
||
int nSize = handle->getSize();
|
||
QPointF pt = handle->pos();
|
||
(*it)->move(pt.x() + nSize + 1, pt.y() - nSize - 1);
|
||
}
|
||
else
|
||
(*it)->setVisible(false);
|
||
|
||
break;
|
||
}
|
||
case H_rotate_rightBottom:
|
||
{
|
||
ItemControlHandle* handle = getHandle(H_rightBottom);
|
||
if(handle)
|
||
{
|
||
int nSize = handle->getSize();
|
||
QPointF pt = handle->pos();
|
||
(*it)->move(pt.x() + nSize + 1, pt.y() + nSize + 1);
|
||
}
|
||
else
|
||
(*it)->setVisible(false);
|
||
|
||
break;
|
||
}
|
||
case H_rotate_leftBottom:
|
||
{
|
||
ItemControlHandle* handle = getHandle(H_leftBottom);
|
||
if(handle)
|
||
{
|
||
int nSize = handle->getSize();
|
||
QPointF pt = handle->pos();
|
||
(*it)->move(pt.x() - nSize - 1, pt.y() + nSize + 1);
|
||
}
|
||
else
|
||
(*it)->setVisible(false);
|
||
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
m_boundingRect_selected = boundRect.adjusted(-nMargin, -nMargin, nMargin, nMargin);
|
||
}
|
||
|
||
virtual QRectF boundingRect() const { return m_boundingRect; }
|
||
virtual QPainterPath shape()
|
||
{
|
||
QPainterPath path;
|
||
return path;
|
||
}
|
||
|
||
protected:
|
||
QPen m_pen;
|
||
QBrush m_brush;
|
||
double m_dWidth;
|
||
double m_dHeight;
|
||
QRectF m_boundingRect;
|
||
QRectF m_boundingRect_selected;//选中矩形框
|
||
|
||
QGraphicsPathItem* m_pOperationCopy; //图元移动和旋转时的操作副本
|
||
QPointF m_movingIniPos; //移动副本开始移动初始点
|
||
|
||
QVector<ItemControlHandle*> m_vecHanle;
|
||
};
|
||
|
||
typedef AbstractShapeType<QGraphicsItem> AbstractShape;
|
||
|
||
class GraphicsBaseItem : public QObject, public AbstractShapeType<QGraphicsItem>
|
||
{
|
||
Q_OBJECT
|
||
|
||
public:
|
||
GraphicsBaseItem(QGraphicsItem *parent);
|
||
virtual ~GraphicsBaseItem();
|
||
|
||
virtual void createOperationCopy();
|
||
virtual void removeOperationCopy();
|
||
virtual void moveOperationCopy(const QPointF&);
|
||
virtual void rotateOperationCopy(const double&);
|
||
//多边形、线段等点选创建的对象需要的函数
|
||
virtual void addPoint(const QPointF&) {}
|
||
virtual bool endDrawing() { return true; }
|
||
|
||
protected:
|
||
virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange, const QVariant&);
|
||
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent*);
|
||
};
|
||
|
||
#endif
|