From 39af5363018359f3e67bf75575c4841b057e85b4 Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Tue, 5 Jan 2021 18:48:12 -0800 Subject: [PATCH] Multiple rows/columns instructions. --- common/lc_global.h | 1 + common/lc_instructions.cpp | 125 +++++++++++++++++++++++++++++++ common/lc_instructions.h | 46 ++++++++++++ common/lc_instructionsdialog.cpp | 119 +++++++++++++++++++++++++---- common/lc_instructionsdialog.h | 22 ++++-- common/lc_mainwindow.cpp | 13 ++-- common/lc_model.cpp | 42 ----------- common/lc_model.h | 7 -- common/project.cpp | 10 +-- common/project.h | 6 +- leocad.pro | 2 + 11 files changed, 303 insertions(+), 90 deletions(-) create mode 100644 common/lc_instructions.cpp create mode 100644 common/lc_instructions.h diff --git a/common/lc_global.h b/common/lc_global.h index b0150d08..3be31534 100644 --- a/common/lc_global.h +++ b/common/lc_global.h @@ -73,6 +73,7 @@ typedef std::map> lcPartsList; struct lcModelPartsEntry; struct lcMinifig; enum class lcViewpoint; +class lcInstructions; class lcVector2; class lcVector3; diff --git a/common/lc_instructions.cpp b/common/lc_instructions.cpp new file mode 100644 index 00000000..f5d7ea99 --- /dev/null +++ b/common/lc_instructions.cpp @@ -0,0 +1,125 @@ +#include "lc_global.h" +#include "lc_instructions.h" +#include "project.h" +#include "lc_model.h" +#include "piece.h" +#include "pieceinf.h" + +lcInstructions::lcInstructions(Project* Project) + : mProject(Project) +{ + mPageSettings.Rows = 1; + mPageSettings.Columns = 1; + mPageSettings.Direction = lcInstructionsDirection::Horizontal; + + CreatePages(); +} + +void lcInstructions::SetDefaultPageSettings(const lcInstructionsPageSettings& PageSettings) +{ + mPageSettings = PageSettings; + + CreatePages(); +} + +void lcInstructions::CreatePages() +{ + mPages.clear(); + + if (mProject) + { + std::vector AddedModels; + + lcModel* Model = mProject->GetMainModel(); + + if (Model) + AddDefaultPages(Model, AddedModels); + } +} + +void lcInstructions::AddDefaultPages(lcModel* Model, std::vector& AddedModels) +{ + if (std::find(AddedModels.begin(), AddedModels.end(), Model) != AddedModels.end()) + return; + + AddedModels.push_back(Model); + + const lcStep LastStep = Model->GetLastStep(); + lcInstructionsPage Page; + int Row = 0, Column = 0; + + for (lcStep Step = 1; Step <= LastStep; Step++) + { + std::set StepSubModels; + + for (lcPiece* Piece : Model->GetPieces()) + { + if (!Piece->IsHidden() && Piece->GetStepShow() == Step && Piece->mPieceInfo->IsModel()) + { + lcModel* SubModel = Piece->mPieceInfo->GetModel(); + + if (std::find(AddedModels.begin(), AddedModels.end(), SubModel) != AddedModels.end()) + StepSubModels.insert(SubModel); + } + } + + if (!StepSubModels.empty()) + { + if (!Page.Steps.empty()) + { + mPages.emplace_back(std::move(Page)); + Row = 0; + Column = 0; + } + + for (lcModel* SubModel : StepSubModels) + AddDefaultPages(SubModel, AddedModels); + } + + lcInstructionsStep InstructionsStep; + + InstructionsStep.Model = Model; + InstructionsStep.Step = Step; + + const double Width = 1.0 / (double)mPageSettings.Columns; + const double Height = 1.0 / (double)mPageSettings.Rows; + InstructionsStep.Rect = QRectF(Column * Width, Row * Height, Width, Height); + + Page.Steps.push_back(std::move(InstructionsStep)); + + if (mPageSettings.Direction == lcInstructionsDirection::Horizontal) + { + Column++; + + if (Column == mPageSettings.Columns) + { + Row++; + Column = 0; + } + + if (Row == mPageSettings.Rows) + { + mPages.emplace_back(std::move(Page)); + Row = 0; + Column = 0; + } + } + else + { + Row++; + + if (Row == mPageSettings.Rows) + { + Row = 0; + Column++; + } + + if (Column == mPageSettings.Columns) + { + mPages.emplace_back(std::move(Page)); + Row = 0; + Column = 0; + } + } + } +} diff --git a/common/lc_instructions.h b/common/lc_instructions.h new file mode 100644 index 00000000..cf0aaee2 --- /dev/null +++ b/common/lc_instructions.h @@ -0,0 +1,46 @@ +#pragma once + +#include "object.h" + +enum class lcInstructionsDirection +{ + Horizontal, + Vertical +}; + +struct lcInstructionsPageSettings +{ + int Rows; + int Columns; + lcInstructionsDirection Direction; +}; + +struct lcInstructionsStep +{ + QRectF Rect; + lcModel* Model; + lcStep Step; +}; + +struct lcInstructionsPage +{ +// lcInstructionsPageSettings Settings; + std::vector Steps; +}; + +class lcInstructions +{ +public: + lcInstructions(Project* Project = nullptr); + + void SetDefaultPageSettings(const lcInstructionsPageSettings& PageSettings); + + std::vector mPages; + lcInstructionsPageSettings mPageSettings; + +protected: + void CreatePages(); + void AddDefaultPages(lcModel* Model, std::vector& AddedModels); + + Project* mProject = nullptr; +}; diff --git a/common/lc_instructionsdialog.cpp b/common/lc_instructionsdialog.cpp index 2bbef3ce..d0c6c1b5 100644 --- a/common/lc_instructionsdialog.cpp +++ b/common/lc_instructionsdialog.cpp @@ -3,29 +3,37 @@ #include "project.h" #include "lc_model.h" -lcInstructionsPageWidget::lcInstructionsPageWidget(QWidget* Parent, Project* Project) +lcInstructionsPageWidget::lcInstructionsPageWidget(QWidget* Parent) : QGraphicsView(Parent) { } -void lcInstructionsPageWidget::SetCurrentPage(lcInstructionsPageLayout* PageLayout) +void lcInstructionsPageWidget::SetCurrentPage(const lcInstructionsPage* Page) { QGraphicsScene* Scene = new QGraphicsScene(this); setScene(Scene); Scene->setSceneRect(0, 0, 1000, 1000); // Scene->setBackgroundBrush(Qt::black); - QImage StepImage = PageLayout->Model->GetStepImage(false, 500, 500, PageLayout->Step); - QGraphicsPixmapItem* StepImageItem = Scene->addPixmap(QPixmap::fromImage(StepImage)); - StepImageItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); + if (Page) + { + for (const lcInstructionsStep& Step : Page->Steps) + { + QImage StepImage = Step.Model->GetStepImage(false, 500, 500, Step.Step); + QGraphicsPixmapItem* StepImageItem = Scene->addPixmap(QPixmap::fromImage(StepImage)); + StepImageItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); + StepImageItem->setPos(1000.0 * Step.Rect.x(), 1000.0 * Step.Rect.y()); - QGraphicsSimpleTextItem* StepNumberItem = Scene->addSimpleText(QString::number(PageLayout->Step), QFont("Helvetica", 96)); - StepNumberItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); + QGraphicsSimpleTextItem* StepNumberItem = Scene->addSimpleText(QString::number(Step.Step), QFont("Helvetica", 96)); + StepNumberItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); + StepNumberItem->setPos(1000.0 * Step.Rect.x(), 1000.0 * Step.Rect.y()); - QImage PartsImage = PageLayout->Model->GetPartsListImage(300, PageLayout->Step); - QGraphicsPixmapItem* PartsImageItem = Scene->addPixmap(QPixmap::fromImage(PartsImage)); - PartsImageItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); - PartsImageItem->setPos(StepNumberItem->pos() + QPointF(StepNumberItem->sceneBoundingRect().width(), 0)); + QImage PartsImage = Step.Model->GetPartsListImage(300, Step.Step); + QGraphicsPixmapItem* PartsImageItem = Scene->addPixmap(QPixmap::fromImage(PartsImage)); + PartsImageItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); + PartsImageItem->setPos(StepNumberItem->pos() + QPointF(StepNumberItem->sceneBoundingRect().width(), 0)); + } + } } lcInstructionsDialog::lcInstructionsDialog(QWidget* Parent, Project* Project) @@ -36,6 +44,7 @@ lcInstructionsDialog::lcInstructionsDialog(QWidget* Parent, Project* Project) setWindowTitle(tr("Instructions")); QVBoxLayout* Layout = new QVBoxLayout(CentralWidget); + Layout->setContentsMargins(0, 0, 0, 0); QSplitter* Splitter = new QSplitter(CentralWidget); Splitter->setOrientation(Qt::Horizontal); @@ -44,19 +53,99 @@ lcInstructionsDialog::lcInstructionsDialog(QWidget* Parent, Project* Project) mThumbnailsWidget = new QListWidget(Splitter); Splitter->addWidget(mThumbnailsWidget); - mPageWidget = new lcInstructionsPageWidget(Splitter, mProject); + mPageWidget = new lcInstructionsPageWidget(Splitter); Splitter->addWidget(mPageWidget); - mPageLayouts = mProject->GetPageLayouts(); + mInstructions = mProject->GetInstructions(); - for (size_t PageNumber = 0; PageNumber < mPageLayouts.size(); PageNumber++) + mPageSettingsToolBar = addToolBar(tr("Page Settings")); + mPageSettingsToolBar->setObjectName("PageSettings"); + mPageSettingsToolBar->setFloatable(false); + mPageSettingsToolBar->setMovable(false); + + mVerticalPageAction = mPageSettingsToolBar->addAction("Vertical"); + mVerticalPageAction->setCheckable(true); + mHorizontalPageAction = mPageSettingsToolBar->addAction("Horizontal"); + mHorizontalPageAction->setCheckable(true); + + mRowsSpinBox = new QSpinBox(mPageSettingsToolBar); + mPageSettingsToolBar->addWidget(mRowsSpinBox); + + mColumnsSpinBox = new QSpinBox(mPageSettingsToolBar); + mPageSettingsToolBar->addWidget(mColumnsSpinBox); + + QActionGroup* PageDirectionGroup = new QActionGroup(mPageSettingsToolBar); + PageDirectionGroup->addAction(mVerticalPageAction); + PageDirectionGroup->addAction(mHorizontalPageAction); + + for (size_t PageNumber = 0; PageNumber < mInstructions.mPages.size(); PageNumber++) mThumbnailsWidget->addItem(QString("Page %1").arg(PageNumber + 1)); connect(mThumbnailsWidget, SIGNAL(currentRowChanged(int)), this, SLOT(CurrentThumbnailChanged(int))); mThumbnailsWidget->setCurrentRow(0); + + connect(mVerticalPageAction, SIGNAL(checked()), this, SLOT(UpdatePageSettings())); + connect(mHorizontalPageAction, SIGNAL(checked()), this, SLOT(UpdatePageSettings())); + connect(mRowsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdatePageSettings())); + connect(mColumnsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdatePageSettings())); +} + +void lcInstructionsDialog::UpdatePageSettings() +{ + lcInstructionsPageSettings PageSettings; + + PageSettings.Rows = mRowsSpinBox->value(); + PageSettings.Columns = mColumnsSpinBox->value(); + + if (mHorizontalPageAction->isChecked()) + PageSettings.Direction = lcInstructionsDirection::Horizontal; + else + PageSettings.Direction = lcInstructionsDirection::Vertical; + + mInstructions.SetDefaultPageSettings(PageSettings); +// lcInstructionsPage* Page = &mInstructions.mPages[mThumbnailsWidget->currentIndex().row()]; + + mThumbnailsWidget->clear(); + for (size_t PageNumber = 0; PageNumber < mInstructions.mPages.size(); PageNumber++) + mThumbnailsWidget->addItem(QString("Page %1").arg(PageNumber + 1)); + +// mThumbnailsWidget->setCurrentRow(0); + +// mPageWidget->SetCurrentPage(Page); } void lcInstructionsDialog::CurrentThumbnailChanged(int Index) { - mPageWidget->SetCurrentPage(&mPageLayouts[Index]); + if (Index < 0 || Index >= mInstructions.mPages.size()) + { + mPageWidget->SetCurrentPage(nullptr); + return; + } + + const lcInstructionsPage* Page = &mInstructions.mPages[Index]; +// const lcInstructionsPageSettings& PageSettings = Page->Settings; + const lcInstructionsPageSettings& PageSettings = mInstructions.mPageSettings; + + mPageWidget->SetCurrentPage(Page); + + if (PageSettings.Direction == lcInstructionsDirection::Horizontal) + { + mHorizontalPageAction->blockSignals(true); + mHorizontalPageAction->setChecked(true); + mHorizontalPageAction->blockSignals(false); + } + else + { + mVerticalPageAction->blockSignals(true); + mVerticalPageAction->setChecked(true); + mVerticalPageAction->blockSignals(false); + } + + mRowsSpinBox->blockSignals(true); + mRowsSpinBox->setValue(PageSettings.Rows); + mRowsSpinBox->blockSignals(false); + + mColumnsSpinBox->blockSignals(true); + mColumnsSpinBox->setValue(PageSettings.Columns); + mColumnsSpinBox->blockSignals(false); } diff --git a/common/lc_instructionsdialog.h b/common/lc_instructionsdialog.h index 07f141b7..9f716c36 100644 --- a/common/lc_instructionsdialog.h +++ b/common/lc_instructionsdialog.h @@ -1,16 +1,15 @@ #pragma once -//struct lcInstructionsPageLayout; -#include "lc_model.h" +#include "lc_instructions.h" class lcInstructionsPageWidget : public QGraphicsView { Q_OBJECT public: - lcInstructionsPageWidget(QWidget* Parent, Project* Project); + lcInstructionsPageWidget(QWidget* Parent); - void SetCurrentPage(lcInstructionsPageLayout* PageLayout); + void SetCurrentPage(const lcInstructionsPage* Page); }; class lcInstructionsDialog : public QMainWindow @@ -21,14 +20,21 @@ public: lcInstructionsDialog(QWidget* Parent, Project* Project); protected slots: + void UpdatePageSettings(); void CurrentThumbnailChanged(int Index); protected: - Project* mProject; + Project* mProject = nullptr; int mCurrentPageNumber; - std::vector mPageLayouts; + lcInstructions mInstructions; - QListWidget* mThumbnailsWidget; - lcInstructionsPageWidget* mPageWidget; + QListWidget* mThumbnailsWidget = nullptr; + lcInstructionsPageWidget* mPageWidget = nullptr ; + + QToolBar* mPageSettingsToolBar = nullptr; + QAction* mVerticalPageAction = nullptr; + QAction* mHorizontalPageAction = nullptr; + QSpinBox* mRowsSpinBox = nullptr; + QSpinBox* mColumnsSpinBox = nullptr; }; diff --git a/common/lc_mainwindow.cpp b/common/lc_mainwindow.cpp index a2522984..d5005d98 100644 --- a/common/lc_mainwindow.cpp +++ b/common/lc_mainwindow.cpp @@ -1144,8 +1144,8 @@ void lcMainWindow::Print(QPrinter* Printer) int DocCopies; int PageCopies; - std::vector PageLayouts = lcGetActiveProject()->GetPageLayouts(); - const int PageCount = static_cast(PageLayouts.size()); + lcInstructions Instructions = lcGetActiveProject()->GetInstructions(); + const int PageCount = static_cast(Instructions.mPages.size()); if (Printer->collateCopies()) { @@ -1214,8 +1214,9 @@ void lcMainWindow::Print(QPrinter* Printer) int StepWidth = MarginRect.width(); int StepHeight = MarginRect.height(); - lcModel* Model = PageLayouts[Page - 1].Model; - lcStep Step = PageLayouts[Page - 1].Step; + const lcInstructionsPage& PageLayout = Instructions.mPages[Page - 1]; + lcModel* Model = PageLayout.Steps[0].Model; + lcStep Step = PageLayout.Steps[0].Step; QImage Image = Model->GetStepImage(false, StepWidth, StepHeight, Step); Painter.drawImage(MarginRect.left(), MarginRect.top(), Image); @@ -1319,7 +1320,7 @@ void lcMainWindow::ShowInstructionsDialog() void lcMainWindow::ShowPrintDialog() { #ifndef QT_NO_PRINTER - int PageCount = static_cast(lcGetActiveProject()->GetPageLayouts().size()); + int PageCount = static_cast(lcGetActiveProject()->GetInstructions().mPages.size()); QPrinter Printer(QPrinter::HighResolution); Printer.setFromTo(1, PageCount + 1); @@ -1943,7 +1944,7 @@ void lcMainWindow::TogglePrintPreview() #ifndef QT_NO_PRINTER // todo: print preview inside main window - int PageCount = static_cast(lcGetActiveProject()->GetPageLayouts().size()); + int PageCount = static_cast(lcGetActiveProject()->GetInstructions().mPages.size()); QPrinter Printer(QPrinter::ScreenResolution); Printer.setFromTo(1, PageCount + 1); diff --git a/common/lc_model.cpp b/common/lc_model.cpp index 31fd5c6c..5166d5bb 100644 --- a/common/lc_model.cpp +++ b/common/lc_model.cpp @@ -1547,48 +1547,6 @@ void lcModel::SaveStepImages(const QString& BaseName, bool AddStepSuffix, bool Z } } -std::vector lcModel::GetPageLayouts(std::vector& AddedModels) -{ - std::vector PageLayouts; - - if (std::find(AddedModels.begin(), AddedModels.end(), this) != AddedModels.end()) - return PageLayouts; - - AddedModels.push_back(this); - - std::map> StepPieces; - - for (lcPiece* Piece : mPieces) - if (!Piece->IsHidden()) - StepPieces[Piece->GetStepShow()].push_back(Piece); - - lcStep CurrentStep = 1; - - for (const std::pair>& StepIt : StepPieces) - { - while (StepIt.first > CurrentStep) - { - PageLayouts.emplace_back(lcInstructionsPageLayout{ this, CurrentStep }); - CurrentStep++; - } - - for (lcPiece* Piece : StepIt.second) - { - if (Piece->mPieceInfo->IsModel()) - { - lcModel* SubModel = Piece->mPieceInfo->GetModel(); - std::vector SubModelLayouts = SubModel->GetPageLayouts(AddedModels); - PageLayouts.insert(PageLayouts.end(), std::make_move_iterator(SubModelLayouts.begin()), std::make_move_iterator(SubModelLayouts.end())); - } - } - - PageLayouts.emplace_back(lcInstructionsPageLayout{ this, CurrentStep }); - CurrentStep++; - } - - return PageLayouts; -} - void lcModel::RayTest(lcObjectRayTest& ObjectRayTest) const { for (lcPiece* Piece : mPieces) diff --git a/common/lc_model.h b/common/lc_model.h index 17acdcaf..7d94893d 100644 --- a/common/lc_model.h +++ b/common/lc_model.h @@ -18,12 +18,6 @@ #define LC_SEL_CAN_ADD_CONTROL_POINT 0x0800 // Can add control points to focused piece #define LC_SEL_CAN_REMOVE_CONTROL_POINT 0x1000 // Can remove control points from focused piece -struct lcInstructionsPageLayout -{ - lcModel* Model; - lcStep Step; -}; - enum class lcSelectionMode { Single, @@ -243,7 +237,6 @@ public: QImage GetStepImage(bool Zoom, int Width, int Height, lcStep Step); QImage GetPartsListImage(int MaxWidth, lcStep Step) const; void SaveStepImages(const QString& BaseName, bool AddStepSuffix, bool Zoom, int Width, int Height, lcStep Start, lcStep End); - std::vector GetPageLayouts(std::vector& AddedModels); void RayTest(lcObjectRayTest& ObjectRayTest) const; void BoxTest(lcObjectBoxTest& ObjectBoxTest) const; diff --git a/common/project.cpp b/common/project.cpp index 2bb9bf14..c0dfde95 100644 --- a/common/project.cpp +++ b/common/project.cpp @@ -5,6 +5,7 @@ #include "pieceinf.h" #include "camera.h" #include "project.h" +#include "lc_instructions.h" #include "image.h" #include "lc_mainwindow.h" #include "lc_view.h" @@ -1501,14 +1502,9 @@ void Project::ExportCSV() } } -std::vector Project::GetPageLayouts() const +lcInstructions Project::GetInstructions() { - std::vector AddedModels; - - if (!mModels.IsEmpty()) - return mModels[0]->GetPageLayouts(AddedModels); - - return std::vector(); + return lcInstructions(this); } void Project::ExportHTML(const lcHTMLExportOptions& Options) diff --git a/common/project.h b/common/project.h index 252cabed..2876598b 100644 --- a/common/project.h +++ b/common/project.h @@ -29,8 +29,6 @@ public: bool PartsListEnd; }; -struct lcInstructionsPageLayout; - class Project { public: @@ -38,9 +36,7 @@ public: ~Project(); Project(const Project&) = delete; - Project(Project&&) = delete; Project& operator=(const Project&) = delete; - Project& operator=(Project&&) = delete; const lcArray& GetModels() const { @@ -75,7 +71,7 @@ public: QString GetImageFileName(bool AllowCurrentFolder) const; - std::vector GetPageLayouts() const; + lcInstructions GetInstructions(); void SetActiveModel(int ModelIndex); void SetActiveModel(const QString& FileName); diff --git a/leocad.pro b/leocad.pro index 07bb9f05..cc0bb135 100644 --- a/leocad.pro +++ b/leocad.pro @@ -186,6 +186,7 @@ SOURCES += \ common/lc_file.cpp \ common/lc_glextensions.cpp \ common/lc_http.cpp \ + common/lc_instructions.cpp \ common/lc_instructionsdialog.cpp \ common/lc_library.cpp \ common/lc_lxf.cpp \ @@ -252,6 +253,7 @@ HEADERS += \ common/lc_glextensions.h \ common/lc_global.h \ common/lc_http.h \ + common/lc_instructions.h \ common/lc_instructionsdialog.h \ common/lc_library.h \ common/lc_lxf.h \