diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml new file mode 100644 index 00000000..b859dec5 --- /dev/null +++ b/.github/workflows/continuous.yml @@ -0,0 +1,65 @@ +name: LeoCAD CI + +on: + push: + branches: [ "master" ] + +jobs: + build-ubuntu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + cache: 'true' + - name: Get number of CPU cores + uses: SimenB/github-actions-cpu-cores@v1 + id: cpu-cores + - name: Generate Makefile + run: qmake PREFIX=/usr + - name: Build + run: make -j ${{ steps.cpu-cores.outputs.count }} + + build-macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + cache: 'true' + - name: Cache Library + uses: actions/cache@v3 + id: cache-library + with: + path: library.bin + key: library-20.03 + - name: Download Library + if: steps.cache-library.outputs.cache-hit != 'true' + run: | + wget https://github.com/leozide/leocad/releases/download/v19.07.1/Library-20.03.zip -O library.zip + unzip library.zip + - name: Cache POV-Ray + uses: actions/cache@v3 + id: cache-povray + with: + path: povray + key: povray-20.03 + - name: Download POV-Ray + if: steps.cache-povray.outputs.cache-hit != 'true' + run: | + wget https://github.com/leozide/povray/releases/download/continuous/povray + chmod +x povray + curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/leozide/leocad/commits/master -o repo.txt + echo < repo.txt + echo export REMOTE=$(grep -Po '(?<=: \")(([a-z0-9])\w+)(?=\")' -m 1 repo.txt) + export REMOTE=$(grep -Po '(?<=: \")(([a-z0-9])\w+)(?=\")' -m 1 repo.txt) + echo $REMOTE + - name: Get number of CPU cores + uses: SimenB/github-actions-cpu-cores@v1 + id: cpu-cores + - name: Generate Makefile + run: qmake PREFIX=/usr + - name: Build + run: make -j ${{ steps.cpu-cores.outputs.count }} diff --git a/appveyor.yml b/appveyor.yml index c7616a77..752a5945 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,48 +1,118 @@ version: '{branch}.{build}' skip_tags: true image: +- Ubuntu1604 +- macos - Visual Studio 2019 configuration: Release platform: x64 environment: GITHUB_TOKEN: - secure: p5KEQtln6gMUfQLCkLsHUOhADIxPFjH8WICuY9pZeni1S1Es1XRGz7+OoFZKj8Ev + secure: ZaApxtWM3JA1AdJqs2pv+BCE5XIUrrVKXNy05q8f6f4zRZ7H/lMEJ6gZ1o2yp6NT -before_build: -- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" -- set PATH=C:\Qt\5.15\msvc2019_64\bin;%PATH% -- git rev-parse --short HEAD > version.txt -- set /p VERSION= < version.txt -- qmake -v -- qmake -tp vc +for: + - + matrix: + only: + - image: Visual Studio 2019 + + before_build: + - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" + - set PATH=C:\Qt\5.15\msvc2019_64\bin;%PATH% + - git rev-parse --short HEAD > version.txt + - set /p VERSION= < version.txt + - qmake -v + - qmake -tp vc -build: - project: leocad.vcxproj - verbosity: minimal + build: + project: leocad.vcxproj + verbosity: minimal -after_build: -- 7z a symbols.zip build/release/leocad.exe build/release/leocad.pdb -- mkdir appdir -- copy build\release\leocad.exe appdir -- copy docs\readme.md appdir\readme.txt -- appveyor DownloadFile https://github.com/leozide/leocad/releases/download/v19.07.1/Library-20.03.zip -FileName library.zip -- 7z e library.zip -- copy library.bin appdir\\library.bin -- appveyor DownloadFile https://github.com/leozide/povray/releases/download/continuous/povconsole32-sse2.exe -FileName appdir\povconsole32-sse2.exe -- windeployqt appdir\leocad.exe -- copy tools\setup\leocad.nsi . -- copy tools\setup\setup.ico . -- 'copy "%VCToolsRedistDir%\vcredist_x64.exe" appdir' -- '"C:\Program Files (x86)\NSIS\makensis.exe" /V4 /DX64 "/XOutFile LeoCAD-Windows-%VERSION%.exe" leocad.nsi' -- set TRAVIS_TAG=%APPVEYOR_REPO_TAG_NAME% -- set TRAVIS_REPO_SLUG=%APPVEYOR_REPO_NAME% -- set TRAVIS_COMMIT=%APPVEYOR_REPO_COMMIT% -- appveyor DownloadFile https://github.com/probonopd/uploadtool/raw/master/upload.sh -- if not defined APPVEYOR_PULL_REQUEST_NUMBER (bash upload.sh LeoCAD*.exe) + after_build: + - 7z a symbols.zip build/release/leocad.exe build/release/leocad.pdb + - mkdir appdir + - copy build\release\leocad.exe appdir + - copy docs\readme.md appdir\readme.txt + - appveyor DownloadFile https://github.com/leozide/leocad/releases/download/v19.07.1/Library-20.03.zip -FileName library.zip + - 7z e library.zip + - copy library.bin appdir\\library.bin + - appveyor DownloadFile https://github.com/leozide/povray/releases/download/continuous/povconsole32-sse2.exe -FileName appdir\povconsole32-sse2.exe + - windeployqt appdir\leocad.exe + - copy tools\setup\leocad.nsi . + - copy tools\setup\setup.ico . + - 'copy "%VCToolsRedistDir%\vcredist_x64.exe" appdir' + - '"C:\Program Files (x86)\NSIS\makensis.exe" /V4 /DX64 "/XOutFile LeoCAD-Windows-%VERSION%.exe" leocad.nsi' + - set TRAVIS_TAG=%APPVEYOR_REPO_TAG_NAME% + - set TRAVIS_REPO_SLUG=%APPVEYOR_REPO_NAME% + - set TRAVIS_COMMIT=%APPVEYOR_REPO_COMMIT% + - appveyor DownloadFile https://github.com/probonopd/uploadtool/raw/master/upload.sh + - if not defined APPVEYOR_PULL_REQUEST_NUMBER (bash upload.sh LeoCAD*.exe) -artifacts: -- path: symbols.zip - name: symbols -- path: LeoCAD-Windows-$(VERSION).exe - name: leocad + artifacts: + - path: symbols.zip + name: symbols + - path: LeoCAD-Windows-$(VERSION).exe + name: leocad + + - + matrix: + only: + - image: Ubuntu1604 + + install: + - sudo apt-get -y install libqt5opengl5-dev + + before_build: + - export PATH=$HOME/Qt/5.15/gcc_64/bin:$PATH + - export TRAVIS_TAG=$APPVEYOR_REPO_TAG_NAME + - export TRAVIS_REPO_SLUG=$APPVEYOR_REPO_NAME + - export TRAVIS_COMMIT=$APPVEYOR_REPO_COMMIT + + build_script: + - qmake PREFIX=/usr + - make + + after_build: + - cp build/release/leocad . + - export VERSION=$(git rev-parse --short HEAD) + - zip LeoCAD-Linux-$VERSION-arm64.zip leocad + - 'curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/leozide/leocad/commits/master -o repo.txt' + - 'export REMOTE=$(grep -Po ''(?<=: \")(([a-z0-9])\w+)(?=\")'' -m 1 repo.txt)' + - export LOCAL=$(git rev-parse HEAD) + - if [[ "$REMOTE" != "$LOCAL" ]]; then echo "Build no longer current. $REMOTE vs $LOCAL - aborting upload."; travis_terminate 0; fi; + - appveyor DownloadFile https://github.com/probonopd/uploadtool/raw/master/upload.sh + - bash upload.sh LeoCAD*.zip + + - + matrix: + only: + - image: macos + + install: + - brew install grep + + before_build: + - export PATH=$HOME/Qt/5.15/clang_64/bin:$PATH + - export TRAVIS_TAG=$APPVEYOR_REPO_TAG_NAME + - export TRAVIS_REPO_SLUG=$APPVEYOR_REPO_NAME + - export TRAVIS_COMMIT=$APPVEYOR_REPO_COMMIT + - appveyor DownloadFile https://github.com/leozide/povray/releases/download/continuous/povray + - chmod +x povray + - appveyor DownloadFile https://github.com/leozide/leocad/releases/download/v19.07.1/Library-20.03.zip -FileName library.zip + - unzip library.zip + + build_script: + - qmake PREFIX=/usr + - make + + after_build: + - cd build/release + - macdeployqt LeoCAD.app -dmg + - mv LeoCAD.dmg LeoCAD-macOS-$(git rev-parse --short HEAD).dmg + - 'curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/leozide/leocad/commits/master -o repo.txt' + - 'export REMOTE=$(ggrep -Po ''(?<=: \")(([a-z0-9])\w+)(?=\")'' -m 1 repo.txt)' + - export LOCAL=$(git rev-parse HEAD) + - if [[ "$REMOTE" != "$LOCAL" ]]; then echo "Build no longer current. $REMOTE vs $LOCAL - aborting upload."; exit 0; fi; + - appveyor DownloadFile https://github.com/probonopd/uploadtool/raw/master/upload.sh + - bash upload.sh LeoCAD*.dmg* diff --git a/common/lc_application.cpp b/common/lc_application.cpp index f009232e..e8bcfa17 100644 --- a/common/lc_application.cpp +++ b/common/lc_application.cpp @@ -354,20 +354,6 @@ lcCommandLineOptions lcApplication::ParseCommandLineOptions() lcCommandLineOptions Options; - Options.ParseOK = true; - Options.Exit = false; - Options.SaveImage = false; - Options.SaveWavefront = false; - Options.Save3DS = false; - Options.SaveCOLLADA = false; - Options.SaveHTML = false; - Options.SetCameraAngles = false; - Options.SetCameraPosition = false; - Options.Orthographic = false; - Options.SetFoV = false; - Options.SetZPlanes = false; - Options.SetFadeStepsColor = false; - Options.SetHighlightColor = false; Options.FadeSteps = Preferences.mFadeSteps; Options.ImageHighlight = Preferences.mHighlightNewParts; Options.ImageWidth = lcGetProfileInt(LC_PROFILE_IMAGE_WIDTH); @@ -788,6 +774,11 @@ lcCommandLineOptions lcApplication::ParseCommandLineOptions() Options.SaveCOLLADA = true; ParseString(Options.SaveCOLLADAName, false); } + else if (Option == QLatin1String("-csv") || Option == QLatin1String("--export-csv")) + { + Options.SaveCSV = true; + ParseString(Options.SaveCSVName, false); + } else if (Option == QLatin1String("-html") || Option == QLatin1String("--export-html")) { Options.SaveHTML = true; @@ -842,6 +833,7 @@ lcCommandLineOptions lcApplication::ParseCommandLineOptions() Options.StdOut += tr(" -obj, --export-wavefront : Export the model to Wavefront OBJ format.\n"); Options.StdOut += tr(" -3ds, --export-3ds : Export the model to 3D Studio 3DS format.\n"); Options.StdOut += tr(" -dae, --export-collada : Export the model to COLLADA DAE format.\n"); + Options.StdOut += tr(" -csv, --export-csv : Export the list of parts used in csv format.\n"); Options.StdOut += tr(" -html, --export-html : Create an HTML page for the model.\n"); Options.StdOut += tr(" -v, --version: Output version information and exit.\n"); Options.StdOut += tr(" -?, --help: Display this help message and exit.\n"); @@ -888,7 +880,7 @@ lcCommandLineOptions lcApplication::ParseCommandLineOptions() Options.StdErr += tr("--camera-position is ignored when --camera-angles is set.\n"); } - const bool SaveAndExit = (Options.SaveImage || Options.SaveWavefront || Options.Save3DS || Options.SaveCOLLADA || Options.SaveHTML); + const bool SaveAndExit = (Options.SaveImage || Options.SaveWavefront || Options.Save3DS || Options.SaveCOLLADA || Options.SaveCSV || Options.SaveHTML); if (SaveAndExit && Options.ProjectName.isEmpty()) { @@ -929,7 +921,7 @@ lcStartupMode lcApplication::Initialize(const QList>& Libra return lcStartupMode::Error; } - const bool SaveAndExit = (Options.SaveImage || Options.SaveWavefront || Options.Save3DS || Options.SaveCOLLADA || Options.SaveHTML); + const bool SaveAndExit = (Options.SaveImage || Options.SaveWavefront || Options.Save3DS || Options.SaveCOLLADA || Options.SaveCSV || Options.SaveHTML); if (!SaveAndExit) { @@ -1191,6 +1183,31 @@ lcStartupMode lcApplication::Initialize(const QList>& Libra StdOut << tr("Saved '%1'.\n").arg(FileName); } + if (Options.SaveCSV) + { + QString FileName; + + if (!Options.SaveCSVName.isEmpty()) + FileName = Options.SaveCSVName; + else + FileName = Options.ProjectName; + + QString Extension = QFileInfo(FileName).suffix().toLower(); + + if (Extension.isEmpty()) + { + FileName += ".csv"; + } + else if (Extension != "csv") + { + FileName = FileName.left(FileName.length() - Extension.length() - 1); + FileName += ".csv"; + } + + if (mProject->ExportCSV(FileName)) + StdOut << tr("Saved '%1'.\n").arg(FileName); + } + if (Options.SaveHTML) { lcHTMLExportOptions HTMLOptions(mProject); diff --git a/common/lc_application.h b/common/lc_application.h index fb1a8f83..6dd1cf89 100644 --- a/common/lc_application.h +++ b/common/lc_application.h @@ -101,23 +101,24 @@ public: struct lcCommandLineOptions { - bool ParseOK; - bool Exit; - bool SaveImage; - bool SaveWavefront; - bool Save3DS; - bool SaveCOLLADA; - bool SaveHTML; - bool SetCameraAngles; - bool SetCameraPosition; - bool Orthographic; - bool SetFoV; - bool SetZPlanes; - bool SetFadeStepsColor; - bool SetHighlightColor; - bool FadeSteps; - bool ImageHighlight; - bool AutomateEdgeColor; + bool ParseOK = true; + bool Exit = false; + bool SaveImage = false; + bool SaveWavefront = false; + bool Save3DS = false; + bool SaveCOLLADA = false; + bool SaveCSV = false; + bool SaveHTML = false; + bool SetCameraAngles = false; + bool SetCameraPosition = false; + bool Orthographic = false; + bool SetFoV = false; + bool SetZPlanes = false; + bool SetFadeStepsColor = false; + bool SetHighlightColor = false; + bool FadeSteps = false; + bool ImageHighlight = false; + bool AutomateEdgeColor = false; int ImageWidth; int ImageHeight; int AASamples; @@ -146,6 +147,7 @@ struct lcCommandLineOptions QString SaveWavefrontName; QString Save3DSName; QString SaveCOLLADAName; + QString SaveCSVName; QString SaveHTMLName; QList> LibraryPaths; QString StdOut; diff --git a/common/lc_instructions.cpp b/common/lc_instructions.cpp index d3cd9b59..dacd33d2 100644 --- a/common/lc_instructions.cpp +++ b/common/lc_instructions.cpp @@ -250,4 +250,7 @@ void lcInstructions::AddDefaultPages(lcModel* Model, std::vector } } } + + if (!Page.Steps.empty()) + mPages.emplace_back(std::move(Page)); } diff --git a/common/lc_mainwindow.cpp b/common/lc_mainwindow.cpp index d34e1272..622da8f2 100644 --- a/common/lc_mainwindow.cpp +++ b/common/lc_mainwindow.cpp @@ -2590,7 +2590,7 @@ void lcMainWindow::HandleCommand(lcCommandId CommandId) break; case LC_FILE_EXPORT_CSV: - lcGetActiveProject()->ExportCSV(); + lcGetActiveProject()->ExportCSV(QString()); break; case LC_FILE_EXPORT_POVRAY: diff --git a/common/project.cpp b/common/project.cpp index 8a4cdcaf..eff545df 100644 --- a/common/project.cpp +++ b/common/project.cpp @@ -1428,7 +1428,7 @@ bool Project::ExportCOLLADA(const QString& FileName) return true; } -void Project::ExportCSV() +bool Project::ExportCSV(const QString& FileName) { lcPartsList PartsList; @@ -1438,13 +1438,13 @@ void Project::ExportCSV() if (PartsList.empty()) { QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("Nothing to export.")); - return; + return false; } - QString SaveFileName = GetExportFileName(QString(), "csv", tr("Export CSV"), tr("CSV Files (*.csv);;All Files (*.*)")); + QString SaveFileName = GetExportFileName(FileName, "csv", tr("Export CSV"), tr("CSV Files (*.csv);;All Files (*.*)")); if (SaveFileName.isEmpty()) - return; + return false; lcDiskFile CSVFile(SaveFileName); char Line[1024]; @@ -1452,7 +1452,7 @@ void Project::ExportCSV() if (!CSVFile.Open(QIODevice::WriteOnly)) { QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Could not open file '%1' for writing.").arg(SaveFileName)); - return; + return false; } CSVFile.WriteLine("Part Name,Color,Quantity,Part ID,Color Code\n"); @@ -1463,10 +1463,15 @@ void Project::ExportCSV() for (const auto& ColorIt : PartIt.second) { - sprintf(Line, "\"%s\",\"%s\",%d,%s,%d\n", Info->m_strDescription, gColorList[ColorIt.first].Name, ColorIt.second, Info->mFileName, gColorList[ColorIt.first].Code); + std::string Description = Info->m_strDescription; + Description.erase(std::remove(Description.begin(), Description.end(), ','), Description.end()); + + sprintf(Line, "\"%s\",\"%s\",%d,%s,%d\n", Description.c_str(), gColorList[ColorIt.first].Name, ColorIt.second, Info->mFileName, gColorList[ColorIt.first].Code); CSVFile.WriteLine(Line); } } + + return true; } lcInstructions* Project::GetInstructions() diff --git a/common/project.h b/common/project.h index 3f8eed24..e40efdcf 100644 --- a/common/project.h +++ b/common/project.h @@ -93,7 +93,7 @@ public: bool Export3DStudio(const QString& FileName); void ExportBrickLink(); bool ExportCOLLADA(const QString& FileName); - void ExportCSV(); + bool ExportCSV(const QString& FileName); void ExportHTML(const lcHTMLExportOptions& Options); bool ExportPOVRay(const QString& FileName); bool ExportWavefront(const QString& FileName); diff --git a/qt/lc_qutils.cpp b/qt/lc_qutils.cpp index c08f21e2..a8522960 100644 --- a/qt/lc_qutils.cpp +++ b/qt/lc_qutils.cpp @@ -47,40 +47,56 @@ float lcParseValueLocalized(const QString& Value) // Resize all columns to content except for one stretching column. (taken from QT creator) lcQTreeWidgetColumnStretcher::lcQTreeWidgetColumnStretcher(QTreeWidget *treeWidget, int columnToStretch) - : QObject(treeWidget->header()), m_columnToStretch(columnToStretch) + : QObject(treeWidget->header()), m_columnToStretch(columnToStretch), m_interactiveResize(false), m_stretchWidth(0) { parent()->installEventFilter(this); + connect(treeWidget->header(), SIGNAL(sectionResized(int, int, int)), SLOT(sectionResized(int, int, int))); QHideEvent fake; lcQTreeWidgetColumnStretcher::eventFilter(parent(), &fake); } +void lcQTreeWidgetColumnStretcher::sectionResized(int LogicalIndex, int OldSize, int NewSize) +{ + Q_UNUSED(OldSize) + + if (LogicalIndex == m_columnToStretch) + { + QHeaderView* HeaderView = qobject_cast(parent()); + + if (HeaderView->isVisible()) + m_interactiveResize = true; + + m_stretchWidth = NewSize; + } +} + bool lcQTreeWidgetColumnStretcher::eventFilter(QObject* Object, QEvent* Event) { if (Object == parent()) { + QHeaderView* HeaderView = qobject_cast(Object); + if (Event->type() == QEvent::Show) { - QHeaderView* HeaderView = qobject_cast(Object); - for (int i = 0; i < HeaderView->count(); ++i) HeaderView->setSectionResizeMode(i, QHeaderView::Interactive); + + m_stretchWidth = HeaderView->sectionSize(m_columnToStretch); + } else if (Event->type() == QEvent::Hide) { - QHeaderView* HeaderView = qobject_cast(Object); - - for (int i = 0; i < HeaderView->count(); ++i) - HeaderView->setSectionResizeMode(i, i == m_columnToStretch ? QHeaderView::Stretch : QHeaderView::ResizeToContents); + if (!m_interactiveResize) + for (int i = 0; i < HeaderView->count(); ++i) + HeaderView->setSectionResizeMode(i, i == m_columnToStretch ? QHeaderView::Stretch : QHeaderView::ResizeToContents); } else if (Event->type() == QEvent::Resize) { - QHeaderView* HeaderView = qobject_cast(Object); + if (HeaderView->sectionResizeMode(m_columnToStretch) == QHeaderView::Interactive) { - if (HeaderView->sectionResizeMode(m_columnToStretch) == QHeaderView::Interactive) - { - const QResizeEvent* ResizeEvent = reinterpret_cast(Event); - const int Diff = ResizeEvent->size().width() - ResizeEvent->oldSize().width() ; - HeaderView->resizeSection(m_columnToStretch, qMax(32, HeaderView->sectionSize(1) + Diff)); + const int StretchWidth = HeaderView->isVisible() ? m_stretchWidth : 32; + + HeaderView->resizeSection(m_columnToStretch, StretchWidth); } } } diff --git a/qt/lc_qutils.h b/qt/lc_qutils.h index 1b229160..5a6591ee 100644 --- a/qt/lc_qutils.h +++ b/qt/lc_qutils.h @@ -15,7 +15,13 @@ public: bool eventFilter(QObject* Object, QEvent* Event) override; +private slots: + void sectionResized(int LogicalIndex, int OldSize, int NewSize); + +private: const int m_columnToStretch; + bool m_interactiveResize; + int m_stretchWidth; }; class lcSmallLineEdit : public QLineEdit