Add flip
parent
5e97e3d268
commit
62fdcbdced
|
@ -32,6 +32,7 @@ int main(int argc, char ** argv)
|
|||
darkPalette.setColor(QPalette::ToolTipBase, Theme::white);
|
||||
darkPalette.setColor(QPalette::ToolTipText, 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::ButtonText, Theme::white);
|
||||
darkPalette.setColor(QPalette::BrightText, Theme::red);
|
||||
|
|
|
@ -14,7 +14,8 @@ unsigned long SkeletonDocument::m_maxSnapshot = 1000;
|
|||
SkeletonDocument::SkeletonDocument() :
|
||||
m_resultMeshIsObsolete(false),
|
||||
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()
|
||||
{
|
||||
if (nullptr != m_meshGenerator) {
|
||||
if (nullptr != m_meshGenerator || m_batchChangeRefCount > 0) {
|
||||
m_resultMeshIsObsolete = true;
|
||||
return;
|
||||
}
|
||||
|
@ -867,3 +883,15 @@ void SkeletonDocument::paste()
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,6 +106,13 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
enum class SkeletonProfile
|
||||
{
|
||||
Unknown = 0,
|
||||
Main,
|
||||
Side
|
||||
};
|
||||
|
||||
class SkeletonHistoryItem
|
||||
{
|
||||
public:
|
||||
|
@ -121,13 +128,6 @@ enum class SkeletonDocumentEditMode
|
|||
ZoomOut
|
||||
};
|
||||
|
||||
enum class SkeletonProfile
|
||||
{
|
||||
Unknown = 0,
|
||||
Main,
|
||||
Side
|
||||
};
|
||||
|
||||
class SkeletonDocument : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -170,6 +170,7 @@ public:
|
|||
Mesh *takeResultMesh();
|
||||
QImage preview;
|
||||
void updateTurnaround(const QImage &image);
|
||||
bool hasPastableContentInClipboard() const;
|
||||
public slots:
|
||||
void removeNode(QUuid nodeId);
|
||||
void removeEdge(QUuid edgeId);
|
||||
|
@ -193,6 +194,8 @@ public slots:
|
|||
void undo();
|
||||
void redo();
|
||||
void paste();
|
||||
void batchChangeBegin();
|
||||
void batchChangeEnd();
|
||||
private:
|
||||
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());
|
||||
|
@ -205,6 +208,7 @@ private:
|
|||
static unsigned long m_maxSnapshot;
|
||||
std::deque<SkeletonHistoryItem> m_undoItems;
|
||||
std::deque<SkeletonHistoryItem> m_redoItems;
|
||||
int m_batchChangeRefCount;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -195,6 +195,8 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
|||
connect(graphicsWidget, &SkeletonGraphicsWidget::redo, m_document, &SkeletonDocument::redo);
|
||||
connect(graphicsWidget, &SkeletonGraphicsWidget::paste, m_document, &SkeletonDocument::paste);
|
||||
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::nodeRemoved, graphicsWidget, &SkeletonGraphicsWidget::nodeRemoved);
|
||||
|
|
|
@ -102,10 +102,23 @@ void SkeletonGraphicsWidget::showContextMenu(const QPoint &pos)
|
|||
|
||||
QAction pasteAction("Paste", this);
|
||||
connect(&pasteAction, &QAction::triggered, m_document, &SkeletonDocument::paste);
|
||||
pasteAction.setEnabled(m_document->hasPastableContentInClipboard());
|
||||
contextMenu.addAction(&pasteAction);
|
||||
|
||||
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);
|
||||
connect(&selectAllAction, &QAction::triggered, this, &SkeletonGraphicsWidget::selectAll);
|
||||
selectAllAction.setEnabled(!nodeItemMap.empty());
|
||||
|
@ -123,18 +136,6 @@ void SkeletonGraphicsWidget::showContextMenu(const QPoint &pos)
|
|||
|
||||
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);
|
||||
connect(&changeTurnaroundAction, &QAction::triggered, [=]() {
|
||||
emit changeTurnaround();
|
||||
|
@ -425,11 +426,7 @@ bool SkeletonGraphicsWidget::wheel(QWheelEvent *event)
|
|||
readMergedSkeletonNodeSetFromRangeSelection(&nodeItems);
|
||||
float unifiedDelta = sceneRadiusToUnified(delta);
|
||||
if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier)) {
|
||||
QVector2D center;
|
||||
for (const auto &nodeItem: nodeItems) {
|
||||
center += QVector2D(nodeItem->origin());
|
||||
}
|
||||
center /= nodeItems.size();
|
||||
QVector2D center = centerOfNodeItemSet(nodeItems);
|
||||
for (const auto &nodeItem: nodeItems) {
|
||||
QVector2D origin = QVector2D(nodeItem->origin());
|
||||
QVector2D ray = (center - origin) * 0.01 * delta;
|
||||
|
@ -459,6 +456,50 @@ bool SkeletonGraphicsWidget::wheel(QWheelEvent *event)
|
|||
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)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
|
@ -619,6 +660,7 @@ bool SkeletonGraphicsWidget::mouseDoubleClick(QMouseEvent *event)
|
|||
void SkeletonGraphicsWidget::deleteSelected()
|
||||
{
|
||||
if (!m_rangeSelectionSet.empty()) {
|
||||
emit batchChangeBegin();
|
||||
std::set<QUuid> nodeIdSet;
|
||||
std::set<QUuid> edgeIdSet;
|
||||
readSkeletonNodeAndEdgeIdSetFromRangeSelection(&nodeIdSet, &edgeIdSet);
|
||||
|
@ -628,6 +670,7 @@ void SkeletonGraphicsWidget::deleteSelected()
|
|||
for (const auto &id: nodeIdSet) {
|
||||
emit removeNode(id);
|
||||
}
|
||||
emit batchChangeEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1094,3 +1137,6 @@ void SkeletonGraphicsWidget::copy()
|
|||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(snapshotXml);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -264,8 +264,8 @@ signals:
|
|||
void redo();
|
||||
void paste();
|
||||
void changeTurnaround();
|
||||
void addMirror();
|
||||
void deleteMirror();
|
||||
void batchChangeBegin();
|
||||
void batchChangeEnd();
|
||||
public:
|
||||
SkeletonGraphicsWidget(const SkeletonDocument *document);
|
||||
std::map<QUuid, std::pair<SkeletonGraphicsNodeItem *, SkeletonGraphicsNodeItem *>> nodeItemMap;
|
||||
|
@ -308,6 +308,8 @@ public slots:
|
|||
void selectPartAll();
|
||||
void cut();
|
||||
void copy();
|
||||
void flipHorizontally();
|
||||
void flipVertically();
|
||||
private slots:
|
||||
void turnaroundImageReady();
|
||||
private:
|
||||
|
@ -321,6 +323,7 @@ private:
|
|||
void checkRangeSelection();
|
||||
void clearRangeSelection();
|
||||
void removeItem(QGraphicsItem *item);
|
||||
QVector2D centerOfNodeItemSet(const std::set<SkeletonGraphicsNodeItem *> &set);
|
||||
private:
|
||||
QGraphicsPixmapItem *m_backgroundItem;
|
||||
const SkeletonDocument *m_document;
|
||||
|
|
|
@ -13,6 +13,8 @@ public:
|
|||
std::map<QString, std::map<QString, QString>> nodes;
|
||||
std::map<QString, std::map<QString, QString>> edges;
|
||||
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;
|
||||
public:
|
||||
SkeletonSnapshot();
|
||||
|
|
Loading…
Reference in New Issue