master
Jeremy Hu 2018-04-09 22:24:30 +08:00
parent 5e97e3d268
commit 62fdcbdced
7 changed files with 114 additions and 28 deletions

View File

@ -32,6 +32,7 @@ int main(int argc, char ** argv)
darkPalette.setColor(QPalette::ToolTipBase, Theme::white); darkPalette.setColor(QPalette::ToolTipBase, Theme::white);
darkPalette.setColor(QPalette::ToolTipText, Theme::white); darkPalette.setColor(QPalette::ToolTipText, Theme::white);
darkPalette.setColor(QPalette::Text, Theme::white); darkPalette.setColor(QPalette::Text, Theme::white);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, Theme::black);
darkPalette.setColor(QPalette::Button, QColor(53,53,53)); darkPalette.setColor(QPalette::Button, QColor(53,53,53));
darkPalette.setColor(QPalette::ButtonText, Theme::white); darkPalette.setColor(QPalette::ButtonText, Theme::white);
darkPalette.setColor(QPalette::BrightText, Theme::red); darkPalette.setColor(QPalette::BrightText, Theme::red);

View File

@ -14,7 +14,8 @@ unsigned long SkeletonDocument::m_maxSnapshot = 1000;
SkeletonDocument::SkeletonDocument() : SkeletonDocument::SkeletonDocument() :
m_resultMeshIsObsolete(false), m_resultMeshIsObsolete(false),
m_resultMesh(nullptr), m_resultMesh(nullptr),
m_meshGenerator(nullptr) m_meshGenerator(nullptr),
m_batchChangeRefCount(0)
{ {
} }
@ -754,9 +755,24 @@ void SkeletonDocument::meshReady()
} }
} }
void SkeletonDocument::batchChangeBegin()
{
m_batchChangeRefCount++;
}
void SkeletonDocument::batchChangeEnd()
{
m_batchChangeRefCount--;
if (0 == m_batchChangeRefCount) {
if (m_resultMeshIsObsolete) {
generateMesh();
}
}
}
void SkeletonDocument::generateMesh() void SkeletonDocument::generateMesh()
{ {
if (nullptr != m_meshGenerator) { if (nullptr != m_meshGenerator || m_batchChangeRefCount > 0) {
m_resultMeshIsObsolete = true; m_resultMeshIsObsolete = true;
return; return;
} }
@ -867,3 +883,15 @@ void SkeletonDocument::paste()
addFromSnapshot(snapshot); addFromSnapshot(snapshot);
} }
} }
bool SkeletonDocument::hasPastableContentInClipboard() const
{
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
if (mimeData->hasText()) {
if (-1 != mimeData->text().left(1000).indexOf("partIdList"))
return true;
}
return false;
}

View File

@ -106,6 +106,13 @@ public:
} }
}; };
enum class SkeletonProfile
{
Unknown = 0,
Main,
Side
};
class SkeletonHistoryItem class SkeletonHistoryItem
{ {
public: public:
@ -121,13 +128,6 @@ enum class SkeletonDocumentEditMode
ZoomOut ZoomOut
}; };
enum class SkeletonProfile
{
Unknown = 0,
Main,
Side
};
class SkeletonDocument : public QObject class SkeletonDocument : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -170,6 +170,7 @@ public:
Mesh *takeResultMesh(); Mesh *takeResultMesh();
QImage preview; QImage preview;
void updateTurnaround(const QImage &image); void updateTurnaround(const QImage &image);
bool hasPastableContentInClipboard() const;
public slots: public slots:
void removeNode(QUuid nodeId); void removeNode(QUuid nodeId);
void removeEdge(QUuid edgeId); void removeEdge(QUuid edgeId);
@ -193,6 +194,8 @@ public slots:
void undo(); void undo();
void redo(); void redo();
void paste(); void paste();
void batchChangeBegin();
void batchChangeEnd();
private: private:
void splitPartByNode(std::vector<std::vector<QUuid>> *groups, QUuid nodeId); void splitPartByNode(std::vector<std::vector<QUuid>> *groups, QUuid nodeId);
void joinNodeAndNeiborsToGroup(std::vector<QUuid> *group, QUuid nodeId, std::set<QUuid> *visitMap, QUuid noUseEdgeId=QUuid()); void joinNodeAndNeiborsToGroup(std::vector<QUuid> *group, QUuid nodeId, std::set<QUuid> *visitMap, QUuid noUseEdgeId=QUuid());
@ -205,6 +208,7 @@ private:
static unsigned long m_maxSnapshot; static unsigned long m_maxSnapshot;
std::deque<SkeletonHistoryItem> m_undoItems; std::deque<SkeletonHistoryItem> m_undoItems;
std::deque<SkeletonHistoryItem> m_redoItems; std::deque<SkeletonHistoryItem> m_redoItems;
int m_batchChangeRefCount;
}; };
#endif #endif

View File

@ -195,6 +195,8 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
connect(graphicsWidget, &SkeletonGraphicsWidget::redo, m_document, &SkeletonDocument::redo); connect(graphicsWidget, &SkeletonGraphicsWidget::redo, m_document, &SkeletonDocument::redo);
connect(graphicsWidget, &SkeletonGraphicsWidget::paste, m_document, &SkeletonDocument::paste); connect(graphicsWidget, &SkeletonGraphicsWidget::paste, m_document, &SkeletonDocument::paste);
connect(graphicsWidget, &SkeletonGraphicsWidget::changeTurnaround, this, &SkeletonDocumentWindow::changeTurnaround); connect(graphicsWidget, &SkeletonGraphicsWidget::changeTurnaround, this, &SkeletonDocumentWindow::changeTurnaround);
connect(graphicsWidget, &SkeletonGraphicsWidget::batchChangeBegin, m_document, &SkeletonDocument::batchChangeBegin);
connect(graphicsWidget, &SkeletonGraphicsWidget::batchChangeEnd, m_document, &SkeletonDocument::batchChangeEnd);
connect(m_document, &SkeletonDocument::nodeAdded, graphicsWidget, &SkeletonGraphicsWidget::nodeAdded); connect(m_document, &SkeletonDocument::nodeAdded, graphicsWidget, &SkeletonGraphicsWidget::nodeAdded);
connect(m_document, &SkeletonDocument::nodeRemoved, graphicsWidget, &SkeletonGraphicsWidget::nodeRemoved); connect(m_document, &SkeletonDocument::nodeRemoved, graphicsWidget, &SkeletonGraphicsWidget::nodeRemoved);

View File

@ -102,10 +102,23 @@ void SkeletonGraphicsWidget::showContextMenu(const QPoint &pos)
QAction pasteAction("Paste", this); QAction pasteAction("Paste", this);
connect(&pasteAction, &QAction::triggered, m_document, &SkeletonDocument::paste); connect(&pasteAction, &QAction::triggered, m_document, &SkeletonDocument::paste);
pasteAction.setEnabled(m_document->hasPastableContentInClipboard());
contextMenu.addAction(&pasteAction); contextMenu.addAction(&pasteAction);
contextMenu.addSeparator(); contextMenu.addSeparator();
QAction flipHorizontallyAction("H Flip", this);
connect(&flipHorizontallyAction, &QAction::triggered, this, &SkeletonGraphicsWidget::flipHorizontally);
flipHorizontallyAction.setEnabled(!m_rangeSelectionSet.empty());
contextMenu.addAction(&flipHorizontallyAction);
QAction flipVerticallyAction("V Flip", this);
connect(&flipVerticallyAction, &QAction::triggered, this, &SkeletonGraphicsWidget::flipVertically);
flipVerticallyAction.setEnabled(!m_rangeSelectionSet.empty());
contextMenu.addAction(&flipVerticallyAction);
contextMenu.addSeparator();
QAction selectAllAction("Select All", this); QAction selectAllAction("Select All", this);
connect(&selectAllAction, &QAction::triggered, this, &SkeletonGraphicsWidget::selectAll); connect(&selectAllAction, &QAction::triggered, this, &SkeletonGraphicsWidget::selectAll);
selectAllAction.setEnabled(!nodeItemMap.empty()); selectAllAction.setEnabled(!nodeItemMap.empty());
@ -123,18 +136,6 @@ void SkeletonGraphicsWidget::showContextMenu(const QPoint &pos)
contextMenu.addSeparator(); contextMenu.addSeparator();
QAction addMirrorAction("Mirror", this);
connect(&addMirrorAction, &QAction::triggered, this, &SkeletonGraphicsWidget::addMirror);
addMirrorAction.setEnabled(readSkeletonNodeAndAnyEdgeOfNodeFromRangeSelection(nullptr, nullptr));
contextMenu.addAction(&addMirrorAction);
QAction deleteMirrorAction("Delete Mirror", this);
connect(&deleteMirrorAction, &QAction::triggered, this, &SkeletonGraphicsWidget::deleteMirror);
deleteMirrorAction.setEnabled(readSkeletonNodeAndAnyEdgeOfNodeFromRangeSelection(nullptr, nullptr));
contextMenu.addAction(&deleteMirrorAction);
contextMenu.addSeparator();
QAction changeTurnaroundAction("Change Turnaround..", this); QAction changeTurnaroundAction("Change Turnaround..", this);
connect(&changeTurnaroundAction, &QAction::triggered, [=]() { connect(&changeTurnaroundAction, &QAction::triggered, [=]() {
emit changeTurnaround(); emit changeTurnaround();
@ -425,11 +426,7 @@ bool SkeletonGraphicsWidget::wheel(QWheelEvent *event)
readMergedSkeletonNodeSetFromRangeSelection(&nodeItems); readMergedSkeletonNodeSetFromRangeSelection(&nodeItems);
float unifiedDelta = sceneRadiusToUnified(delta); float unifiedDelta = sceneRadiusToUnified(delta);
if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier)) { if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier)) {
QVector2D center; QVector2D center = centerOfNodeItemSet(nodeItems);
for (const auto &nodeItem: nodeItems) {
center += QVector2D(nodeItem->origin());
}
center /= nodeItems.size();
for (const auto &nodeItem: nodeItems) { for (const auto &nodeItem: nodeItems) {
QVector2D origin = QVector2D(nodeItem->origin()); QVector2D origin = QVector2D(nodeItem->origin());
QVector2D ray = (center - origin) * 0.01 * delta; QVector2D ray = (center - origin) * 0.01 * delta;
@ -459,6 +456,50 @@ bool SkeletonGraphicsWidget::wheel(QWheelEvent *event)
return false; return false;
} }
QVector2D SkeletonGraphicsWidget::centerOfNodeItemSet(const std::set<SkeletonGraphicsNodeItem *> &set)
{
QVector2D center;
for (const auto &nodeItem: set) {
center += QVector2D(nodeItem->origin());
}
center /= set.size();
return center;
}
void SkeletonGraphicsWidget::flipHorizontally()
{
std::set<SkeletonGraphicsNodeItem *> nodeItems;
readMergedSkeletonNodeSetFromRangeSelection(&nodeItems);
if (nodeItems.empty())
return;
QVector2D center = centerOfNodeItemSet(nodeItems);
for (const auto &nodeItem: nodeItems) {
QPointF origin = nodeItem->origin();
float offset = origin.x() - center.x();
float unifiedOffset = -sceneRadiusToUnified(offset * 2);
if (SkeletonProfile::Main == nodeItem->profile()) {
emit moveNodeBy(nodeItem->id(), unifiedOffset, 0, 0);
} else {
emit moveNodeBy(nodeItem->id(), 0, 0, unifiedOffset);
}
}
}
void SkeletonGraphicsWidget::flipVertically()
{
std::set<SkeletonGraphicsNodeItem *> nodeItems;
readMergedSkeletonNodeSetFromRangeSelection(&nodeItems);
if (nodeItems.empty())
return;
QVector2D center = centerOfNodeItemSet(nodeItems);
for (const auto &nodeItem: nodeItems) {
QPointF origin = nodeItem->origin();
float offset = origin.y() - center.y();
float unifiedOffset = -sceneRadiusToUnified(offset * 2);
emit moveNodeBy(nodeItem->id(), 0, unifiedOffset, 0);
}
}
bool SkeletonGraphicsWidget::mouseRelease(QMouseEvent *event) bool SkeletonGraphicsWidget::mouseRelease(QMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
@ -619,6 +660,7 @@ bool SkeletonGraphicsWidget::mouseDoubleClick(QMouseEvent *event)
void SkeletonGraphicsWidget::deleteSelected() void SkeletonGraphicsWidget::deleteSelected()
{ {
if (!m_rangeSelectionSet.empty()) { if (!m_rangeSelectionSet.empty()) {
emit batchChangeBegin();
std::set<QUuid> nodeIdSet; std::set<QUuid> nodeIdSet;
std::set<QUuid> edgeIdSet; std::set<QUuid> edgeIdSet;
readSkeletonNodeAndEdgeIdSetFromRangeSelection(&nodeIdSet, &edgeIdSet); readSkeletonNodeAndEdgeIdSetFromRangeSelection(&nodeIdSet, &edgeIdSet);
@ -628,6 +670,7 @@ void SkeletonGraphicsWidget::deleteSelected()
for (const auto &id: nodeIdSet) { for (const auto &id: nodeIdSet) {
emit removeNode(id); emit removeNode(id);
} }
emit batchChangeEnd();
} }
} }
@ -1094,3 +1137,6 @@ void SkeletonGraphicsWidget::copy()
QClipboard *clipboard = QApplication::clipboard(); QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(snapshotXml); clipboard->setText(snapshotXml);
} }

View File

@ -264,8 +264,8 @@ signals:
void redo(); void redo();
void paste(); void paste();
void changeTurnaround(); void changeTurnaround();
void addMirror(); void batchChangeBegin();
void deleteMirror(); void batchChangeEnd();
public: public:
SkeletonGraphicsWidget(const SkeletonDocument *document); SkeletonGraphicsWidget(const SkeletonDocument *document);
std::map<QUuid, std::pair<SkeletonGraphicsNodeItem *, SkeletonGraphicsNodeItem *>> nodeItemMap; std::map<QUuid, std::pair<SkeletonGraphicsNodeItem *, SkeletonGraphicsNodeItem *>> nodeItemMap;
@ -308,6 +308,8 @@ public slots:
void selectPartAll(); void selectPartAll();
void cut(); void cut();
void copy(); void copy();
void flipHorizontally();
void flipVertically();
private slots: private slots:
void turnaroundImageReady(); void turnaroundImageReady();
private: private:
@ -321,6 +323,7 @@ private:
void checkRangeSelection(); void checkRangeSelection();
void clearRangeSelection(); void clearRangeSelection();
void removeItem(QGraphicsItem *item); void removeItem(QGraphicsItem *item);
QVector2D centerOfNodeItemSet(const std::set<SkeletonGraphicsNodeItem *> &set);
private: private:
QGraphicsPixmapItem *m_backgroundItem; QGraphicsPixmapItem *m_backgroundItem;
const SkeletonDocument *m_document; const SkeletonDocument *m_document;

View File

@ -13,6 +13,8 @@ public:
std::map<QString, std::map<QString, QString>> nodes; std::map<QString, std::map<QString, QString>> nodes;
std::map<QString, std::map<QString, QString>> edges; std::map<QString, std::map<QString, QString>> edges;
std::map<QString, std::map<QString, QString>> parts; std::map<QString, std::map<QString, QString>> parts;
std::map<QString, std::map<QString, QString>> mirrors;
std::map<QString, std::map<QString, QString>> trivialMarkers;
std::vector<QString> partIdList; std::vector<QString> partIdList;
public: public:
SkeletonSnapshot(); SkeletonSnapshot();