710 lines
25 KiB
C++
710 lines
25 KiB
C++
#include <QGraphicsPixmapItem>
|
|
#include <QXmlStreamWriter>
|
|
#include <QFile>
|
|
#include <QApplication>
|
|
#include <QGuiApplication>
|
|
#include <cmath>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <assert.h>
|
|
#include "skeletoneditgraphicsview.h"
|
|
#include "skeletoneditnodeitem.h"
|
|
#include "skeletoneditedgeitem.h"
|
|
#include "theme.h"
|
|
|
|
qreal SkeletonEditGraphicsView::m_initialNodeSize = 128;
|
|
qreal SkeletonEditGraphicsView::m_minimalNodeSize = 8;
|
|
|
|
SkeletonEditGraphicsView::SkeletonEditGraphicsView(QWidget *parent) :
|
|
QGraphicsView(parent),
|
|
m_pendingNodeItem(NULL),
|
|
m_pendingEdgeItem(NULL),
|
|
m_inAddNodeMode(true),
|
|
m_nextStartNodeItem(NULL),
|
|
m_lastHoverNodeItem(NULL),
|
|
m_lastMousePos(0, 0),
|
|
m_isMovingNodeItem(false),
|
|
m_backgroundLoaded(false),
|
|
m_modelWidget(NULL),
|
|
m_modelWidgetProxy(NULL),
|
|
m_combineEnabled(false),
|
|
m_unionEnabled(true),
|
|
m_subdivEnabled(false)
|
|
{
|
|
setScene(new QGraphicsScene());
|
|
|
|
m_modelWidget = new ModelWidget(this);
|
|
m_modelWidget->setMinimumSize(128, 128);
|
|
m_modelWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
m_modelWidget->move(100, 100);
|
|
m_modelWidget->setGraphicsView(this);
|
|
m_modelWidgetProxy = scene()->addWidget(m_modelWidget);
|
|
|
|
m_backgroundItem = new QGraphicsPixmapItem();
|
|
m_backgroundItem->setOpacity(0.25);
|
|
scene()->addItem(m_backgroundItem);
|
|
|
|
m_pendingNodeItem = new QGraphicsEllipseItem(0, 0, m_initialNodeSize, m_initialNodeSize);
|
|
m_pendingNodeItem->setVisible(false);
|
|
scene()->addItem(m_pendingNodeItem);
|
|
|
|
m_pendingEdgeItem = new QGraphicsLineItem(0, 0, 0, 0);
|
|
m_pendingEdgeItem->setVisible(false);
|
|
scene()->addItem(m_pendingEdgeItem);
|
|
}
|
|
|
|
ModelWidget *SkeletonEditGraphicsView::modelWidget()
|
|
{
|
|
return m_modelWidget;
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::toggleAddNodeMode()
|
|
{
|
|
if (!m_backgroundLoaded)
|
|
return;
|
|
m_inAddNodeMode = !m_inAddNodeMode;
|
|
applyAddNodeMode();
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::applyAddNodeMode()
|
|
{
|
|
m_pendingNodeItem->setVisible(m_inAddNodeMode);
|
|
m_pendingEdgeItem->setVisible(m_inAddNodeMode && m_nextStartNodeItem);
|
|
setMouseTracking(true);
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::turnOffAddNodeMode()
|
|
{
|
|
if (!m_backgroundLoaded)
|
|
return;
|
|
m_inAddNodeMode = false;
|
|
applyAddNodeMode();
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::turnOnAddNodeMode()
|
|
{
|
|
if (!m_backgroundLoaded)
|
|
return;
|
|
m_inAddNodeMode = true;
|
|
applyAddNodeMode();
|
|
}
|
|
|
|
SkeletonEditNodeItem *SkeletonEditGraphicsView::findNodeItemByPos(QPointF pos)
|
|
{
|
|
QList<QGraphicsItem *>::iterator it;
|
|
QList<QGraphicsItem *> list = scene()->items();
|
|
for (it = list.begin(); it != list.end(); ++it) {
|
|
if ((*it)->data(0).toString() == "node") {
|
|
SkeletonEditNodeItem *nodeItem = static_cast<SkeletonEditNodeItem *>(*it);
|
|
if (nodeItem->shape().contains(pos)) {
|
|
return nodeItem;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SkeletonEditEdgeItem *SkeletonEditGraphicsView::findEdgeItemByPos(QPointF pos)
|
|
{
|
|
QList<QGraphicsItem *>::iterator it;
|
|
QList<QGraphicsItem *> list = scene()->items();
|
|
for (it = list.begin(); it != list.end(); ++it) {
|
|
if ((*it)->data(0).toString() == "edge") {
|
|
SkeletonEditEdgeItem *edgeItem = static_cast<SkeletonEditEdgeItem *>(*it);
|
|
if (edgeItem->shape().contains(pos)) {
|
|
return edgeItem;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SkeletonEditEdgeItem *SkeletonEditGraphicsView::findEdgeItemByNodePair(SkeletonEditNodeItem *first,
|
|
SkeletonEditNodeItem *second)
|
|
{
|
|
QList<QGraphicsItem *>::iterator it;
|
|
QList<QGraphicsItem *> list = scene()->items();
|
|
assert(first != second);
|
|
for (it = list.begin(); it != list.end(); ++it) {
|
|
if ((*it)->data(0).toString() == "edge") {
|
|
SkeletonEditEdgeItem *edgeItem = static_cast<SkeletonEditEdgeItem *>(*it);
|
|
if ((edgeItem->firstNode() == first || edgeItem->secondNode() == first) &&
|
|
(edgeItem->firstNode() == second || edgeItem->secondNode() == second)) {
|
|
return edgeItem;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::mousePress(QMouseEvent *event, const QPointF &scenePos)
|
|
{
|
|
bool processed = false;
|
|
if (!m_backgroundLoaded)
|
|
return false;
|
|
QPointF pos = scenePos;
|
|
if (event->button() == Qt::LeftButton) {
|
|
if (!m_inAddNodeMode) {
|
|
if (m_lastHoverNodeItem) {
|
|
setNextStartNodeItem(m_lastHoverNodeItem);
|
|
m_lastHoverNodeItem = NULL;
|
|
processed = true;
|
|
} else {
|
|
if (m_nextStartNodeItem) {
|
|
setNextStartNodeItem(NULL);
|
|
processed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
m_lastMousePos = pos;
|
|
return processed;
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::mouseDoubleClick(QMouseEvent *event, const QPointF &scenePos)
|
|
{
|
|
bool processed = false;
|
|
if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
|
|
processed = true;
|
|
emit changeTurnaroundTriggered();
|
|
}
|
|
return processed;
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::removeSelectedItems()
|
|
{
|
|
if (m_nextStartNodeItem) {
|
|
SkeletonEditNodeItem *nodeItem = m_nextStartNodeItem;
|
|
setNextStartNodeItem(NULL);
|
|
removeNodeItem(nodeItem->nextSidePair());
|
|
removeNodeItem(nodeItem);
|
|
emit nodesChanged();
|
|
}
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::removeNodeItem(SkeletonEditNodeItem *nodeItem)
|
|
{
|
|
scene()->removeItem(nodeItem);
|
|
QList<QGraphicsItem *>::iterator it;
|
|
QList<QGraphicsItem *> list = scene()->items();
|
|
for (it = list.begin(); it != list.end(); ++it) {
|
|
if ((*it)->data(0).toString() == "edge") {
|
|
SkeletonEditEdgeItem *edgeItem = static_cast<SkeletonEditEdgeItem *>(*it);
|
|
if (edgeItem->firstNode() == nodeItem || edgeItem->secondNode() == nodeItem) {
|
|
scene()->removeItem(edgeItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::fetchNodeItemAndAllSidePairs(SkeletonEditNodeItem *nodeItem, std::vector<SkeletonEditNodeItem *> *sidePairs)
|
|
{
|
|
sidePairs->push_back(nodeItem);
|
|
sidePairs->push_back(nodeItem->nextSidePair());
|
|
sidePairs->push_back(nodeItem->nextSidePair()->nextSidePair());
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::removeNodeItemAndSidePairs(SkeletonEditNodeItem *nodeItem)
|
|
{
|
|
std::vector<SkeletonEditNodeItem *> nodes;
|
|
fetchNodeItemAndAllSidePairs(nodeItem, &nodes);
|
|
for (size_t i = 0; i < nodes.size(); i++) {
|
|
removeNodeItem(nodes[i]);
|
|
}
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::keyPress(QKeyEvent *event, const QPointF &scenePos)
|
|
{
|
|
bool processed = false;
|
|
if (!m_backgroundLoaded)
|
|
return false;
|
|
if (event->key() == Qt::Key_A) {
|
|
toggleAddNodeMode();
|
|
processed = true;
|
|
} else if (event->key() == Qt::Key_C) {
|
|
m_combineEnabled = !m_combineEnabled;
|
|
emit nodesChanged();
|
|
} else if (event->key() == Qt::Key_U) {
|
|
m_unionEnabled = !m_unionEnabled;
|
|
emit nodesChanged();
|
|
} else if (event->key() == Qt::Key_S) {
|
|
m_subdivEnabled = !m_subdivEnabled;
|
|
emit nodesChanged();
|
|
} else if (event->key() == Qt::Key_Delete || event->key() ==Qt::Key_Backspace) {
|
|
removeSelectedItems();
|
|
processed = true;
|
|
}
|
|
return processed;
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::resizeEvent(QResizeEvent *event)
|
|
{
|
|
QFrame::resizeEvent(event);
|
|
emit sizeChanged();
|
|
}
|
|
|
|
SkeletonEditNodeItem *SkeletonEditGraphicsView::addNodeItemAndSidePairs(QRectF area, SkeletonEditNodeItem *fromNodeItem, const QString &sideColorName)
|
|
{
|
|
float pairedX = 0;
|
|
QRectF pairedRect = area;
|
|
if (fromNodeItem) {
|
|
pairedX = fromNodeItem->nextSidePair()->rect().x();
|
|
} else {
|
|
if (area.center().x() < scene()->sceneRect().width() / 2) {
|
|
pairedX = area.center().x() + scene()->sceneRect().width() / 4;
|
|
} else {
|
|
pairedX = area.center().x() - scene()->sceneRect().width() / 4;
|
|
}
|
|
}
|
|
pairedRect.translate(pairedX - area.x(), 0);
|
|
SkeletonEditNodeItem *firstNode = new SkeletonEditNodeItem(area);
|
|
scene()->addItem(firstNode);
|
|
firstNode->setSideColorName(fromNodeItem ? fromNodeItem->sideColorName() : sideColorName);
|
|
SkeletonEditNodeItem *secondNode = new SkeletonEditNodeItem(pairedRect);
|
|
scene()->addItem(secondNode);
|
|
secondNode->setSideColorName(firstNode->nextSideColorName());
|
|
firstNode->setNextSidePair(secondNode);
|
|
secondNode->setNextSidePair(firstNode);
|
|
setNextStartNodeItem(firstNode);
|
|
if (!fromNodeItem) {
|
|
return firstNode;
|
|
}
|
|
addEdgeItem(fromNodeItem, firstNode);
|
|
addEdgeItem(fromNodeItem->nextSidePair(), firstNode->nextSidePair());
|
|
return firstNode;
|
|
}
|
|
|
|
SkeletonEditNodeItem *SkeletonEditGraphicsView::addNodeItem(float originX, float originY, float radius)
|
|
{
|
|
QRectF area(originX - radius, originY - radius, radius * 2, radius * 2);
|
|
SkeletonEditNodeItem *firstNode = new SkeletonEditNodeItem(area);
|
|
scene()->addItem(firstNode);
|
|
return firstNode;
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::addEdgeItem(SkeletonEditNodeItem *first, SkeletonEditNodeItem *second)
|
|
{
|
|
SkeletonEditEdgeItem *newEdge = new SkeletonEditEdgeItem();
|
|
newEdge->setNodes(first, second);
|
|
scene()->addItem(newEdge);
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::mouseRelease(QMouseEvent *event, const QPointF &scenePos)
|
|
{
|
|
bool processed = false;
|
|
if (!m_backgroundLoaded)
|
|
return false;
|
|
if (event->button() == Qt::LeftButton) {
|
|
if (m_inAddNodeMode) {
|
|
if (m_lastHoverNodeItem && m_nextStartNodeItem &&
|
|
m_lastHoverNodeItem != m_nextStartNodeItem &&
|
|
m_lastHoverNodeItem->sideColor() == m_nextStartNodeItem->sideColor()) {
|
|
if (!findEdgeItemByNodePair(m_lastHoverNodeItem, m_nextStartNodeItem)) {
|
|
addEdgeItem(m_nextStartNodeItem, m_lastHoverNodeItem);
|
|
addEdgeItem(m_nextStartNodeItem->nextSidePair(), m_lastHoverNodeItem->nextSidePair());
|
|
processed = true;
|
|
emit nodesChanged();
|
|
}
|
|
} else {
|
|
addNodeItemAndSidePairs(m_pendingNodeItem->rect(), m_nextStartNodeItem);
|
|
processed = true;
|
|
emit nodesChanged();
|
|
}
|
|
}
|
|
m_isMovingNodeItem = false;
|
|
}
|
|
return processed;
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::canNodeItemMoveTo(SkeletonEditNodeItem *item, QPointF moveTo)
|
|
{
|
|
if (moveTo.x() < 0)
|
|
return false;
|
|
if (moveTo.y() < 0)
|
|
return false;
|
|
if (moveTo.x() + item->rect().width() >= scene()->sceneRect().width())
|
|
return false;
|
|
if (moveTo.y() + item->rect().height() >= scene()->sceneRect().height())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::mouseMove(QMouseEvent *event, const QPointF &scenePos)
|
|
{
|
|
bool processed = false;
|
|
if (!m_backgroundLoaded)
|
|
return false;
|
|
QPointF pos = scenePos;
|
|
QPointF moveTo = QPointF(pos.x() - m_pendingNodeItem->rect().width() / 2, pos.y() - m_pendingNodeItem->rect().height() / 2);
|
|
if (moveTo.x() < 0)
|
|
moveTo.setX(0);
|
|
if (moveTo.y() < 0)
|
|
moveTo.setY(0);
|
|
if (moveTo.x() + m_pendingNodeItem->rect().width() >= scene()->sceneRect().width())
|
|
moveTo.setX(scene()->sceneRect().width() - m_pendingNodeItem->rect().width());
|
|
if (moveTo.y() + m_pendingNodeItem->rect().height() >= scene()->sceneRect().height())
|
|
moveTo.setY(scene()->sceneRect().height() - m_pendingNodeItem->rect().height());
|
|
QSizeF oldSize = m_pendingNodeItem->rect().size();
|
|
m_pendingNodeItem->setRect(moveTo.x(), moveTo.y(),
|
|
oldSize.width(),
|
|
oldSize.height());
|
|
if (m_nextStartNodeItem) {
|
|
m_pendingEdgeItem->setLine(QLineF(m_nextStartNodeItem->origin(), QPointF(moveTo.x() + m_pendingNodeItem->rect().width() / 2,
|
|
moveTo.y() + m_pendingNodeItem->rect().height() / 2)));
|
|
}
|
|
if (!m_isMovingNodeItem) {
|
|
SkeletonEditNodeItem *hoverNodeItem = findNodeItemByPos(pos);
|
|
if (hoverNodeItem) {
|
|
hoverNodeItem->setHovered(true);
|
|
processed = true;
|
|
}
|
|
if (hoverNodeItem != m_lastHoverNodeItem) {
|
|
if (m_lastHoverNodeItem)
|
|
m_lastHoverNodeItem->setHovered(false);
|
|
m_lastHoverNodeItem = hoverNodeItem;
|
|
processed = true;
|
|
}
|
|
}
|
|
QPointF curMousePos = pos;
|
|
if (m_lastHoverNodeItem) {
|
|
if ((event->buttons() & Qt::LeftButton) &&
|
|
(curMousePos != m_lastMousePos || m_isMovingNodeItem)) {
|
|
m_isMovingNodeItem = true;
|
|
QRectF rect = m_lastHoverNodeItem->rect();
|
|
QRectF pairedRect;
|
|
|
|
rect.translate(curMousePos.x() - m_lastMousePos.x(), curMousePos.y() - m_lastMousePos.y());
|
|
pairedRect = m_lastHoverNodeItem->nextSidePair()->rect();
|
|
pairedRect.translate(0, curMousePos.y() - m_lastMousePos.y());
|
|
|
|
m_lastHoverNodeItem->setRect(rect);
|
|
m_lastHoverNodeItem->nextSidePair()->setRect(pairedRect);
|
|
|
|
QList<QGraphicsItem *>::iterator it;
|
|
QList<QGraphicsItem *> list = scene()->items();
|
|
for (it = list.begin(); it != list.end(); ++it) {
|
|
if ((*it)->data(0).toString() == "edge") {
|
|
SkeletonEditEdgeItem *edgeItem = static_cast<SkeletonEditEdgeItem *>(*it);
|
|
if (edgeItem->connects(m_lastHoverNodeItem) ||
|
|
edgeItem->connects(m_lastHoverNodeItem->nextSidePair()))
|
|
edgeItem->updatePosition();
|
|
}
|
|
}
|
|
processed = true;
|
|
emit nodesChanged();
|
|
}
|
|
}
|
|
m_lastMousePos = curMousePos;
|
|
return processed;
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::AddItemRadius(QGraphicsEllipseItem *item, float delta)
|
|
{
|
|
QSizeF oldSize = item->rect().size();
|
|
QPointF originPt = QPointF(item->rect().left() + oldSize.width() / 2,
|
|
item->rect().top() + oldSize.height() / 2);
|
|
QSizeF newSize = QSizeF(oldSize.width() + delta, oldSize.height() + delta);
|
|
if (newSize.width() < m_minimalNodeSize || newSize.height() < m_minimalNodeSize) {
|
|
newSize.setWidth(m_minimalNodeSize);
|
|
newSize.setHeight(m_minimalNodeSize);
|
|
}
|
|
QPointF newLeftTop = QPointF(originPt.x() - newSize.width() / 2,
|
|
originPt.y() - newSize.height() / 2);
|
|
if (newLeftTop.x() < 0 || newLeftTop.x() + newSize.width() >= scene()->sceneRect().width())
|
|
return;
|
|
if (newLeftTop.y() < 0 || newLeftTop.y() + newSize.height() >= scene()->sceneRect().height())
|
|
return;
|
|
item->setRect(newLeftTop.x(),
|
|
newLeftTop.y(),
|
|
newSize.width(),
|
|
newSize.height());
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::canAddItemRadius(QGraphicsEllipseItem *item, float delta)
|
|
{
|
|
QSizeF oldSize = item->rect().size();
|
|
QPointF originPt = QPointF(item->rect().left() + oldSize.width() / 2,
|
|
item->rect().top() + oldSize.height() / 2);
|
|
QSizeF newSize = QSizeF(oldSize.width() + delta, oldSize.height() + delta);
|
|
if (newSize.width() < m_minimalNodeSize || newSize.height() < m_minimalNodeSize) {
|
|
newSize.setWidth(m_minimalNodeSize);
|
|
newSize.setHeight(m_minimalNodeSize);
|
|
}
|
|
QPointF newLeftTop = QPointF(originPt.x() - newSize.width() / 2,
|
|
originPt.y() - newSize.height() / 2);
|
|
if (newLeftTop.x() < 0 || newLeftTop.x() + newSize.width() >= scene()->sceneRect().width())
|
|
return false;
|
|
if (newLeftTop.y() < 0 || newLeftTop.y() + newSize.height() >= scene()->sceneRect().height())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::wheel(QWheelEvent *event, const QPointF &scenePos)
|
|
{
|
|
bool processed = false;
|
|
if (!m_backgroundLoaded)
|
|
return false;
|
|
qreal delta = event->delta() / 10;
|
|
if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier)) {
|
|
if (delta > 0)
|
|
delta = 1;
|
|
else
|
|
delta = -1;
|
|
} else {
|
|
if (fabs(delta) < 1)
|
|
delta = delta < 0 ? -1.0 : 1.0;
|
|
}
|
|
AddItemRadius(m_pendingNodeItem, delta);
|
|
if (!m_inAddNodeMode && m_lastHoverNodeItem) {
|
|
AddItemRadius(m_lastHoverNodeItem, delta);
|
|
processed = true;
|
|
emit nodesChanged();
|
|
}
|
|
if (m_inAddNodeMode)
|
|
processed = true;
|
|
return processed;
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::setNextStartNodeItem(SkeletonEditNodeItem *item)
|
|
{
|
|
if (m_nextStartNodeItem != item) {
|
|
if (m_nextStartNodeItem)
|
|
m_nextStartNodeItem->setChecked(false);
|
|
}
|
|
m_nextStartNodeItem = item;
|
|
if (m_nextStartNodeItem)
|
|
m_nextStartNodeItem->setChecked(true);
|
|
applyAddNodeMode();
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::updateBackgroundImage(const QImage &image)
|
|
{
|
|
QSizeF oldSceneSize = scene()->sceneRect().size();
|
|
QPixmap pixmap = QPixmap::fromImage(image);
|
|
scene()->setSceneRect(pixmap.rect());
|
|
m_backgroundItem->setPixmap(pixmap);
|
|
adjustItems(oldSceneSize, scene()->sceneRect().size());
|
|
if (!m_backgroundLoaded) {
|
|
m_backgroundLoaded = true;
|
|
applyAddNodeMode();
|
|
}
|
|
}
|
|
|
|
QPixmap SkeletonEditGraphicsView::backgroundImage()
|
|
{
|
|
return m_backgroundItem->pixmap();
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::hasBackgroundImage()
|
|
{
|
|
return m_backgroundLoaded;
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::adjustItems(QSizeF oldSceneSize, QSizeF newSceneSize)
|
|
{
|
|
if (oldSceneSize == newSceneSize)
|
|
return;
|
|
float radiusMul = (float)newSceneSize.height() / oldSceneSize.height();
|
|
float xMul = (float)newSceneSize.width() / oldSceneSize.width();
|
|
float yMul = radiusMul;
|
|
QList<QGraphicsItem *>::iterator it;
|
|
QList<QGraphicsItem *> list = scene()->items();
|
|
for (it = list.begin(); it != list.end(); ++it) {
|
|
if ((*it)->data(0).toString() == "node") {
|
|
SkeletonEditNodeItem *nodeItem = static_cast<SkeletonEditNodeItem *>(*it);
|
|
nodeItem->setRadius(nodeItem->radius() * radiusMul);
|
|
QPointF oldOrigin = nodeItem->origin();
|
|
nodeItem->setOrigin(QPointF(oldOrigin.x() * xMul, oldOrigin.y() * yMul));
|
|
}
|
|
}
|
|
for (it = list.begin(); it != list.end(); ++it) {
|
|
if ((*it)->data(0).toString() == "edge") {
|
|
SkeletonEditEdgeItem *edgeItem = static_cast<SkeletonEditEdgeItem *>(*it);
|
|
edgeItem->updatePosition();
|
|
}
|
|
}
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::loadFromSnapshot(SkeletonSnapshot *snapshot)
|
|
{
|
|
float radiusMul = 1.0;
|
|
float xMul = 1.0;
|
|
float yMul = radiusMul;
|
|
|
|
QString canvasWidth = snapshot->canvas["width"];
|
|
QString canvasHeight = snapshot->canvas["height"];
|
|
float canvasWidthVal = canvasWidth.toFloat();
|
|
float canvasHeightVal = canvasHeight.toFloat();
|
|
if (!hasBackgroundImage()) {
|
|
QPixmap emptyImage((int)canvasWidthVal, (int)canvasHeightVal);
|
|
emptyImage.fill(QWidget::palette().color(QWidget::backgroundRole()));
|
|
updateBackgroundImage(emptyImage.toImage());
|
|
}
|
|
if (canvasHeightVal > 0)
|
|
radiusMul = (float)scene()->sceneRect().height() / canvasHeightVal;
|
|
if (canvasWidthVal > 0)
|
|
xMul = (float)scene()->sceneRect().width() / canvasWidthVal;
|
|
yMul = radiusMul;
|
|
|
|
std::map<QString, SkeletonEditNodeItem *> nodeItemMap;
|
|
std::map<QString, std::map<QString, QString>>::iterator nodeIterator;
|
|
for (nodeIterator = snapshot->nodes.begin(); nodeIterator != snapshot->nodes.end(); nodeIterator++) {
|
|
std::map<QString, QString> *snapshotNode = &nodeIterator->second;
|
|
SkeletonEditNodeItem *nodeItem = addNodeItem((*snapshotNode)["x"].toFloat() * xMul,
|
|
(*snapshotNode)["y"].toFloat() * yMul,
|
|
(*snapshotNode)["radius"].toFloat() * radiusMul);
|
|
nodeItem->setSideColorName((*snapshotNode)["sideColorName"]);
|
|
nodeItem->markAsBranch("true" == (*snapshotNode)["isBranch"]);
|
|
nodeItemMap[nodeIterator->first] = nodeItem;
|
|
}
|
|
for (nodeIterator = snapshot->nodes.begin(); nodeIterator != snapshot->nodes.end(); nodeIterator++) {
|
|
std::map<QString, QString> *snapshotNode = &nodeIterator->second;
|
|
SkeletonEditNodeItem *nodeItem = nodeItemMap[nodeIterator->first];
|
|
nodeItem->setNextSidePair(nodeItemMap[(*snapshotNode)["nextSidePair"]]);
|
|
}
|
|
|
|
std::map<QString, std::map<QString, QString>>::iterator edgeIterator;
|
|
for (edgeIterator = snapshot->edges.begin(); edgeIterator != snapshot->edges.end(); edgeIterator++) {
|
|
std::map<QString, QString> *snapshotEdge = &edgeIterator->second;
|
|
addEdgeItem(nodeItemMap[(*snapshotEdge)["from"]], nodeItemMap[(*snapshotEdge)["to"]]);
|
|
}
|
|
|
|
emit nodesChanged();
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::saveToSnapshot(SkeletonSnapshot *snapshot)
|
|
{
|
|
snapshot->canvas["width"] = QString("%1").arg(scene()->sceneRect().width());
|
|
snapshot->canvas["height"] = QString("%1").arg(scene()->sceneRect().height());
|
|
snapshot->canvas["combine"] = m_combineEnabled ? "true" : "false";
|
|
snapshot->canvas["union"] = m_unionEnabled ? "true" : "false";
|
|
snapshot->canvas["subdiv"] = m_subdivEnabled ? "true" : "false";
|
|
|
|
QList<QGraphicsItem *>::iterator it;
|
|
QList<QGraphicsItem *> list = scene()->items();
|
|
|
|
int nextNodeId = 1;
|
|
std::map<SkeletonEditNodeItem *, QString> nodeIdMap;
|
|
for (it = list.begin(); it != list.end(); ++it) {
|
|
if ((*it)->data(0).toString() == "node") {
|
|
SkeletonEditNodeItem *nodeItem = static_cast<SkeletonEditNodeItem *>(*it);
|
|
QString nodeId = QString("node%1").arg(nextNodeId);
|
|
std::map<QString, QString> *snapshotNode = &snapshot->nodes[nodeId];
|
|
(*snapshotNode)["id"] = nodeId;
|
|
(*snapshotNode)["sideColorName"] = nodeItem->sideColorName();
|
|
(*snapshotNode)["radius"] = QString("%1").arg(nodeItem->radius());
|
|
(*snapshotNode)["isBranch"] = QString("%1").arg(nodeItem->isBranch() ? "true" : "false");
|
|
(*snapshotNode)["isRoot"] = QString("%1").arg(nodeItem->isRoot() ? "true" : "false");
|
|
QPointF origin = nodeItem->origin();
|
|
(*snapshotNode)["x"] = QString("%1").arg(origin.x());
|
|
(*snapshotNode)["y"] = QString("%1").arg(origin.y());
|
|
nodeIdMap[nodeItem] = nodeId;
|
|
nextNodeId++;
|
|
}
|
|
}
|
|
|
|
for (it = list.begin(); it != list.end(); ++it) {
|
|
if ((*it)->data(0).toString() == "node") {
|
|
SkeletonEditNodeItem *nodeItem = static_cast<SkeletonEditNodeItem *>(*it);
|
|
QString nodeId = nodeIdMap[nodeItem];
|
|
std::map<QString, QString> *snapshotNode = &snapshot->nodes[nodeId];
|
|
(*snapshotNode)["nextSidePair"] = nodeIdMap[nodeItem->nextSidePair()];
|
|
}
|
|
}
|
|
|
|
int nextEdgeId = 1;
|
|
for (it = list.begin(); it != list.end(); ++it) {
|
|
if ((*it)->data(0).toString() == "edge") {
|
|
SkeletonEditEdgeItem *edgeItem = static_cast<SkeletonEditEdgeItem *>(*it);
|
|
QString edgeId = QString("edge%1").arg(nextEdgeId);
|
|
std::map<QString, QString> *snapshotEdge = &snapshot->edges[edgeId];
|
|
(*snapshotEdge)["id"] = edgeId;
|
|
(*snapshotEdge)["from"] = nodeIdMap[edgeItem->firstNode()];
|
|
(*snapshotEdge)["to"] = nodeIdMap[edgeItem->secondNode()];
|
|
nextEdgeId++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::markAsBranch()
|
|
{
|
|
if (m_nextStartNodeItem) {
|
|
m_nextStartNodeItem->markAsBranch(true);
|
|
m_nextStartNodeItem->nextSidePair()->markAsBranch(true);
|
|
emit nodesChanged();
|
|
}
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::markAsTrunk()
|
|
{
|
|
if (m_nextStartNodeItem) {
|
|
m_nextStartNodeItem->markAsBranch(false);
|
|
m_nextStartNodeItem->nextSidePair()->markAsBranch(false);
|
|
emit nodesChanged();
|
|
}
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::markAsRoot()
|
|
{
|
|
if (m_nextStartNodeItem) {
|
|
m_nextStartNodeItem->markAsRoot(true);
|
|
m_nextStartNodeItem->nextSidePair()->markAsRoot(true);
|
|
emit nodesChanged();
|
|
}
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::markAsChild()
|
|
{
|
|
if (m_nextStartNodeItem) {
|
|
m_nextStartNodeItem->markAsRoot(false);
|
|
m_nextStartNodeItem->nextSidePair()->markAsRoot(false);
|
|
emit nodesChanged();
|
|
}
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::mouseMoveEvent(QMouseEvent *event)
|
|
{
|
|
mouseMove(event, mapToScene(event->pos()));
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::wheelEvent(QWheelEvent *event)
|
|
{
|
|
wheel(event, mapToScene(event->pos()));
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::mouseReleaseEvent(QMouseEvent *event)
|
|
{
|
|
mouseRelease(event, mapToScene(event->pos()));
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::mousePressEvent(QMouseEvent *event)
|
|
{
|
|
mousePress(event, mapToScene(event->pos()));
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::mouseDoubleClickEvent(QMouseEvent *event)
|
|
{
|
|
mouseDoubleClick(event, mapToScene(event->pos()));
|
|
}
|
|
|
|
void SkeletonEditGraphicsView::keyPressEvent(QKeyEvent *event)
|
|
{
|
|
keyPress(event, QPointF());
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::combineEnabled()
|
|
{
|
|
return m_combineEnabled;
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::unionEnabled()
|
|
{
|
|
return m_unionEnabled;
|
|
}
|
|
|
|
bool SkeletonEditGraphicsView::subdivEnabled()
|
|
{
|
|
return m_subdivEnabled;
|
|
}
|
|
|