#include #include #include #include #include #include #include "component_property_widget.h" #include "float_number_widget.h" #include "document.h" #include "theme.h" ComponentPropertyWidget::ComponentPropertyWidget(Document *document, const std::vector &componentIds, QWidget *parent): QWidget(parent), m_document(document), m_componentIds(componentIds) { preparePartIds(); m_color = lastColor(); QPushButton *colorPreviewArea = new QPushButton; colorPreviewArea->setStyleSheet("QPushButton {background-color: " + m_color.name() + "; border-radius: 0;}"); colorPreviewArea->setFixedSize(Theme::toolIconSize * 1.8, Theme::toolIconSize); QPushButton *colorPickerButton = new QPushButton(QChar(fa::eyedropper)); Theme::initIconButton(colorPickerButton); connect(colorPickerButton, &QPushButton::clicked, this, &ComponentPropertyWidget::showColorDialog); QHBoxLayout *colorLayout = new QHBoxLayout; colorLayout->addWidget(colorPreviewArea); colorLayout->addWidget(colorPickerButton); colorLayout->addStretch(); colorLayout->setSizeConstraint(QLayout::SetFixedSize); QGroupBox *deformGroupBox = nullptr; if (nullptr != m_part) { FloatNumberWidget *thicknessWidget = new FloatNumberWidget; thicknessWidget->setItemName(tr("Thickness")); thicknessWidget->setRange(0, 2); thicknessWidget->setValue(m_part->deformThickness); connect(thicknessWidget, &FloatNumberWidget::valueChanged, [=](float value) { emit setPartDeformThickness(m_partId, value); emit groupOperationAdded(); }); FloatNumberWidget *widthWidget = new FloatNumberWidget; widthWidget->setItemName(tr("Width")); widthWidget->setRange(0, 2); widthWidget->setValue(m_part->deformWidth); connect(widthWidget, &FloatNumberWidget::valueChanged, [=](float value) { emit setPartDeformWidth(m_partId, value); emit groupOperationAdded(); }); QPushButton *thicknessEraser = new QPushButton(QChar(fa::eraser)); Theme::initIconButton(thicknessEraser); connect(thicknessEraser, &QPushButton::clicked, [=]() { thicknessWidget->setValue(1.0); emit groupOperationAdded(); }); QPushButton *widthEraser = new QPushButton(QChar(fa::eraser)); Theme::initIconButton(widthEraser); connect(widthEraser, &QPushButton::clicked, [=]() { widthWidget->setValue(1.0); emit groupOperationAdded(); }); QVBoxLayout *deformLayout = new QVBoxLayout; QHBoxLayout *thicknessLayout = new QHBoxLayout; QHBoxLayout *widthLayout = new QHBoxLayout; thicknessLayout->addWidget(thicknessEraser); thicknessLayout->addWidget(thicknessWidget); widthLayout->addWidget(widthEraser); widthLayout->addWidget(widthWidget); QCheckBox *deformUnifyStateBox = new QCheckBox(); Theme::initCheckbox(deformUnifyStateBox); deformUnifyStateBox->setText(tr("Unified")); deformUnifyStateBox->setChecked(m_part->deformUnified); connect(deformUnifyStateBox, &QCheckBox::stateChanged, this, [=]() { emit setPartDeformUnified(m_partId, deformUnifyStateBox->isChecked()); emit groupOperationAdded(); }); QHBoxLayout *deformUnifyLayout = new QHBoxLayout; deformUnifyLayout->addStretch(); deformUnifyLayout->addWidget(deformUnifyStateBox); deformLayout->addLayout(thicknessLayout); deformLayout->addLayout(widthLayout); deformLayout->addLayout(deformUnifyLayout); deformGroupBox = new QGroupBox(tr("Deform")); deformGroupBox->setLayout(deformLayout); } QGroupBox *cutFaceGroupBox = nullptr; if (nullptr != m_part) { FloatNumberWidget *rotationWidget = new FloatNumberWidget; rotationWidget->setItemName(tr("Rotation")); rotationWidget->setRange(-1, 1); rotationWidget->setValue(m_part->cutRotation); connect(rotationWidget, &FloatNumberWidget::valueChanged, [=](float value) { emit setPartCutRotation(m_partId, value); emit groupOperationAdded(); }); QPushButton *rotationEraser = new QPushButton(QChar(fa::eraser)); Theme::initIconButton(rotationEraser); connect(rotationEraser, &QPushButton::clicked, [=]() { rotationWidget->setValue(0.0); emit groupOperationAdded(); }); QPushButton *rotationMinus5Button = new QPushButton(QChar(fa::rotateleft)); Theme::initIconButton(rotationMinus5Button); connect(rotationMinus5Button, &QPushButton::clicked, [=]() { rotationWidget->setValue(-0.5); emit groupOperationAdded(); }); QPushButton *rotation5Button = new QPushButton(QChar(fa::rotateright)); Theme::initIconButton(rotation5Button); connect(rotation5Button, &QPushButton::clicked, [=]() { rotationWidget->setValue(0.5); emit groupOperationAdded(); }); QHBoxLayout *rotationLayout = new QHBoxLayout; rotationLayout->addWidget(rotationEraser); rotationLayout->addWidget(rotationWidget); rotationLayout->addWidget(rotationMinus5Button); rotationLayout->addWidget(rotation5Button); QCheckBox *subdivStateBox = new QCheckBox(); Theme::initCheckbox(subdivStateBox); subdivStateBox->setText(tr("Subdivided")); subdivStateBox->setChecked(m_part->subdived); connect(subdivStateBox, &QCheckBox::stateChanged, this, [=]() { emit setPartSubdivState(m_partId, subdivStateBox->isChecked()); emit groupOperationAdded(); }); QCheckBox *chamferStateBox = new QCheckBox(); Theme::initCheckbox(chamferStateBox); chamferStateBox->setText(tr("Chamfered")); chamferStateBox->setChecked(m_part->chamfered); connect(chamferStateBox, &QCheckBox::stateChanged, this, [=]() { emit setPartChamferState(m_partId, chamferStateBox->isChecked()); emit groupOperationAdded(); }); QHBoxLayout *optionsLayout = new QHBoxLayout; optionsLayout->addStretch(); optionsLayout->addWidget(chamferStateBox); optionsLayout->addWidget(subdivStateBox); QVBoxLayout *cutFaceLayout = new QVBoxLayout; cutFaceLayout->addLayout(rotationLayout); cutFaceLayout->addLayout(optionsLayout); cutFaceGroupBox = new QGroupBox(tr("Cut Face")); cutFaceGroupBox->setLayout(cutFaceLayout); } QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(colorLayout); if (nullptr != deformGroupBox) mainLayout->addWidget(deformGroupBox); if (nullptr != cutFaceGroupBox) mainLayout->addWidget(cutFaceGroupBox); mainLayout->setSizeConstraint(QLayout::SetFixedSize); connect(this, &ComponentPropertyWidget::setPartColorState, m_document, &Document::setPartColorState); connect(this, &ComponentPropertyWidget::endColorPicking, m_document, &Document::enableBackgroundBlur); connect(this, &ComponentPropertyWidget::beginColorPicking, m_document, &Document::disableBackgroundBlur); connect(this, &ComponentPropertyWidget::setPartDeformThickness, m_document, &Document::setPartDeformThickness); connect(this, &ComponentPropertyWidget::setPartDeformWidth, m_document, &Document::setPartDeformWidth); connect(this, &ComponentPropertyWidget::setPartDeformUnified, m_document, &Document::setPartDeformUnified); connect(this, &ComponentPropertyWidget::setPartCutRotation, m_document, &Document::setPartCutRotation); connect(this, &ComponentPropertyWidget::setPartSubdivState, m_document, &Document::setPartSubdivState); connect(this, &ComponentPropertyWidget::setPartChamferState, m_document, &Document::setPartChamferState); connect(this, &ComponentPropertyWidget::groupOperationAdded, m_document, &Document::saveSnapshot); setLayout(mainLayout); setFixedSize(minimumSizeHint()); } void ComponentPropertyWidget::preparePartIds() { std::unordered_set addedPartIdSet; for (const auto &componentId: m_componentIds) { std::vector partIds; m_document->collectComponentDescendantParts(componentId, partIds); for (const auto &it: partIds) { if (addedPartIdSet.insert(it).second) m_partIds.emplace_back(it); } } if (1 == m_partIds.size()) { m_part = m_document->findPart(m_partIds.front()); if (nullptr != m_part) m_partId = m_partIds.front(); } } QColor ComponentPropertyWidget::lastColor() { QColor color = Qt::white; std::map colorMap; for (const auto &partId: m_partIds) { const SkeletonPart *part = m_document->findPart(partId); if (nullptr == part) continue; colorMap[part->color.name()]++; } if (!colorMap.empty()) { color = std::max_element(colorMap.begin(), colorMap.end(), [](const std::map::value_type &a, const std::map::value_type &b) { return a.second < b.second; })->first; } return color; } void ComponentPropertyWidget::showColorDialog() { emit beginColorPicking(); QColor color = QColorDialog::getColor(m_color, this); emit endColorPicking(); if (!color.isValid()) return; for (const auto &partId: m_partIds) { emit setPartColorState(partId, true, color); } emit groupOperationAdded(); }