Add multiple select on parts tree

master
Jeremy Hu 2018-09-07 18:13:55 +08:00
parent 0bf64eeb2d
commit 94d63237e7
6 changed files with 403 additions and 194 deletions

View File

@ -1489,6 +1489,27 @@ void SkeletonDocument::createNewComponentAndMoveThisIn(QUuid componentId)
emit optionsChanged(); emit optionsChanged();
} }
void SkeletonDocument::createNewChildComponent(QUuid parentComponentId)
{
SkeletonComponent *parentComponent = (SkeletonComponent *)findComponent(parentComponentId);
if (!parentComponent->linkToPartId.isNull()) {
parentComponentId = parentComponent->parentId;
parentComponent = (SkeletonComponent *)findComponent(parentComponentId);
}
SkeletonComponent newComponent(QUuid::createUuid());
newComponent.name = tr("Group") + " " + QString::number(componentMap.size() - partMap.size() + 1);
parentComponent->addChild(newComponent.id);
newComponent.parentId = parentComponentId;
componentMap[newComponent.id] = newComponent;
emit componentChildrenChanged(parentComponentId);
emit componentAdded(newComponent.id);
emit optionsChanged();
}
void SkeletonDocument::removePart(QUuid partId) void SkeletonDocument::removePart(QUuid partId)
{ {
auto part = partMap.find(partId); auto part = partMap.find(partId);
@ -1613,6 +1634,20 @@ void SkeletonDocument::removeComponentRecursively(QUuid componentId)
void SkeletonDocument::setCurrentCanvasComponentId(QUuid componentId) void SkeletonDocument::setCurrentCanvasComponentId(QUuid componentId)
{ {
m_currentCanvasComponentId = componentId; m_currentCanvasComponentId = componentId;
const SkeletonComponent *component = findComponent(m_currentCanvasComponentId);
if (nullptr == component) {
//qDebug() << "Current component switch to nullptr componentId:" << componentId;
m_currentCanvasComponentId = QUuid();
} else {
//qDebug() << "Current component switch to " << component->name << "componentId:" << componentId;
if (!component->linkToPartId.isNull()) {
m_currentCanvasComponentId = component->parentId;
component = findComponent(m_currentCanvasComponentId);
//if (nullptr != component) {
// qDebug() << "Then switch to " << component->name << "componentId:" << m_currentCanvasComponentId;
//}
}
}
} }
void SkeletonDocument::addComponent(QUuid parentId) void SkeletonDocument::addComponent(QUuid parentId)
@ -1986,7 +2021,7 @@ void SkeletonDocument::collectComponentDescendantParts(QUuid componentId, std::v
} }
} }
void SkeletonDocument::collectComponentDescendantComponents(QUuid componentId, std::vector<QUuid> &componentIds) void SkeletonDocument::collectComponentDescendantComponents(QUuid componentId, std::vector<QUuid> &componentIds) const
{ {
const SkeletonComponent *component = findComponent(componentId); const SkeletonComponent *component = findComponent(componentId);
if (nullptr == component) if (nullptr == component)
@ -1996,9 +2031,8 @@ void SkeletonDocument::collectComponentDescendantComponents(QUuid componentId, s
return; return;
} }
componentIds.push_back(component->id);
for (const auto &childId: component->childrenIds) { for (const auto &childId: component->childrenIds) {
componentIds.push_back(childId);
collectComponentDescendantComponents(childId, componentIds); collectComponentDescendantComponents(childId, componentIds);
} }
} }

View File

@ -428,6 +428,7 @@ public:
bool isPostProcessResultObsolete() const; bool isPostProcessResultObsolete() const;
void findAllNeighbors(QUuid nodeId, std::set<QUuid> &neighbors) const; void findAllNeighbors(QUuid nodeId, std::set<QUuid> &neighbors) const;
void collectComponentDescendantParts(QUuid componentId, std::vector<QUuid> &partIds) const; void collectComponentDescendantParts(QUuid componentId, std::vector<QUuid> &partIds) const;
void collectComponentDescendantComponents(QUuid componentId, std::vector<QUuid> &componentIds) const;
public slots: public slots:
void removeNode(QUuid nodeId); void removeNode(QUuid nodeId);
void removeEdge(QUuid edgeId); void removeEdge(QUuid edgeId);
@ -473,6 +474,7 @@ public slots:
void moveComponent(QUuid componentId, QUuid toParentId); void moveComponent(QUuid componentId, QUuid toParentId);
void setCurrentCanvasComponentId(QUuid componentId); void setCurrentCanvasComponentId(QUuid componentId);
void createNewComponentAndMoveThisIn(QUuid componentId); void createNewComponentAndMoveThisIn(QUuid componentId);
void createNewChildComponent(QUuid parentComponentId);
void setComponentExpandState(QUuid componentId, bool expanded); void setComponentExpandState(QUuid componentId, bool expanded);
void setComponentSmoothAll(QUuid componentId, float toSmoothAll); void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam); void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
@ -513,7 +515,6 @@ private:
void addPartToComponent(QUuid partId, QUuid componentId); void addPartToComponent(QUuid partId, QUuid componentId);
bool isDescendantComponent(QUuid componentId, QUuid suspiciousId); bool isDescendantComponent(QUuid componentId, QUuid suspiciousId);
void removeComponentRecursively(QUuid componentId); void removeComponentRecursively(QUuid componentId);
void collectComponentDescendantComponents(QUuid componentId, std::vector<QUuid> &componentIds);
void resetDirtyFlags(); void resetDirtyFlags();
void markAllDirty(); void markAllDirty();
private: // need initialize private: // need initialize

View File

@ -594,6 +594,7 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
connect(partTreeWidget, &SkeletonPartTreeWidget::moveComponentToBottom, m_document, &SkeletonDocument::moveComponentToBottom); connect(partTreeWidget, &SkeletonPartTreeWidget::moveComponentToBottom, m_document, &SkeletonDocument::moveComponentToBottom);
connect(partTreeWidget, &SkeletonPartTreeWidget::checkPart, m_document, &SkeletonDocument::checkPart); connect(partTreeWidget, &SkeletonPartTreeWidget::checkPart, m_document, &SkeletonDocument::checkPart);
connect(partTreeWidget, &SkeletonPartTreeWidget::createNewComponentAndMoveThisIn, m_document, &SkeletonDocument::createNewComponentAndMoveThisIn); connect(partTreeWidget, &SkeletonPartTreeWidget::createNewComponentAndMoveThisIn, m_document, &SkeletonDocument::createNewComponentAndMoveThisIn);
connect(partTreeWidget, &SkeletonPartTreeWidget::createNewChildComponent, m_document, &SkeletonDocument::createNewChildComponent);
connect(partTreeWidget, &SkeletonPartTreeWidget::renameComponent, m_document, &SkeletonDocument::renameComponent); connect(partTreeWidget, &SkeletonPartTreeWidget::renameComponent, m_document, &SkeletonDocument::renameComponent);
connect(partTreeWidget, &SkeletonPartTreeWidget::setComponentExpandState, m_document, &SkeletonDocument::setComponentExpandState); connect(partTreeWidget, &SkeletonPartTreeWidget::setComponentExpandState, m_document, &SkeletonDocument::setComponentExpandState);
connect(partTreeWidget, &SkeletonPartTreeWidget::setComponentSmoothAll, m_document, &SkeletonDocument::setComponentSmoothAll); connect(partTreeWidget, &SkeletonPartTreeWidget::setComponentSmoothAll, m_document, &SkeletonDocument::setComponentSmoothAll);

View File

@ -3,6 +3,9 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QWidgetAction> #include <QWidgetAction>
#include <QRadialGradient>
#include <QBrush>
#include <QGuiApplication>
#include "skeletonparttreewidget.h" #include "skeletonparttreewidget.h"
#include "skeletonpartwidget.h" #include "skeletonpartwidget.h"
#include "skeletongraphicswidget.h" #include "skeletongraphicswidget.h"
@ -45,77 +48,210 @@ SkeletonPartTreeWidget::SkeletonPartTreeWidget(const SkeletonDocument *document,
setFont(m_normalFont); setFont(m_normalFont);
QRadialGradient gradient(QPointF(0.25, 0.3), 0.3);
QColor fillColor = QColor(0xfb, 0xf9, 0x87);
fillColor.setAlphaF(0.85);
gradient.setCoordinateMode(QGradient::StretchToDeviceMode);
gradient.setColorAt(0, fillColor);
gradient.setColorAt(1, Qt::transparent);
m_hightlightedPartBackground = QBrush(gradient);
connect(this, &QTreeWidget::customContextMenuRequested, this, &SkeletonPartTreeWidget::showContextMenu); connect(this, &QTreeWidget::customContextMenuRequested, this, &SkeletonPartTreeWidget::showContextMenu);
connect(this, &QTreeWidget::itemChanged, this, &SkeletonPartTreeWidget::groupChanged); connect(this, &QTreeWidget::itemChanged, this, &SkeletonPartTreeWidget::groupChanged);
connect(this, &QTreeWidget::itemExpanded, this, &SkeletonPartTreeWidget::groupExpanded); connect(this, &QTreeWidget::itemExpanded, this, &SkeletonPartTreeWidget::groupExpanded);
connect(this, &QTreeWidget::itemCollapsed, this, &SkeletonPartTreeWidget::groupCollapsed); connect(this, &QTreeWidget::itemCollapsed, this, &SkeletonPartTreeWidget::groupCollapsed);
} }
void SkeletonPartTreeWidget::selectComponent(QUuid componentId) void SkeletonPartTreeWidget::selectComponent(QUuid componentId, bool multiple)
{ {
if (m_currentSelectedComponent != componentId) { if (multiple) {
if (!m_currentSelectedComponent.isNull()) { if (!m_currentSelectedComponentId.isNull()) {
auto item = m_componentItemMap.find(m_currentSelectedComponent); m_selectedComponentIds.insert(m_currentSelectedComponentId);
if (item != m_componentItemMap.end()) { m_currentSelectedComponentId = QUuid();
item->second->setFont(0, m_normalFont); emit currentComponentChanged(m_currentSelectedComponentId);
} }
if (m_selectedComponentIds.find(componentId) != m_selectedComponentIds.end()) {
updateComponentSelectState(componentId, false);
m_selectedComponentIds.erase(componentId);
} else {
updateComponentSelectState(componentId, true);
m_selectedComponentIds.insert(componentId);
} }
m_currentSelectedComponent = componentId; if (m_selectedComponentIds.size() > 1) {
if (!m_currentSelectedComponent.isNull()) { return;
auto item = m_componentItemMap.find(m_currentSelectedComponent); }
if (m_selectedComponentIds.size() == 1)
componentId = *m_selectedComponentIds.begin();
else
componentId = QUuid();
}
if (!m_selectedComponentIds.empty()) {
for (const auto &id: m_selectedComponentIds) {
updateComponentSelectState(id, false);
}
m_selectedComponentIds.clear();
}
if (m_currentSelectedComponentId != componentId) {
if (!m_currentSelectedComponentId.isNull()) {
updateComponentSelectState(m_currentSelectedComponentId, false);
}
m_currentSelectedComponentId = componentId;
if (!m_currentSelectedComponentId.isNull()) {
updateComponentSelectState(m_currentSelectedComponentId, true);
}
emit currentComponentChanged(m_currentSelectedComponentId);
}
}
void SkeletonPartTreeWidget::updateComponentSelectState(QUuid componentId, bool selected)
{
const SkeletonComponent *component = m_document->findComponent(componentId);
if (nullptr == component) {
qDebug() << "Component not found:" << componentId;
return;
}
if (!component->linkToPartId.isNull()) {
auto item = m_partItemMap.find(component->linkToPartId);
if (item != m_componentItemMap.end()) { if (item != m_componentItemMap.end()) {
SkeletonPartWidget *widget = (SkeletonPartWidget *)itemWidget(item->second, 0);
widget->updateCheckedState(selected);
}
return;
}
auto item = m_componentItemMap.find(componentId);
if (item != m_componentItemMap.end()) {
if (selected) {
item->second->setFont(0, m_selectedFont); item->second->setFont(0, m_selectedFont);
item->second->setForeground(0, QBrush(Theme::red));
} else {
item->second->setFont(0, m_normalFont);
item->second->setForeground(0, QBrush(Theme::white));
} }
} }
emit currentComponentChanged(m_currentSelectedComponent);
}
} }
void SkeletonPartTreeWidget::mousePressEvent(QMouseEvent *event) void SkeletonPartTreeWidget::mousePressEvent(QMouseEvent *event)
{ {
QModelIndex itemIndex = indexAt(event->pos()); QModelIndex itemIndex = indexAt(event->pos());
QTreeView::mousePressEvent(event); QTreeView::mousePressEvent(event);
if (event->button() == Qt::LeftButton) {
bool multiple = QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier);
if (itemIndex.isValid()) { if (itemIndex.isValid()) {
QTreeWidgetItem *item = itemFromIndex(itemIndex); QTreeWidgetItem *item = itemFromIndex(itemIndex);
auto componentId = QUuid(item->data(0, Qt::UserRole).toString()); auto componentId = QUuid(item->data(0, Qt::UserRole).toString());
if (m_componentItemMap.find(componentId) != m_componentItemMap.end()) { if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier)) {
selectComponent(componentId); if (!m_shiftStartComponentId.isNull()) {
const SkeletonComponent *parent = m_document->findComponentParent(m_shiftStartComponentId);
if (parent) {
if (!parent->childrenIds.empty()) {
bool startAdd = false;
bool stopAdd = false;
std::vector<QUuid> waitQueue;
for (const auto &childId: parent->childrenIds) {
if (m_shiftStartComponentId == childId || componentId == childId) {
if (startAdd) {
stopAdd = true;
} else {
startAdd = true;
}
}
if (startAdd)
waitQueue.push_back(childId);
if (stopAdd)
break;
}
if (stopAdd && !waitQueue.empty()) {
if (!m_selectedComponentIds.empty()) {
for (const auto &id: m_selectedComponentIds) {
updateComponentSelectState(id, false);
}
m_selectedComponentIds.clear();
}
if (!m_currentSelectedComponentId.isNull()) {
m_currentSelectedComponentId = QUuid();
emit currentComponentChanged(m_currentSelectedComponentId);
}
for (const auto &waitId: waitQueue) {
selectComponent(waitId, true);
}
}
}
}
}
return;
} else {
m_shiftStartComponentId = componentId;
}
selectComponent(componentId, multiple);
return; return;
} }
item = item->parent(); if (!multiple)
if (nullptr != item) {
componentId = QUuid(item->data(0, Qt::UserRole).toString());
if (m_componentItemMap.find(componentId) != m_componentItemMap.end()) {
selectComponent(componentId);
return;
}
}
}
selectComponent(QUuid()); selectComponent(QUuid());
}
} }
void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos) void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos)
{ {
QTreeWidgetItem *item = itemAt(pos); const SkeletonComponent *component = nullptr;
if (nullptr == item) const SkeletonPart *part = nullptr;
return;
auto componentId = QUuid(item->data(0, Qt::UserRole).toString()); std::set<QUuid> unorderedComponentIds = m_selectedComponentIds;
const SkeletonComponent *component = m_document->findComponent(componentId); if (!m_currentSelectedComponentId.isNull())
if (nullptr == component) { unorderedComponentIds.insert(m_currentSelectedComponentId);
qDebug() << "Find component failed:" << componentId;
return; if (unorderedComponentIds.empty()) {
QTreeWidgetItem *item = itemAt(pos);
if (nullptr != item) {
QUuid componentId = QUuid(item->data(0, Qt::UserRole).toString());
unorderedComponentIds.insert(componentId);
}
} }
const SkeletonPart *part = nullptr; std::vector<QUuid> componentIds;
if (!component->linkToPartId.isNull()) { std::vector<QUuid> candidates;
part = m_document->findPart(component->linkToPartId); m_document->collectComponentDescendantComponents(QUuid(), candidates);
for (const auto &cand: candidates) {
if (unorderedComponentIds.find(cand) != unorderedComponentIds.end())
componentIds.push_back(cand);
} }
QMenu contextMenu(this); QMenu contextMenu(this);
if (!component->name.isEmpty()) if (componentIds.size() == 1) {
contextMenu.addSection(component->name); QUuid componentId = *componentIds.begin();
component = m_document->findComponent(componentId);
if (nullptr == component) {
qDebug() << "Component not found:" << componentId;
return;
}
if (component && !component->linkToPartId.isNull()) {
part = m_document->findPart(component->linkToPartId);
}
}
QWidgetAction forDisplayPartImage(this);
QLabel *previewLabel = new QLabel;
previewLabel->setFixedHeight(Theme::previewImageSize);
previewLabel->setStyleSheet("QLabel {color: " + Theme::red.name() + "}");
if (nullptr != part) {
previewLabel->setPixmap(QPixmap::fromImage(part->preview));
} else if (nullptr != component) {
previewLabel->setText(component->name);
} else if (!componentIds.empty()) {
previewLabel->setText(tr("(%1 items)").arg(QString::number(componentIds.size())));
}
QHBoxLayout *layout = new QHBoxLayout;
layout->setAlignment(Qt::AlignCenter);
layout->addWidget(previewLabel);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
QWidget *widget = new QWidget;
widget->setLayout(layout);
forDisplayPartImage.setDefaultWidget(widget);
if (!componentIds.empty()) {
contextMenu.addAction(&forDisplayPartImage);
contextMenu.addSeparator();
}
QAction showAction(tr("Show"), this); QAction showAction(tr("Show"), this);
showAction.setIcon(Theme::awesome()->icon(fa::eye)); showAction.setIcon(Theme::awesome()->icon(fa::eye));
@ -129,10 +265,12 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos)
QAction cancelInverseAction(tr("Cancel Inverse"), this); QAction cancelInverseAction(tr("Cancel Inverse"), this);
QAction selectAction(tr("Select"), this); QAction selectAction(tr("Select"), this);
if (!component->linkToPartId.isNull()) { if (nullptr != component && nullptr != part) {
emit checkPart(component->linkToPartId); connect(&selectAction, &QAction::triggered, [=]() {
emit addPartToSelection(component->linkToPartId);
});
contextMenu.addAction(&selectAction);
if (nullptr != part) {
if (part->visible) { if (part->visible) {
connect(&hideAction, &QAction::triggered, [=]() { connect(&hideAction, &QAction::triggered, [=]() {
emit setPartVisibleState(component->linkToPartId, false); emit setPartVisibleState(component->linkToPartId, false);
@ -156,78 +294,84 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos)
}); });
contextMenu.addAction(&lockAction); contextMenu.addAction(&lockAction);
} }
} } else if (!componentIds.empty()) {
} else {
if (!component->childrenIds.empty()) {
connect(&selectAction, &QAction::triggered, [=]() { connect(&selectAction, &QAction::triggered, [=]() {
for (const auto &componentId: componentIds) {
std::vector<QUuid> partIds; std::vector<QUuid> partIds;
m_document->collectComponentDescendantParts(componentId, partIds); m_document->collectComponentDescendantParts(componentId, partIds);
for (const auto &partId: partIds) { for (const auto &partId: partIds) {
emit addPartToSelection(partId); emit addPartToSelection(partId);
} }
}
}); });
contextMenu.addAction(&selectAction); contextMenu.addAction(&selectAction);
connect(&showAction, &QAction::triggered, [=]() { connect(&showAction, &QAction::triggered, [=]() {
for (const auto &componentId: componentIds)
emit showDescendantComponents(componentId); emit showDescendantComponents(componentId);
}); });
contextMenu.addAction(&showAction); contextMenu.addAction(&showAction);
connect(&hideAction, &QAction::triggered, [=]() { connect(&hideAction, &QAction::triggered, [=]() {
for (const auto &componentId: componentIds)
emit hideDescendantComponents(componentId); emit hideDescendantComponents(componentId);
}); });
contextMenu.addAction(&hideAction); contextMenu.addAction(&hideAction);
connect(&lockAction, &QAction::triggered, [=]() { connect(&lockAction, &QAction::triggered, [=]() {
for (const auto &componentId: componentIds)
emit lockDescendantComponents(componentId); emit lockDescendantComponents(componentId);
}); });
contextMenu.addAction(&lockAction); contextMenu.addAction(&lockAction);
connect(&unlockAction, &QAction::triggered, [=]() { connect(&unlockAction, &QAction::triggered, [=]() {
for (const auto &componentId: componentIds)
emit unlockDescendantComponents(componentId); emit unlockDescendantComponents(componentId);
}); });
contextMenu.addAction(&unlockAction); contextMenu.addAction(&unlockAction);
} }
}
if (!component->inverse) { if (component && !component->inverse) {
connect(&invertAction, &QAction::triggered, [=]() { connect(&invertAction, &QAction::triggered, [=]() {
emit setComponentInverseState(componentId, true); emit setComponentInverseState(component->id, true);
}); });
contextMenu.addAction(&invertAction); contextMenu.addAction(&invertAction);
} }
if (component->inverse) { if (component && component->inverse) {
connect(&cancelInverseAction, &QAction::triggered, [=]() { connect(&cancelInverseAction, &QAction::triggered, [=]() {
emit setComponentInverseState(componentId, false); emit setComponentInverseState(component->id, false);
}); });
contextMenu.addAction(&cancelInverseAction); contextMenu.addAction(&cancelInverseAction);
} }
contextMenu.addSeparator(); contextMenu.addSeparator();
QMenu *smoothMenu = contextMenu.addMenu(tr("Smooth"));
QWidgetAction smoothAction(this); QWidgetAction smoothAction(this);
smoothAction.setDefaultWidget(createSmoothMenuWidget(componentId)); QAction hideOthersAction(tr("Hide Others"), this);
QAction lockOthersAction(tr("Lock Others"), this);
if (nullptr != component) {
QMenu *smoothMenu = contextMenu.addMenu(tr("Smooth"));
smoothAction.setDefaultWidget(createSmoothMenuWidget(component->id));
smoothMenu->addAction(&smoothAction); smoothMenu->addAction(&smoothAction);
contextMenu.addSeparator(); contextMenu.addSeparator();
QAction hideOthersAction(tr("Hide Others"), this);
hideOthersAction.setIcon(Theme::awesome()->icon(fa::eyeslash)); hideOthersAction.setIcon(Theme::awesome()->icon(fa::eyeslash));
connect(&hideOthersAction, &QAction::triggered, [=]() { connect(&hideOthersAction, &QAction::triggered, [=]() {
emit hideOtherComponents(componentId); emit hideOtherComponents(component->id);
}); });
contextMenu.addAction(&hideOthersAction); contextMenu.addAction(&hideOthersAction);
QAction lockOthersAction(tr("Lock Others"), this);
lockOthersAction.setIcon(Theme::awesome()->icon(fa::lock)); lockOthersAction.setIcon(Theme::awesome()->icon(fa::lock));
connect(&lockOthersAction, &QAction::triggered, [=]() { connect(&lockOthersAction, &QAction::triggered, [=]() {
emit lockOtherComponents(componentId); emit lockOtherComponents(component->id);
}); });
contextMenu.addAction(&lockOthersAction); contextMenu.addAction(&lockOthersAction);
contextMenu.addSeparator(); contextMenu.addSeparator();
}
QAction collapseAllAction(tr("Collapse All"), this); QAction collapseAllAction(tr("Collapse All"), this);
connect(&collapseAllAction, &QAction::triggered, [=]() { connect(&collapseAllAction, &QAction::triggered, [=]() {
@ -275,62 +419,77 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos)
contextMenu.addSeparator(); contextMenu.addSeparator();
QAction newGroupAction(tr("New Group"), this);
newGroupAction.setIcon(Theme::awesome()->icon(fa::file));
connect(&newGroupAction, &QAction::triggered, [=]() {
emit createNewChildComponent(nullptr == component ? QUuid() : component->id);
});
contextMenu.addAction(&newGroupAction);
contextMenu.addSeparator();
std::vector<QAction *> groupsActions;
QAction deleteAction(tr("Delete"), this);
QAction moveToTopAction(tr("Top"), this);
QAction moveUpAction(tr("Up"), this);
QAction moveDownAction(tr("Down"), this);
QAction moveToBottomAction(tr("Bottom"), this);
QAction moveToNewGroupAction(tr("New Group"), this);
QAction moveToRootGroupAction(tr("Root"), this);
std::function<void(QUuid, int)> addChildGroupsFunc;
if (!componentIds.empty()) {
QMenu *moveToMenu = contextMenu.addMenu(tr("Move To")); QMenu *moveToMenu = contextMenu.addMenu(tr("Move To"));
QAction moveToTopAction(tr("Top"), this); if (nullptr != component) {
moveToTopAction.setIcon(Theme::awesome()->icon(fa::angledoubleup)); moveToTopAction.setIcon(Theme::awesome()->icon(fa::angledoubleup));
connect(&moveToTopAction, &QAction::triggered, [=]() { connect(&moveToTopAction, &QAction::triggered, [=]() {
emit moveComponentToTop(componentId); emit moveComponentToTop(component->id);
}); });
moveToMenu->addAction(&moveToTopAction); moveToMenu->addAction(&moveToTopAction);
QAction moveUpAction(tr("Up"), this);
moveUpAction.setIcon(Theme::awesome()->icon(fa::angleup)); moveUpAction.setIcon(Theme::awesome()->icon(fa::angleup));
connect(&moveUpAction, &QAction::triggered, [=]() { connect(&moveUpAction, &QAction::triggered, [=]() {
emit moveComponentUp(componentId); emit moveComponentUp(component->id);
}); });
moveToMenu->addAction(&moveUpAction); moveToMenu->addAction(&moveUpAction);
QAction moveDownAction(tr("Down"), this);
moveDownAction.setIcon(Theme::awesome()->icon(fa::angledown)); moveDownAction.setIcon(Theme::awesome()->icon(fa::angledown));
connect(&moveDownAction, &QAction::triggered, [=]() { connect(&moveDownAction, &QAction::triggered, [=]() {
emit moveComponentDown(componentId); emit moveComponentDown(component->id);
}); });
moveToMenu->addAction(&moveDownAction); moveToMenu->addAction(&moveDownAction);
QAction moveToBottomAction(tr("Bottom"), this);
moveToBottomAction.setIcon(Theme::awesome()->icon(fa::angledoubledown)); moveToBottomAction.setIcon(Theme::awesome()->icon(fa::angledoubledown));
connect(&moveToBottomAction, &QAction::triggered, [=]() { connect(&moveToBottomAction, &QAction::triggered, [=]() {
emit moveComponentToBottom(componentId); emit moveComponentToBottom(component->id);
}); });
moveToMenu->addAction(&moveToBottomAction); moveToMenu->addAction(&moveToBottomAction);
moveToMenu->addSeparator(); moveToMenu->addSeparator();
QAction moveToNewGroupAction(tr("New Group"), this);
moveToNewGroupAction.setIcon(Theme::awesome()->icon(fa::file)); moveToNewGroupAction.setIcon(Theme::awesome()->icon(fa::file));
moveToMenu->addAction(&moveToNewGroupAction); moveToMenu->addAction(&moveToNewGroupAction);
connect(&moveToNewGroupAction, &QAction::triggered, [=]() { connect(&moveToNewGroupAction, &QAction::triggered, [=]() {
emit createNewComponentAndMoveThisIn(componentId); emit createNewComponentAndMoveThisIn(component->id);
}); });
moveToMenu->addSeparator(); moveToMenu->addSeparator();
}
QAction moveToRootGroupAction(tr("Root"), this);
moveToMenu->addAction(&moveToRootGroupAction); moveToMenu->addAction(&moveToRootGroupAction);
connect(&moveToRootGroupAction, &QAction::triggered, [=]() { connect(&moveToRootGroupAction, &QAction::triggered, [=]() {
for (const auto &componentId: componentIds)
emit moveComponent(componentId, QUuid()); emit moveComponent(componentId, QUuid());
}); });
std::vector<QAction *> groupsActions; addChildGroupsFunc = [this, &groupsActions, &addChildGroupsFunc, &moveToMenu, &componentIds](QUuid currentId, int tabs) -> void {
std::function<void(QUuid, int)> addChildGroupsFunc;
addChildGroupsFunc = [this, &groupsActions, &addChildGroupsFunc, &moveToMenu, &componentId](QUuid currentId, int tabs) -> void {
const SkeletonComponent *current = m_document->findComponent(currentId); const SkeletonComponent *current = m_document->findComponent(currentId);
if (nullptr == current) if (nullptr == current)
return; return;
if (!current->id.isNull() && current->linkDataType().isEmpty()) { if (!current->id.isNull() && current->linkDataType().isEmpty()) {
QAction *action = new QAction(QString(" ").repeated(tabs * 4) + current->name, this); QAction *action = new QAction(QString(" ").repeated(tabs * 4) + current->name, this);
connect(action, &QAction::triggered, [=]() { connect(action, &QAction::triggered, [=]() {
for (const auto &componentId: componentIds)
emit moveComponent(componentId, current->id); emit moveComponent(componentId, current->id);
}); });
groupsActions.push_back(action); groupsActions.push_back(action);
@ -344,12 +503,13 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos)
contextMenu.addSeparator(); contextMenu.addSeparator();
QAction deleteAction(tr("Delete"), this);
deleteAction.setIcon(Theme::awesome()->icon(fa::trash)); deleteAction.setIcon(Theme::awesome()->icon(fa::trash));
connect(&deleteAction, &QAction::triggered, [=]() { connect(&deleteAction, &QAction::triggered, [=]() {
for (const auto &componentId: componentIds)
emit removeComponent(componentId); emit removeComponent(componentId);
}); });
contextMenu.addAction(&deleteAction); contextMenu.addAction(&deleteAction);
}
contextMenu.exec(mapToGlobal(pos)); contextMenu.exec(mapToGlobal(pos));
@ -504,6 +664,7 @@ void SkeletonPartTreeWidget::addComponentChildrenToItem(QUuid componentId, QTree
m_componentItemMap[childId] = item; m_componentItemMap[childId] = item;
addComponentChildrenToItem(childId, item); addComponentChildrenToItem(childId, item);
} }
updateComponentSelectState(childId, isComponentSelected(childId));
} }
} }
@ -558,7 +719,9 @@ void SkeletonPartTreeWidget::componentRemoved(QUuid componentId)
auto componentItem = m_componentItemMap.find(componentId); auto componentItem = m_componentItemMap.find(componentId);
if (componentItem == m_componentItemMap.end()) if (componentItem == m_componentItemMap.end())
return; return;
m_selectedComponentIds.erase(componentId);
if (m_currentSelectedComponentId == componentId)
m_currentSelectedComponentId = QUuid();
m_componentItemMap.erase(componentId); m_componentItemMap.erase(componentId);
} }
@ -722,8 +885,7 @@ void SkeletonPartTreeWidget::partChecked(QUuid partId)
qDebug() << "Part item not found:" << partId; qDebug() << "Part item not found:" << partId;
return; return;
} }
SkeletonPartWidget *widget = (SkeletonPartWidget *)itemWidget(item->second, 0); item->second->setBackground(0, m_hightlightedPartBackground);
widget->updateCheckedState(true);
} }
void SkeletonPartTreeWidget::partUnchecked(QUuid partId) void SkeletonPartTreeWidget::partUnchecked(QUuid partId)
@ -733,8 +895,7 @@ void SkeletonPartTreeWidget::partUnchecked(QUuid partId)
//qDebug() << "Part item not found:" << partId; //qDebug() << "Part item not found:" << partId;
return; return;
} }
SkeletonPartWidget *widget = (SkeletonPartWidget *)itemWidget(item->second, 0); item->second->setBackground(0, QBrush(Qt::transparent));
widget->updateCheckedState(false);
} }
QSize SkeletonPartTreeWidget::sizeHint() const QSize SkeletonPartTreeWidget::sizeHint() const
@ -754,3 +915,9 @@ void SkeletonPartTreeWidget::keyPressEvent(QKeyEvent *event)
if (m_graphicsFunctions) if (m_graphicsFunctions)
m_graphicsFunctions->keyPress(event); m_graphicsFunctions->keyPress(event);
} }
bool SkeletonPartTreeWidget::isComponentSelected(QUuid componentId)
{
return (m_currentSelectedComponentId == componentId ||
m_selectedComponentIds.find(componentId) != m_selectedComponentIds.end());
}

View File

@ -18,6 +18,7 @@ signals:
void moveComponentToBottom(QUuid componentId); void moveComponentToBottom(QUuid componentId);
void checkPart(QUuid partId); void checkPart(QUuid partId);
void createNewComponentAndMoveThisIn(QUuid componentId); void createNewComponentAndMoveThisIn(QUuid componentId);
void createNewChildComponent(QUuid parentComponentId);
void renameComponent(QUuid componentId, QString name); void renameComponent(QUuid componentId, QString name);
void setComponentExpandState(QUuid componentId, bool expanded); void setComponentExpandState(QUuid componentId, bool expanded);
void setComponentSmoothAll(QUuid componentId, float toSmoothAll); void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
@ -76,8 +77,10 @@ protected:
private: private:
void addComponentChildrenToItem(QUuid componentId, QTreeWidgetItem *parentItem); void addComponentChildrenToItem(QUuid componentId, QTreeWidgetItem *parentItem);
void deleteItemChildren(QTreeWidgetItem *item); void deleteItemChildren(QTreeWidgetItem *item);
void selectComponent(QUuid componentId); void selectComponent(QUuid componentId, bool multiple=false);
QWidget *createSmoothMenuWidget(QUuid componentId); QWidget *createSmoothMenuWidget(QUuid componentId);
void updateComponentSelectState(QUuid componentId, bool selected);
bool isComponentSelected(QUuid componentId);
private: private:
const SkeletonDocument *m_document = nullptr; const SkeletonDocument *m_document = nullptr;
std::map<QUuid, QTreeWidgetItem *> m_partItemMap; std::map<QUuid, QTreeWidgetItem *> m_partItemMap;
@ -85,7 +88,10 @@ private:
SkeletonGraphicsFunctions *m_graphicsFunctions = nullptr; SkeletonGraphicsFunctions *m_graphicsFunctions = nullptr;
QFont m_normalFont; QFont m_normalFont;
QFont m_selectedFont; QFont m_selectedFont;
QUuid m_currentSelectedComponent; QUuid m_currentSelectedComponentId;
QBrush m_hightlightedPartBackground;
QUuid m_shiftStartComponentId;
std::set<QUuid> m_selectedComponentIds;
}; };
#endif #endif

View File

@ -250,7 +250,7 @@ void SkeletonPartWidget::updateAllButtons()
void SkeletonPartWidget::updateCheckedState(bool checked) void SkeletonPartWidget::updateCheckedState(bool checked)
{ {
if (checked) if (checked)
m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid #f7d9c8;}"); m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid " + Theme::red.name() + ";}");
else else
m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid transparent;}"); m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid transparent;}");
} }