diff --git a/common/lc_minifigdialog.cpp b/common/lc_minifigdialog.cpp index 77a858e0..87f76aba 100644 --- a/common/lc_minifigdialog.cpp +++ b/common/lc_minifigdialog.cpp @@ -9,41 +9,93 @@ #include "lc_library.h" #include "lc_view.h" #include "camera.h" +#include "lc_doublespinbox.h" +#include "lc_qutils.h" lcMinifigDialog::lcMinifigDialog(QWidget* Parent) : QDialog(Parent), ui(new Ui::lcMinifigDialog) { ui->setupUi(this); - mComboBoxes = + QGridLayout* MinifigLayout = ui->MinifigLayout; + + bool HasSpinBox[LC_MFW_NUMITEMS] = { true, true, true, false, false, false, false, true, true, true, true, true, true, true, true, true, true }; + bool IsLeft[LC_MFW_NUMITEMS] = { true, true, true, true, false, false, false, false, true, false, true, false, true, false, true, false, true }; + int LeftRow = 0, RightRow = 2; + + QString Labels[LC_MFW_NUMITEMS] = { - ui->hatsType, ui->hats2Type, ui->headType, ui->neckType, ui->bodyType, ui->body2Type, ui->body3Type, ui->rarmType, ui->larmType, - ui->rhandType, ui->lhandType, ui->rhandaType, ui->lhandaType, ui->rlegType, ui->llegType, ui->rlegaType, ui->llegaType + tr("Hat"), tr("Hat Accessory"), tr("Head"), tr("Neck"), tr("Torso"), tr("Hip"), tr("Hip Accessory"), tr("Left Arm"), tr("Right Arm"), tr("Left Hand"), tr("Right Hand"), + tr("Left Hand Accessory"), tr("Right Hand Accessory"), tr("Left Leg"), tr("Right Leg"), tr("Left Leg Accessory"), tr("Right Leg Accessory") }; - mColorPickers = + QSizePolicy PieceButtonSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + PieceButtonSizePolicy.setHorizontalStretch(2); + PieceButtonSizePolicy.setVerticalStretch(0); + + for (int ItemIndex = 0; ItemIndex < LC_MFW_NUMITEMS; ItemIndex++) { - ui->hatsColor, ui->hats2Color, ui->headColor, ui->neckColor, ui->bodyColor, ui->body2Color, ui->body3Color, ui->rarmColor, ui->larmColor, - ui->rhandColor, ui->lhandColor, ui->rhandaColor, ui->lhandaColor, ui->rlegColor, ui->llegColor, ui->rlegaColor, ui->llegaColor - }; + bool Left = IsLeft[ItemIndex]; - mSpinBoxes = - { - ui->hatsAngle, ui->hats2Angle, ui->headAngle, nullptr, nullptr, nullptr, nullptr, ui->rarmAngle, ui->larmAngle, - ui->rhandAngle, ui->lhandAngle, ui->rhandaAngle, ui->lhandaAngle, ui->rlegAngle, ui->llegAngle, ui->rlegaAngle, ui->llegaAngle - }; + lcElidableToolButton* PieceButton = new lcElidableToolButton(this); + mPieceButtons[ItemIndex] = PieceButton; + PieceButton->setSizePolicy(PieceButtonSizePolicy); - for (QComboBox* ComboBox : mComboBoxes) - connect(ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(TypeChanged(int))); + connect(PieceButton, &QToolButton::clicked, this, &lcMinifigDialog::PieceButtonClicked); + + lcColorPicker* ColorPicker = new lcColorPicker(this); + mColorPickers[ItemIndex] = ColorPicker; - for (lcColorPicker* ColorPicker : mColorPickers) connect(ColorPicker, &lcColorPicker::ColorChanged, this, &lcMinifigDialog::ColorChanged); - for (QDoubleSpinBox* SpinBox : mSpinBoxes) - if (SpinBox) - connect(SpinBox, SIGNAL(valueChanged(double)), this, SLOT(AngleChanged(double))); + lcDoubleSpinBox* SpinBox = HasSpinBox[ItemIndex] ? new lcDoubleSpinBox(this) : nullptr; + mSpinBoxes[ItemIndex] = SpinBox; - QGridLayout* PreviewLayout = new QGridLayout(ui->minifigFrame); + if (SpinBox) + { + SpinBox->setRange(-360.0, 360.0); + SpinBox->SetSnap(lcFloatPropertySnap::Rotation); + SpinBox->setSingleStep(5.0); + + connect(SpinBox, QOverload::of(&lcDoubleSpinBox::valueChanged), this, &lcMinifigDialog::AngleChanged); + } + + QWidget* Label = new QLabel(Labels[ItemIndex], this); + + auto AddRow=[MinifigLayout, Label, PieceButton, ColorPicker, SpinBox](int& Row, int Column) + { + if (Row) + { + MinifigLayout->setRowMinimumHeight(Row++, 2); + } + + MinifigLayout->addWidget(Label, Row++, Column + 0, 1, 3); + MinifigLayout->addWidget(PieceButton, Row, Column + 0); + MinifigLayout->addWidget(ColorPicker, Row, Column + 1); + + if (SpinBox) + MinifigLayout->addWidget(SpinBox, Row, Column + 2); + + Row++; + }; + + if (Left) + AddRow(LeftRow, 0); + else + AddRow(RightRow, 4); + } + + QFrame* PreviewFrame = new QFrame(ui->widget); + QSizePolicy PreviewSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + PreviewSizePolicy.setHorizontalStretch(3); + PreviewSizePolicy.setVerticalStretch(0); + PreviewFrame->setSizePolicy(PreviewSizePolicy); + PreviewFrame->setFrameShape(QFrame::NoFrame); + PreviewFrame->setFrameShadow(QFrame::Plain); + + MinifigLayout->addWidget(PreviewFrame, 0, 3, -1, 1); + + QGridLayout* PreviewLayout = new QGridLayout(PreviewFrame); PreviewLayout->setContentsMargins(0, 0, 0, 0); mMinifigWizard = new MinifigWizard(); @@ -58,34 +110,16 @@ lcMinifigDialog::lcMinifigDialog(QWidget* Parent) for (int ItemIndex = 0; ItemIndex < LC_MFW_NUMITEMS; ItemIndex++) { - const std::vector& PartList = mMinifigWizard->mSettings[ItemIndex]; - QStringList ItemStrings; - QVector Separators; + const std::vector& PieceList = mMinifigWizard->mSettings[ItemIndex]; + int PieceIndex = mMinifigWizard->GetSelectionIndex(ItemIndex); + QToolButton* PieceButton = mPieceButtons[ItemIndex]; - for (const lcMinifigPieceInfo& MinifigPieceInfo : PartList) - { - const char* Description = MinifigPieceInfo.Description; - - if (Description[0] != '-' || Description[1] != '-') - ItemStrings.append(Description); - else - Separators.append(ItemStrings.size()); - } - - QComboBox* ItemCombo = mComboBoxes[ItemIndex]; - - ItemCombo->blockSignals(true); - ItemCombo->addItems(ItemStrings); - for (int SeparatorIndex = Separators.size() - 1; SeparatorIndex >= 0; SeparatorIndex--) - ItemCombo->insertSeparator(Separators[SeparatorIndex]); - ItemCombo->setCurrentIndex(mMinifigWizard->GetSelectionIndex(ItemIndex)); - ItemCombo->blockSignals(false); + PieceButton->setText(PieceList[PieceIndex].Description); lcColorPicker* ColorPicker = mColorPickers[ItemIndex]; + QSignalBlocker ColorPickerBlocker(ColorPicker); - ColorPicker->blockSignals(true); ColorPicker->SetCurrentColor(mMinifigWizard->mMinifig.Colors[ItemIndex]); - ColorPicker->blockSignals(false); } UpdateTemplateCombo(); @@ -131,7 +165,7 @@ void lcMinifigDialog::on_TemplateComboBox_currentIndexChanged(const QString& Tem { if (Info == MinifigPieceInfo.Info) { - mComboBoxes[PartIdx]->setCurrentText(MinifigPieceInfo.Description); + mPieceButtons[PartIdx]->setText(MinifigPieceInfo.Description); break; } } @@ -139,7 +173,7 @@ void lcMinifigDialog::on_TemplateComboBox_currentIndexChanged(const QString& Tem } else { - mComboBoxes[PartIdx]->setCurrentText("None"); + mPieceButtons[PartIdx]->setText(tr("None")); } mColorPickers[PartIdx]->SetCurrentColorCode(Template.Colors[PartIdx]); @@ -176,12 +210,12 @@ void lcMinifigDialog::on_TemplateSaveButton_clicked() lcMinifigTemplate Template; - for (int PartIdx = 0; PartIdx < LC_MFW_NUMITEMS; PartIdx++) + for (int ItemIndex = 0; ItemIndex < LC_MFW_NUMITEMS; ItemIndex++) { - Template.Parts[PartIdx] = mMinifigWizard->mSettings[PartIdx][mComboBoxes[PartIdx]->currentIndex()].Info->mFileName; - Template.Colors[PartIdx] = mColorPickers[PartIdx]->GetCurrentColorCode(); - QDoubleSpinBox* AngleSpinBox = mSpinBoxes[PartIdx]; - Template.Angles[PartIdx] = AngleSpinBox ? AngleSpinBox->value() : 0.0f; + Template.Parts[ItemIndex] = mMinifigWizard->mSettings[ItemIndex][mMinifigWizard->GetSelectionIndex(ItemIndex)].Info->mFileName; + Template.Colors[ItemIndex] = mColorPickers[ItemIndex]->GetCurrentColorCode(); + QDoubleSpinBox* AngleSpinBox = mSpinBoxes[ItemIndex]; + Template.Angles[ItemIndex] = AngleSpinBox ? AngleSpinBox->value() : 0.0f; } mMinifigWizard->SaveTemplate(TemplateName, Template); @@ -245,16 +279,53 @@ void lcMinifigDialog::on_TemplateExportButton_clicked() File.write(Templates); } -void lcMinifigDialog::TypeChanged(int Index) +void lcMinifigDialog::PieceButtonClicked() { - std::array::iterator Search = std::find(mComboBoxes.begin(), mComboBoxes.end(), sender()); + QToolButton* PieceButton = qobject_cast(sender()); - if (Search == mComboBoxes.end()) + if (!PieceButton) return; + std::array::iterator Search = std::find(mPieceButtons.begin(), mPieceButtons.end(), PieceButton); + + if (Search == mPieceButtons.end()) + return; + + int ItemIndex = std::distance(mPieceButtons.begin(), Search); + PieceInfo* CurrentInfo = mMinifigWizard->mMinifig.Parts[ItemIndex]; + + QPoint Position = PieceButton->mapToGlobal(PieceButton->rect().bottomLeft()); + std::vector> Parts; + + Parts.reserve(mMinifigWizard->mSettings[ItemIndex].size()); + Parts.emplace_back(nullptr, tr("None").toStdString()); + + for (const lcMinifigPieceInfo& Setting : mMinifigWizard->mSettings[ItemIndex]) + if (Setting.Info) + Parts.emplace_back(Setting.Info, Setting.Description); + + std::optional Result = lcShowPieceListPopup(PieceButton, CurrentInfo, Parts, mMinifigWizard->mMinifig.Colors[ItemIndex], false, true, Position); + + if (!Result.has_value()) + return; + + PieceInfo* NewPiece = Result.value(); + mView->MakeCurrent(); - mMinifigWizard->SetSelectionIndex(std::distance(mComboBoxes.begin(), Search), Index); + mMinifigWizard->SetPieceInfo(ItemIndex, NewPiece); mView->Redraw(); + + if (NewPiece) + { + const std::vector& PieceList = mMinifigWizard->mSettings[ItemIndex]; + int PieceIndex = mMinifigWizard->GetSelectionIndex(ItemIndex); + + PieceButton->setText(PieceList[PieceIndex].Description); + } + else + { + PieceButton->setText("None"); + } } void lcMinifigDialog::ColorChanged(int Index) diff --git a/common/lc_minifigdialog.h b/common/lc_minifigdialog.h index 9b6aace2..9c57aa9a 100644 --- a/common/lc_minifigdialog.h +++ b/common/lc_minifigdialog.h @@ -24,7 +24,7 @@ protected slots: void on_TemplateDeleteButton_clicked(); void on_TemplateImportButton_clicked(); void on_TemplateExportButton_clicked(); - void TypeChanged(int Index); + void PieceButtonClicked(); void ColorChanged(int Index); void AngleChanged(double Value); @@ -34,7 +34,7 @@ protected: Ui::lcMinifigDialog* ui; lcView* mView; - std::array mComboBoxes; + std::array mPieceButtons; std::array mColorPickers; std::array mSpinBoxes; }; diff --git a/common/lc_minifigdialog.ui b/common/lc_minifigdialog.ui index 0b0b5c42..6504ea1f 100644 --- a/common/lc_minifigdialog.ui +++ b/common/lc_minifigdialog.ui @@ -6,7 +6,7 @@ 0 0 - 840 + 979 416 @@ -16,662 +16,7 @@ - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - 1 - 0 - - - - QFrame::NoFrame - - - QFrame::Plain - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - - - - - - - - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - - - - - - - - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - - - - - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - 60 - 16777215 - - - - 1 - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - - - - - - - - 1 - 0 - - - - QComboBox::AdjustToContents - - - 24 - - - - + @@ -739,61 +84,7 @@ - - - lcColorPicker - QToolButton -
lc_colorpicker.h
-
-
- hatsType - hatsColor - hatsAngle - headAngle - headColor - headType - hats2Type - hats2Color - hats2Angle - neckType - neckColor - bodyColor - bodyType - larmType - larmColor - larmAngle - rarmAngle - rarmColor - rarmType - lhandType - lhandColor - lhandAngle - rhandAngle - rhandColor - rhandType - lhandaType - lhandaColor - lhandaAngle - rhandaAngle - rhandaColor - rhandaType - body2Type - body2Color - body3Color - body3Type - llegType - llegColor - llegAngle - rlegAngle - rlegColor - rlegType - llegaType - llegaColor - llegaAngle - rlegaAngle - rlegaColor - rlegaType TemplateComboBox TemplateSaveButton TemplateDeleteButton diff --git a/common/lc_partselectionwidget.cpp b/common/lc_partselectionwidget.cpp index 268dfa48..b5382fff 100644 --- a/common/lc_partselectionwidget.cpp +++ b/common/lc_partselectionwidget.cpp @@ -86,9 +86,9 @@ void lcPartSelectionListModel::SetColorIndex(int ColorIndex) if (mColorLocked || ColorIndex == mColorIndex) return; - UpdateThumbnails(); - mColorIndex = ColorIndex; + + UpdateThumbnails(); } void lcPartSelectionListModel::ToggleColorLocked() @@ -234,29 +234,43 @@ void lcPartSelectionListModel::SetCurrentModelCategory() SetFilter(mFilter); } -void lcPartSelectionListModel::SetCustomParts(const std::vector& Parts) +void lcPartSelectionListModel::SetCustomParts(const std::vector>& Parts, int ColorIndex, bool Sort) { beginResetModel(); + mColorLocked = true; + mColorIndex = ColorIndex; + ReleaseThumbnails(); mParts.clear(); - for (PieceInfo* Part : Parts) + for (auto [Info, Description] : Parts) { lcPartSelectionListModelEntry& Entry = mParts.emplace_back(); - Entry.Info = Part; + Entry.Info = Info; + Entry.Description = Description; - if (lcTrainTrackInfo* TrainTrackInfo = Part->GetTrainTrackInfo()) - Entry.ColorIndex = mColorIndex; + if (Info) + if (lcTrainTrackInfo* TrainTrackInfo = Info->GetTrainTrackInfo()) + Entry.ColorIndex = mColorIndex; } - auto lcPartSortFunc = [](const lcPartSelectionListModelEntry& a, const lcPartSelectionListModelEntry& b) + if (Sort) { - return strcmp(a.Info->m_strDescription, b.Info->m_strDescription) < 0; - }; + auto lcPartSortFunc = [](const lcPartSelectionListModelEntry& a, const lcPartSelectionListModelEntry& b) + { + if (!a.Info) + return true; - std::sort(mParts.begin(), mParts.end(), lcPartSortFunc); + if (!b.Info) + return false; + + return strcmp(a.Info->m_strDescription, b.Info->m_strDescription) < 0; + }; + + std::sort(mParts.begin(), mParts.end(), lcPartSortFunc); + } endResetModel(); @@ -286,14 +300,16 @@ void lcPartSelectionListModel::SetFilter(const QString& Filter) PieceInfo* Info = mParts[PartIdx].Info; bool Visible = true; - if (!mShowDecoratedParts && Info->IsPatterned() && !Info->IsProjectPiece()) + if (!Info) + Visible = true; + else if (!mShowDecoratedParts && Info->IsPatterned() && !Info->IsProjectPiece()) Visible = false; else if (!mShowPartAliases && Info->m_strDescription[0] == '=') Visible = false; else if (!mFilter.isEmpty()) { char Description[sizeof(Info->m_strDescription)]; - char* Src = Info->m_strDescription; + const char* Src = mParts[PartIdx].Description.empty() ? Info->m_strDescription : mParts[PartIdx].Description.c_str(); char* Dst = Description; for (;;) @@ -312,10 +328,12 @@ void lcPartSelectionListModel::SetFilter(const QString& Filter) if (FixedStringFilter) { if (DefaultFilter) + { if (mCaseSensitiveFilter) Visible = strstr(Description, mFilter) || strstr(Info->mFileName, mFilter); else Visible = strcasestr(Description, mFilter) || strcasestr(Info->mFileName, mFilter); + } else if (mFileNameFilter) Visible = mCaseSensitiveFilter ? strstr(Info->mFileName, mFilter) : strcasestr(Info->mFileName, mFilter); else if (mPartDescriptionFilter) @@ -323,14 +341,15 @@ void lcPartSelectionListModel::SetFilter(const QString& Filter) } else { + QString DescriptionString = mParts[PartIdx].Description.empty() ? QString(Description) : QString::fromStdString(mParts[PartIdx].Description); + if (DefaultFilter) - Visible = QString(Description).contains(FilterRx) || QString(Info->mFileName).contains(FilterRx); + Visible = DescriptionString.contains(FilterRx) || QString(Info->mFileName).contains(FilterRx); else if (mFileNameFilter) Visible = QString(Info->mFileName).contains(FilterRx); else if (mPartDescriptionFilter) - Visible = QString(Description).contains(FilterRx); + Visible = DescriptionString.contains(FilterRx); } - } mListView->setRowHidden((int)PartIdx, !Visible); @@ -356,11 +375,13 @@ QVariant lcPartSelectionListModel::data(const QModelIndex& Index, int Role) cons { case Qt::DisplayRole: if (!mIconSize || mShowPartNames || mListMode) - return QVariant(QString::fromLatin1(Info->m_strDescription)); + return QVariant(mParts[InfoIndex].Description.empty() ? QString::fromLatin1(Info->m_strDescription) : QString::fromStdString(mParts[InfoIndex].Description)); break; case Qt::ToolTipRole: - return QVariant(QString("%1 (%2)").arg(QString::fromLatin1(Info->m_strDescription), QString::fromLatin1(Info->mFileName))); + if (Info) + return QVariant(QString("%1 (%2)").arg(QString::fromLatin1(Info->m_strDescription), QString::fromLatin1(Info->mFileName))); + break; case Qt::DecorationRole: if (mIconSize && !mParts[InfoIndex].Pixmap.isNull()) @@ -424,6 +445,10 @@ void lcPartSelectionListModel::RequestThumbnail(int PartIndex) return; PieceInfo* Info = mParts[PartIndex].Info; + + if (!Info) + return; + int ColorIndex = mParts[PartIndex].ColorIndex == -1 ? mColorIndex : mParts[PartIndex].ColorIndex; auto [ThumbnailId, Thumbnail] = lcGetPiecesLibrary()->GetThumbnailManager()->RequestThumbnail(Info, ColorIndex, mIconSize); @@ -581,8 +606,7 @@ void lcPartSelectionListView::DoubleClicked(const QModelIndex& Index) { PieceInfo* Info = GetListModel()->GetPieceInfo(Index.row()); - if (Info) - emit PartPicked(Info); + emit PartPicked(Info); } void lcPartSelectionListView::CustomContextMenuRequested(QPoint Pos) @@ -671,11 +695,11 @@ void lcPartSelectionListView::SetCategory(lcPartCategoryType Type, int Index) } } -void lcPartSelectionListView::SetCustomParts(const std::vector& Parts) +void lcPartSelectionListView::SetCustomParts(const std::vector>& Parts, int ColorIndex, bool Sort) { mCategoryType = lcPartCategoryType::Custom; - mListModel->SetCustomParts(Parts); + mListModel->SetCustomParts(Parts, ColorIndex, Sort); setCurrentIndex(mListModel->index(0, 0)); } @@ -840,6 +864,44 @@ void lcPartSelectionListView::startDrag(Qt::DropActions SupportedActions) Drag->exec(Qt::CopyAction); } +QSize lcPartSelectionListView::sizeHint() const +{ + if (model()->rowCount() == 0) + return QListView::sizeHint(); + + if (mListModel->GetIconSize() == 0) + return QSize(500, 350); + + QRect CellRect1 = visualRect(model()->index(0, 0)); + QRect RightRect(CellRect1.topRight(), CellRect1.size()); + QRect BottomRect(CellRect1.bottomLeft(), CellRect1.size()); + + for (int Row = 1; Row < model()->rowCount(); Row++) + { + QRect Rect = visualRect(model()->index(Row, 0)); + + if (Row == 1) + RightRect = Rect; + + if (Rect.top() != CellRect1.top()) + { + BottomRect = Rect; + break; + } + } + + int Columns = 5; + int Rows = qMin(4, (model()->rowCount() + Columns - 1) / Columns); + + QSize CellSize(RightRect.left() - CellRect1.left(), BottomRect.top() - CellRect1.top()); + QSize Size(CellSize.width() * Columns + frameWidth() * 2, CellSize.height() * Rows + frameWidth() * 2); + + if (verticalScrollBar()) + Size += QSize(verticalScrollBar()->width() + 1, 0); + + return Size; +} + lcPartSelectionWidget::lcPartSelectionWidget(QWidget* Parent) : QWidget(Parent) { diff --git a/common/lc_partselectionwidget.h b/common/lc_partselectionwidget.h index de6fa60d..631569de 100644 --- a/common/lc_partselectionwidget.h +++ b/common/lc_partselectionwidget.h @@ -57,6 +57,7 @@ protected: struct lcPartSelectionListModelEntry { PieceInfo* Info = nullptr; + std::string Description; int ColorIndex = -1; QPixmap Pixmap; lcPartThumbnailId ThumbnailId = lcPartThumbnailId::Invalid; @@ -150,7 +151,7 @@ public: void SetModelsCategory(); void SetPaletteCategory(int SetIndex); void SetCurrentModelCategory(); - void SetCustomParts(const std::vector& Parts); + void SetCustomParts(const std::vector>& Parts, int ColorIndex, bool Sort); void SetFilter(const QString& Filter); void RequestThumbnail(int PartIndex); void SetShowDecoratedParts(bool Show); @@ -192,9 +193,10 @@ public: lcPartSelectionListView(QWidget* Parent, lcPartSelectionWidget* PartSelectionWidget); void startDrag(Qt::DropActions SupportedActions) override; + QSize sizeHint() const override; void SetCategory(lcPartCategoryType Type, int Index); - void SetCustomParts(const std::vector& Parts); + void SetCustomParts(const std::vector>& Parts, int ColorIndex, bool Sort); void SetCurrentPart(PieceInfo* Info); PieceInfo* GetCurrentPart() const diff --git a/common/lc_view.cpp b/common/lc_view.cpp index 1acf9754..54515d93 100644 --- a/common/lc_view.cpp +++ b/common/lc_view.cpp @@ -331,7 +331,8 @@ void lcView::ShowTrainTrackPopup() int ConnectionIndex = mTrackToolSection - LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST; const lcTrainTrackConnectionType& ConnectionType = TrainTrackInfo->GetConnections()[ConnectionIndex].Type; - PieceInfo* Info = lcShowTrainTrackPopup(mWidget, ConnectionType); + std::optional Result = lcShowTrainTrackPopup(mWidget, ConnectionType); + PieceInfo* Info = Result.has_value() ? Result.value() : nullptr; if (Info) { diff --git a/common/minifig.cpp b/common/minifig.cpp index e88f6cce..3d88dd4b 100644 --- a/common/minifig.cpp +++ b/common/minifig.cpp @@ -117,7 +117,6 @@ void MinifigWizard::ParseSettings(lcFile& Settings) if (!FoundSection) { - lcMinifigPieceInfo MinifigInfo; strncpy(MinifigInfo.Description, "None", sizeof(MinifigInfo.Description)); MinifigInfo.Description[sizeof(MinifigInfo.Description)-1] = 0; @@ -466,14 +465,14 @@ int MinifigWizard::GetSelectionIndex(int Type) const return 0; } -void MinifigWizard::SetSelectionIndex(int Type, int Index) +void MinifigWizard::SetPieceInfo(int Type, PieceInfo* Info) { lcPiecesLibrary* Library = lcGetPiecesLibrary(); if (mMinifig.Parts[Type]) Library->ReleasePieceInfo(mMinifig.Parts[Type]); - mMinifig.Parts[Type] = mSettings[Type][Index].Info; + mMinifig.Parts[Type] = Info; if (mMinifig.Parts[Type]) Library->LoadPieceInfo(mMinifig.Parts[Type], true, true); diff --git a/common/minifig.h b/common/minifig.h index 0ab192ec..95df0608 100644 --- a/common/minifig.h +++ b/common/minifig.h @@ -76,7 +76,7 @@ public: void Calculate(); int GetSelectionIndex(int Type) const; - void SetSelectionIndex(int Type, int Index); + void SetPieceInfo(int Type, PieceInfo* Info); void SetColor(int Type, int Color); void SetAngle(int Type, float Angle); diff --git a/qt/lc_qutils.cpp b/qt/lc_qutils.cpp index 971e15f1..380f17c6 100644 --- a/qt/lc_qutils.cpp +++ b/qt/lc_qutils.cpp @@ -5,6 +5,7 @@ #include "lc_model.h" #include "pieceinf.h" #include "lc_partselectionwidget.h" +#include "lc_mainwindow.h" QString lcFormatValue(float Value, int Precision) { @@ -183,7 +184,7 @@ lcPieceIdPickerPopup::lcPieceIdPickerPopup(PieceInfo* Current, QWidget* Parent) connect(mPartSelectionWidget, &lcPartSelectionWidget::PartPicked, this, &lcPieceIdPickerPopup::PartPicked); - QDialogButtonBox* ButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, this); + QDialogButtonBox* ButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); Layout->addWidget(ButtonBox); QObject::connect(ButtonBox, &QDialogButtonBox::accepted, this, &lcPieceIdPickerPopup::Accept); @@ -229,50 +230,59 @@ void lcPieceIdPickerPopup::Close() Menu->close(); } -lcTrainTrackPickerPopup::lcTrainTrackPickerPopup(QWidget* Parent, const lcTrainTrackConnectionType& ConnectionType) - : QWidget(Parent) +lcPieceListPickerPopup::lcPieceListPickerPopup(QWidget* Parent, PieceInfo* InitialPart, const std::vector>& Parts, int ColorIndex, bool Sort, bool ShowFilter) + : QWidget(Parent), mInitialPart(InitialPart) { QVBoxLayout* Layout = new QVBoxLayout(this); + if (ShowFilter) + { + mFilterWidget = new QLineEdit(this); + mFilterWidget->setPlaceholderText(tr("Filter Parts")); + Layout->addWidget(mFilterWidget); + + connect(mFilterWidget, &QLineEdit::textChanged, this, &lcPieceListPickerPopup::FilterChanged); + } + mPartSelectionListView = new lcPartSelectionListView(this, nullptr); Layout->addWidget(mPartSelectionListView); mPartSelectionListView->setMinimumWidth(450); mPartSelectionListView->setDragEnabled(false); - std::vector Parts = lcGetPiecesLibrary()->GetVisibleTrainTrackParts(ConnectionType); + mPartSelectionListView->SetCustomParts(Parts, ColorIndex, Sort); - mPartSelectionListView->SetCustomParts(Parts); + connect(mPartSelectionListView, &lcPartSelectionListView::PartPicked, this, &lcPieceListPickerPopup::Accept); - connect(mPartSelectionListView, &lcPartSelectionListView::PartPicked, this, &lcTrainTrackPickerPopup::Accept); - - QDialogButtonBox* ButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, this); + QDialogButtonBox* ButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); Layout->addWidget(ButtonBox); - QObject::connect(ButtonBox, &QDialogButtonBox::accepted, this, &lcTrainTrackPickerPopup::Accept); - QObject::connect(ButtonBox, &QDialogButtonBox::rejected, this, &lcTrainTrackPickerPopup::Reject); + QObject::connect(ButtonBox, &QDialogButtonBox::accepted, this, &lcPieceListPickerPopup::Accept); + QObject::connect(ButtonBox, &QDialogButtonBox::rejected, this, &lcPieceListPickerPopup::Reject); } -void lcTrainTrackPickerPopup::showEvent(QShowEvent* ShowEvent) +void lcPieceListPickerPopup::showEvent(QShowEvent* ShowEvent) { QWidget::showEvent(ShowEvent); + mPartSelectionListView->SetCurrentPart(mInitialPart); mPartSelectionListView->setFocus(); } -void lcTrainTrackPickerPopup::Accept() +void lcPieceListPickerPopup::Accept() { - mPickedTrainTrack = mPartSelectionListView->GetCurrentPart(); + mPickedPiece = mPartSelectionListView->GetCurrentPart(); + mAccepted = true; Close(); } -void lcTrainTrackPickerPopup::Reject() +void lcPieceListPickerPopup::Reject() { Close(); } -void lcTrainTrackPickerPopup::Close() +void lcPieceListPickerPopup::Close() { QMenu* Menu = qobject_cast(parent()); @@ -280,18 +290,58 @@ void lcTrainTrackPickerPopup::Close() Menu->close(); } -PieceInfo* lcShowTrainTrackPopup(QWidget* Parent, const lcTrainTrackConnectionType& ConnectionType) +void lcPieceListPickerPopup::FilterChanged(const QString& Text) +{ + if (mFilterAction) + { + if (Text.isEmpty()) + { + delete mFilterAction; + mFilterAction = nullptr; + } + } + else + { + if (!Text.isEmpty()) + { + mFilterAction = mFilterWidget->addAction(QIcon(":/stylesheet/close.svg"), QLineEdit::TrailingPosition); + connect(mFilterAction, &QAction::triggered, this, &lcPieceListPickerPopup::FilterTriggered); + } + } + + mPartSelectionListView->GetListModel()->SetFilter(Text); +} + +void lcPieceListPickerPopup::FilterTriggered() +{ + mFilterWidget->clear(); +} + +std::optional lcShowPieceListPopup(QWidget* Parent, PieceInfo* InitialPart, const std::vector>& Parts, int ColorIndex, bool Sort, bool ShowFilter, QPoint Position) { std::unique_ptr Menu(new QMenu(Parent)); QWidgetAction* Action = new QWidgetAction(Menu.get()); - lcTrainTrackPickerPopup* Popup = new lcTrainTrackPickerPopup(Menu.get(), ConnectionType); + lcPieceListPickerPopup* Popup = new lcPieceListPickerPopup(Menu.get(), InitialPart, Parts, ColorIndex, Sort, ShowFilter); Action->setDefaultWidget(Popup); Menu->addAction(Action); - Menu->exec(QCursor::pos()); + Menu->exec(Position); - return Popup->GetPickedTrainTrack(); + return Popup->GetPickedPiece(); +} + +std::optional lcShowTrainTrackPopup(QWidget* Parent, const lcTrainTrackConnectionType& ConnectionType) +{ + std::vector TrainTrackParts = lcGetPiecesLibrary()->GetVisibleTrainTrackParts(ConnectionType); + std::vector> Parts; + + Parts.reserve(TrainTrackParts.size()); + + for (PieceInfo* Info : TrainTrackParts) + Parts.emplace_back(Info, std::string()); + + return lcShowPieceListPopup(Parent, nullptr, Parts, gMainWindow->mColorIndex, true, false, QCursor::pos()); } lcColorDialogPopup::lcColorDialogPopup(const QColor& InitialColor, QWidget* Parent) diff --git a/qt/lc_qutils.h b/qt/lc_qutils.h index f919de35..91fa14e4 100644 --- a/qt/lc_qutils.h +++ b/qt/lc_qutils.h @@ -192,31 +192,39 @@ protected: PieceInfo* mInitialPart = nullptr; }; -class lcTrainTrackPickerPopup : public QWidget +class lcPieceListPickerPopup : public QWidget { Q_OBJECT public: - lcTrainTrackPickerPopup(QWidget* Parent, const lcTrainTrackConnectionType& ConnectionType); + lcPieceListPickerPopup(QWidget* Parent, PieceInfo* InitialPart, const std::vector>& Parts, int ColorIndex, bool Sort, bool ShowFilter); + virtual ~lcPieceListPickerPopup() = default; - PieceInfo* GetPickedTrainTrack() const + std::optional GetPickedPiece() const { - return mPickedTrainTrack; + return mAccepted ? std::optional(mPickedPiece) : std::nullopt; } protected slots: void Accept(); void Reject(); + void FilterChanged(const QString& Text); + void FilterTriggered(); protected: void showEvent(QShowEvent* ShowEvent) override; void Close(); lcPartSelectionListView* mPartSelectionListView = nullptr; - PieceInfo* mPickedTrainTrack = nullptr; + QLineEdit* mFilterWidget = nullptr; + QAction* mFilterAction = nullptr; + PieceInfo* mInitialPart = nullptr; + PieceInfo* mPickedPiece = nullptr; + bool mAccepted = false; }; -PieceInfo* lcShowTrainTrackPopup(QWidget* Parent, const lcTrainTrackConnectionType& ConnectionType); +std::optional lcShowPieceListPopup(QWidget* Parent, PieceInfo* InitialPart, const std::vector>& Parts, int ColorIndex, bool Sort, bool ShowFilter, QPoint Position); +std::optional lcShowTrainTrackPopup(QWidget* Parent, const lcTrainTrackConnectionType& ConnectionType); class lcColorDialogPopup : public QWidget {