From 57bc2970058207bf8b61b6d722d6de30d4463ef1 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Wed, 6 Mar 2024 22:47:31 -0600 Subject: [PATCH] Start: Recreate start as a QtWidgets-based app Removes all Start network access and dependency on Chromium for rendering. Written entirely in C++ (no HTML, CSS, JS, etc.). --- .gitmodules | 3 + cMake/FreeCAD_Helpers/PrintFinalReport.cmake | 32 +- src/3rdParty/GSL | 1 + src/Gui/Icons/resource.qrc | 1 + src/Mod/Assembly/Gui/Resources/Assembly.qrc | 1 + src/Mod/CMakeLists.txt | 4 + src/Mod/CleanStart/App/AppCleanStart.cpp | 60 ++++ src/Mod/CleanStart/App/CMakeLists.txt | 50 +++ .../CleanStart/App/DisplayedFilesModel.cpp | 221 +++++++++++++ src/Mod/CleanStart/App/DisplayedFilesModel.h | 85 +++++ src/Mod/CleanStart/App/ExamplesModel.cpp | 54 ++++ src/Mod/CleanStart/App/ExamplesModel.h | 53 ++++ src/Mod/CleanStart/App/PreCompiled.cpp | 25 ++ src/Mod/CleanStart/App/PreCompiled.h | 51 +++ src/Mod/CleanStart/App/RecentFilesModel.cpp | 51 +++ src/Mod/CleanStart/App/RecentFilesModel.h | 52 +++ src/Mod/CleanStart/CMakeLists.txt | 49 +++ src/Mod/CleanStart/CleanStartGlobal.h | 48 +++ src/Mod/CleanStart/Gui/AppCleanStartGui.cpp | 81 +++++ src/Mod/CleanStart/Gui/CMakeLists.txt | 89 ++++++ src/Mod/CleanStart/Gui/CleanStartView.cpp | 298 ++++++++++++++++++ src/Mod/CleanStart/Gui/CleanStartView.h | 96 ++++++ src/Mod/CleanStart/Gui/Command.cpp | 62 ++++ src/Mod/CleanStart/Gui/FileCardDelegate.cpp | 148 +++++++++ src/Mod/CleanStart/Gui/FileCardDelegate.h | 52 +++ src/Mod/CleanStart/Gui/FileCardView.cpp | 84 +++++ src/Mod/CleanStart/Gui/FileCardView.h | 47 +++ src/Mod/CleanStart/Gui/PreCompiled.cpp | 25 ++ src/Mod/CleanStart/Gui/PreCompiled.h | 65 ++++ .../CleanStart/Gui/Resources/CleanStart.qrc | 5 + .../Resources/icons/CleanStartWorkbench.svg | 35 ++ src/Mod/CleanStart/Gui/Workbench.cpp | 87 +++++ src/Mod/CleanStart/Gui/Workbench.h | 63 ++++ src/Mod/CleanStart/Init.py | 29 ++ src/Mod/CleanStart/InitGui.py | 51 +++ src/Mod/CleanStart/README.md | 53 ++++ 36 files changed, 2209 insertions(+), 2 deletions(-) create mode 160000 src/3rdParty/GSL create mode 100644 src/Mod/CleanStart/App/AppCleanStart.cpp create mode 100644 src/Mod/CleanStart/App/CMakeLists.txt create mode 100644 src/Mod/CleanStart/App/DisplayedFilesModel.cpp create mode 100644 src/Mod/CleanStart/App/DisplayedFilesModel.h create mode 100644 src/Mod/CleanStart/App/ExamplesModel.cpp create mode 100644 src/Mod/CleanStart/App/ExamplesModel.h create mode 100644 src/Mod/CleanStart/App/PreCompiled.cpp create mode 100644 src/Mod/CleanStart/App/PreCompiled.h create mode 100644 src/Mod/CleanStart/App/RecentFilesModel.cpp create mode 100644 src/Mod/CleanStart/App/RecentFilesModel.h create mode 100644 src/Mod/CleanStart/CMakeLists.txt create mode 100644 src/Mod/CleanStart/CleanStartGlobal.h create mode 100644 src/Mod/CleanStart/Gui/AppCleanStartGui.cpp create mode 100644 src/Mod/CleanStart/Gui/CMakeLists.txt create mode 100644 src/Mod/CleanStart/Gui/CleanStartView.cpp create mode 100644 src/Mod/CleanStart/Gui/CleanStartView.h create mode 100644 src/Mod/CleanStart/Gui/Command.cpp create mode 100644 src/Mod/CleanStart/Gui/FileCardDelegate.cpp create mode 100644 src/Mod/CleanStart/Gui/FileCardDelegate.h create mode 100644 src/Mod/CleanStart/Gui/FileCardView.cpp create mode 100644 src/Mod/CleanStart/Gui/FileCardView.h create mode 100644 src/Mod/CleanStart/Gui/PreCompiled.cpp create mode 100644 src/Mod/CleanStart/Gui/PreCompiled.h create mode 100644 src/Mod/CleanStart/Gui/Resources/CleanStart.qrc create mode 100644 src/Mod/CleanStart/Gui/Resources/icons/CleanStartWorkbench.svg create mode 100644 src/Mod/CleanStart/Gui/Workbench.cpp create mode 100644 src/Mod/CleanStart/Gui/Workbench.h create mode 100644 src/Mod/CleanStart/Init.py create mode 100644 src/Mod/CleanStart/InitGui.py create mode 100644 src/Mod/CleanStart/README.md diff --git a/.gitmodules b/.gitmodules index 42c9b757f4..b6bc63efd4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "tests/lib"] path = tests/lib url = https://github.com/google/googletest +[submodule "src/3rdParty/GSL"] + path = src/3rdParty/GSL + url = https://github.com/microsoft/GSL diff --git a/cMake/FreeCAD_Helpers/PrintFinalReport.cmake b/cMake/FreeCAD_Helpers/PrintFinalReport.cmake index 70cb84edef..adb4c97a13 100644 --- a/cMake/FreeCAD_Helpers/PrintFinalReport.cmake +++ b/cMake/FreeCAD_Helpers/PrintFinalReport.cmake @@ -88,11 +88,39 @@ macro(PrintFinalReport) value(FREECAD_CREATE_MAC_APP) value(FREECAD_USE_PYBIND11) value(FREECAD_USE_EXTERNAL_KDL) + value(BUILD_ADDONMGR) + value(BUILD_ARCH) + value(BUILD_ASSEMBLY) + value(BUILD_CLOUD) + value(BUILD_DRAFT) + value(BUILD_DRAWING) value(BUILD_FEM) - value(BUILD_WEB) - value(BUILD_GUI) + value(BUILD_HELP) + value(BUILD_IDF) + value(BUILD_IMPORT) + value(BUILD_INSPECTION) + value(BUILD_JTREADER) + value(BUILD_MATERIAL) + value(BUILD_MESH) + value(BUILD_MESH_PART) + value(BUILD_OPENSCAD) + value(BUILD_PART) + value(BUILD_PART_DESIGN) + value(BUILD_PATH) + value(BUILD_PLOT) + value(BUILD_POINTS) + value(BUILD_REVERSEENGINEERING) + value(BUILD_ROBOT) + value(BUILD_SANDBOX) + value(BUILD_SHOW) + value(BUILD_SKETCHER) + value(BUILD_SPREADSHEET) value(BUILD_START) + value(BUILD_SURFACE) value(BUILD_TECHDRAW) + value(BUILD_TEST) + value(BUILD_TUX) + value(BUILD_WEB) value(CMAKE_INSTALL_PREFIX) value(USE_CUDA) value(USE_OPENCV) diff --git a/src/3rdParty/GSL b/src/3rdParty/GSL new file mode 160000 index 0000000000..b39e7e4b09 --- /dev/null +++ b/src/3rdParty/GSL @@ -0,0 +1 @@ +Subproject commit b39e7e4b0987859f5b19ff7686b149c916588658 diff --git a/src/Gui/Icons/resource.qrc b/src/Gui/Icons/resource.qrc index 95fc934f8e..a5bf4c9b2c 100644 --- a/src/Gui/Icons/resource.qrc +++ b/src/Gui/Icons/resource.qrc @@ -12,6 +12,7 @@ list-add.svg freecad.svg freecad-doc.png + freecad-doc.svg bulb.svg TextDocument.svg button_down.svg diff --git a/src/Mod/Assembly/Gui/Resources/Assembly.qrc b/src/Mod/Assembly/Gui/Resources/Assembly.qrc index ad258eecf3..82325ce87a 100644 --- a/src/Mod/Assembly/Gui/Resources/Assembly.qrc +++ b/src/Mod/Assembly/Gui/Resources/Assembly.qrc @@ -16,5 +16,6 @@ panels/TaskAssemblyInsertLink.ui preferences/Assembly.ui icons/Assembly_CreateJointDistance.svg + icons/AssemblyWorkbench.svg diff --git a/src/Mod/CMakeLists.txt b/src/Mod/CMakeLists.txt index 896402098f..7873061e5c 100644 --- a/src/Mod/CMakeLists.txt +++ b/src/Mod/CMakeLists.txt @@ -10,6 +10,10 @@ if(BUILD_ASSEMBLY) add_subdirectory(Assembly) endif(BUILD_ASSEMBLY) +if(BUILD_CLEANSTART) + add_subdirectory(CleanStart) +endif(BUILD_CLEANSTART) + if(BUILD_CLOUD) add_subdirectory(Cloud) endif(BUILD_CLOUD) diff --git a/src/Mod/CleanStart/App/AppCleanStart.cpp b/src/Mod/CleanStart/App/AppCleanStart.cpp new file mode 100644 index 0000000000..f0d300cc67 --- /dev/null +++ b/src/Mod/CleanStart/App/AppCleanStart.cpp @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * +# Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#include +#include +#include + +#include + +#include <3rdParty/GSL/include/gsl/pointers> + +namespace CleanStart +{ +class Module: public Py::ExtensionModule +{ +public: + Module() + : Py::ExtensionModule("CleanStart") + { + initialize("This module is the CleanStart module."); // register with Python + } +}; + +PyObject* initModule() +{ + auto newModule = gsl::owner(new Module); + return Base::Interpreter().addModule(newModule); // Transfer ownership +} + +} // namespace CleanStart + +/* Python entry */ +PyMOD_INIT_FUNC(CleanStart) +{ + PyObject* mod = CleanStart::initModule(); + Base::Console().Log("Loading CleanStart module... done\n"); + PyMOD_Return(mod); +} diff --git a/src/Mod/CleanStart/App/CMakeLists.txt b/src/Mod/CleanStart/App/CMakeLists.txt new file mode 100644 index 0000000000..40dd253fb8 --- /dev/null +++ b/src/Mod/CleanStart/App/CMakeLists.txt @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# /**************************************************************************** +# * * +# * Copyright (c) 2024 The FreeCAD Project Association AISBL * +# * * +# * This file is part of FreeCAD. * +# * * +# * FreeCAD is free software: you can redistribute it and/or modify it * +# * under the terms of the GNU Lesser General Public License as * +# * published by the Free Software Foundation, either version 2.1 of the * +# * License, or (at your option) any later version. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, but * +# * WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +# * Lesser General Public License for more details. * +# * * +# * You should have received a copy of the GNU Lesser General Public * +# * License along with FreeCAD. If not, see * +# * . * +# * * +# ***************************************************************************/ + +include_directories( + ${PYTHON_INCLUDE_DIRS} + ${QtCore_INCLUDE_DIRS} +) + +set(CleanStart_LIBS + FreeCADApp + ) + +SET(CleanStart_SRCS + AppCleanStart.cpp + DisplayedFilesModel.cpp + DisplayedFilesModel.h + ExamplesModel.cpp + ExamplesModel.h + PreCompiled.cpp + PreCompiled.h + RecentFilesModel.cpp + RecentFilesModel.h) + +add_library(CleanStart SHARED ${CleanStart_SRCS}) +target_link_libraries(CleanStart ${CleanStart_LIBS}) + +SET_BIN_DIR(CleanStart CleanStart /Mod/CleanStart) +SET_PYTHON_PREFIX_SUFFIX(CleanStart) + +INSTALL(TARGETS CleanStart DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/Mod/CleanStart/App/DisplayedFilesModel.cpp b/src/Mod/CleanStart/App/DisplayedFilesModel.cpp new file mode 100644 index 0000000000..1a91db8819 --- /dev/null +++ b/src/Mod/CleanStart/App/DisplayedFilesModel.cpp @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#include +#endif + +#include "DisplayedFilesModel.h" +#include +#include + +using namespace CleanStart; + + +namespace +{ + +std::string humanReadableSize(unsigned int bytes) +{ + static const std::vector siPrefix { + "b", + "kb", + "Mb", + "Gb", + "Tb", + "Pb", + "Eb" // I think it's safe to stop here (for the time being)... + }; + size_t base = 0; + double inUnits = bytes; + constexpr double siFactor {1000.0}; + while (inUnits > siFactor && base < siPrefix.size() - 1) { + ++base; + inUnits /= siFactor; + } + if (base == 0) { + // Don't include a decimal point for bytes + return fmt::format("{:.0f} {}", inUnits, siPrefix[base]); + } + // For all others, include one digit after the decimal place + return fmt::format("{:.1f} {}", inUnits, siPrefix[base]); +} + +FileStats fileInfoFromFreeCADFile(const std::string& path) +{ + App::ProjectFile proj(path); + proj.loadDocument(); + auto metadata = proj.getMetadata(); + FileStats result; + result.insert(std::make_pair(DisplayedFilesModelRoles::author, metadata.createdBy)); + result.insert(std::make_pair(DisplayedFilesModelRoles::modifiedTime, metadata.lastModifiedDate)); + result.insert(std::make_pair(DisplayedFilesModelRoles::creationTime, metadata.creationDate)); + result.insert(std::make_pair(DisplayedFilesModelRoles::company, metadata.company)); + result.insert(std::make_pair(DisplayedFilesModelRoles::license, metadata.license)); + result.insert(std::make_pair(DisplayedFilesModelRoles::description, metadata.comment)); + return result; +} + +/// Load the thumbnail image data (if any) that is stored in an FCStd file. +/// \returns The image bytes, or an empty QByteArray (if no thumbnail was stored) +QByteArray loadFCStdThumbnail(const std::string & pathToFCStdFile) +{ + App::ProjectFile proj(pathToFCStdFile); + if (proj.loadDocument()) { + try { + std::string thumbnailFile = proj.extractInputFile("thumbnails/Thumbnail.png"); + auto inputFile = QFile(QString::fromStdString(thumbnailFile)); + inputFile.open(QIODevice::OpenModeFlag::ReadOnly); + return inputFile.readAll(); + } + catch (...) { + } + } + return {}; +} + +FileStats getFileInfo(const std::string& path) +{ + FileStats result; + Base::FileInfo file(path); + if (file.hasExtension("FCStd")) { + result = fileInfoFromFreeCADFile(path); + } + else { + file.lastModified(); + } + result.insert(std::make_pair(DisplayedFilesModelRoles::path, path)); + result.insert(std::make_pair(DisplayedFilesModelRoles::size, humanReadableSize(file.size()))); + result.insert(std::make_pair(DisplayedFilesModelRoles::baseName, file.fileName())); + return result; +} +} // namespace + +DisplayedFilesModel::DisplayedFilesModel(QObject* parent) : QAbstractListModel(parent) +{ +} + + +int DisplayedFilesModel::rowCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return static_cast(_fileInfoCache.size()); +} + +QVariant DisplayedFilesModel::data(const QModelIndex& index, int roleAsInt) const +{ + int row = index.row(); + if (row < 0 || row >= static_cast(_fileInfoCache.size())) { + return {}; + } + auto mapEntry = _fileInfoCache.at(row); + auto role = static_cast(roleAsInt); + switch (role) { + case DisplayedFilesModelRoles::author: // NOLINT(bugprone-branch-clone) + [[fallthrough]]; + case DisplayedFilesModelRoles::baseName: + [[fallthrough]]; + case DisplayedFilesModelRoles::company: + [[fallthrough]]; + case DisplayedFilesModelRoles::creationTime: + [[fallthrough]]; + case DisplayedFilesModelRoles::description: + [[fallthrough]]; + case DisplayedFilesModelRoles::license: + [[fallthrough]]; + case DisplayedFilesModelRoles::modifiedTime: + [[fallthrough]]; + case DisplayedFilesModelRoles::path: + [[fallthrough]]; + case DisplayedFilesModelRoles::size: + if (mapEntry.find(role) != mapEntry.end()) { + return QString::fromStdString(mapEntry.at(role)); + } + else { + return {}; + } + case DisplayedFilesModelRoles::image: { + auto path = QString::fromStdString(mapEntry.at(DisplayedFilesModelRoles::path)); + if (_imageCache.contains(path)) { + return _imageCache[path]; + } + break; + } + default: + break; + } + switch (roleAsInt) { + case Qt::ItemDataRole::ToolTipRole: + return QString::fromStdString(mapEntry.at(DisplayedFilesModelRoles::path)); + } + return {}; +} + +bool freecadCanOpen (const QString& extension) +{ + auto importTypes = App::GetApplication().getImportTypes(); + return std::find(importTypes.begin(), importTypes.end(), extension.toStdString()) != importTypes.end(); +} + +void DisplayedFilesModel::addFile(const QString &filePath) +{ + QFileInfo qfi (filePath); + if (!qfi.isReadable()){ + return; + } + if (!freecadCanOpen(qfi.suffix())) { + return; + } + _fileInfoCache.emplace_back(getFileInfo(filePath.toStdString())); + if (qfi.completeSuffix() == QLatin1String("FCStd")) { + auto thumbnail = loadFCStdThumbnail(filePath.toStdString()); + if (!thumbnail.isEmpty()) { + _imageCache.insert(filePath, thumbnail); + } + } +} + +void DisplayedFilesModel::clear() +{ + _fileInfoCache.clear(); +} + +QHash DisplayedFilesModel::roleNames() const +{ + static QHash nameMap { + std::make_pair(int(DisplayedFilesModelRoles::author), "author"), + std::make_pair(int(DisplayedFilesModelRoles::baseName), "baseName"), + std::make_pair(int(DisplayedFilesModelRoles::company), "company"), + std::make_pair(int(DisplayedFilesModelRoles::creationTime), "creationTime"), + std::make_pair(int(DisplayedFilesModelRoles::description), "description"), + std::make_pair(int(DisplayedFilesModelRoles::image), "image"), + std::make_pair(int(DisplayedFilesModelRoles::license), "license"), + std::make_pair(int(DisplayedFilesModelRoles::modifiedTime), "modifiedTime"), + std::make_pair(int(DisplayedFilesModelRoles::path), "path"), + std::make_pair(int(DisplayedFilesModelRoles::size), "size"), + }; + return nameMap; +} diff --git a/src/Mod/CleanStart/App/DisplayedFilesModel.h b/src/Mod/CleanStart/App/DisplayedFilesModel.h new file mode 100644 index 0000000000..e08937d060 --- /dev/null +++ b/src/Mod/CleanStart/App/DisplayedFilesModel.h @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef FREECAD_CLEANSTART_DISPLAYEDFILESMODEL_H +#define FREECAD_CLEANSTART_DISPLAYEDFILESMODEL_H + +#include +#include +#include + +#include "../CleanStartGlobal.h" + +namespace CleanStart +{ + +enum class DisplayedFilesModelRoles +{ + baseName = Qt::UserRole + 1, + image, + size, + author, + creationTime, + modifiedTime, + description, + company, + license, + path +}; + +using FileStats = std::map; + +/// A model for displaying a list of files including a thumbnail or icon, plus various file statistics. +class CleanStartExport DisplayedFilesModel: public QAbstractListModel +{ + Q_OBJECT +public: + explicit DisplayedFilesModel(QObject* parent = nullptr); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + + void addFile(const QString &filePath); + + void clear(); + +protected: + /// For communication with QML, define the text version of each role name defined in the + /// DisplayedFilesModelRoles enumeration + QHash roleNames() const override; + + /// Destroy and recreate the cache of info about the files. Should be connected to a signal + /// indicating when some piece of information about the files has changed. Does NOT generate + /// a new list of files, only re-caches the existing ones. + void reCacheFileInfo(); + +private: + + std::vector _fileInfoCache; + QMap _imageCache; +}; + +} // namespace CleanStart + +#endif // FREECAD_CLEANSTART_DISPLAYEDFILESMODEL_H diff --git a/src/Mod/CleanStart/App/ExamplesModel.cpp b/src/Mod/CleanStart/App/ExamplesModel.cpp new file mode 100644 index 0000000000..7b9733158b --- /dev/null +++ b/src/Mod/CleanStart/App/ExamplesModel.cpp @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#endif + +#include "ExamplesModel.h" +#include + +using namespace CleanStart; + +FC_LOG_LEVEL_INIT(ExamplesModel) + +ExamplesModel::ExamplesModel(QObject* parent) : DisplayedFilesModel(parent) +{ + auto examplesPath = QDir(QString::fromStdString(App::Application::getResourceDir())); + _examplesDirectory.setPath (examplesPath.filePath(QLatin1String("examples"))); +} + +void ExamplesModel::loadExamples() +{ + beginResetModel(); + clear(); + if (!_examplesDirectory.isReadable()) { + Base::Console().Warning("Cannot read %s", _examplesDirectory.absolutePath().toStdString().c_str()); + } + auto entries = _examplesDirectory.entryList(QDir::Filter::Files | QDir::Filter::Readable, QDir::SortFlag::Name); + for (const auto & entry : entries) { + addFile(_examplesDirectory.filePath(entry)); + } + endResetModel(); +} diff --git a/src/Mod/CleanStart/App/ExamplesModel.h b/src/Mod/CleanStart/App/ExamplesModel.h new file mode 100644 index 0000000000..fe232b737a --- /dev/null +++ b/src/Mod/CleanStart/App/ExamplesModel.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef FREECAD_CLEANSTART_EXAMPLESMODEL_H +#define FREECAD_CLEANSTART_EXAMPLESMODEL_H + +#include +#include +#include +#include + +#include "DisplayedFilesModel.h" +#include "../CleanStartGlobal.h" + +namespace CleanStart +{ + +/// A model for displaying a list of files including a thumbnail or icon, plus various file statistics. +class CleanStartExport ExamplesModel: public DisplayedFilesModel +{ + Q_OBJECT +public: + explicit ExamplesModel(QObject* parent = nullptr); + + void loadExamples(); + +private: + QDir _examplesDirectory; +}; + +} // namespace CleanStart + +#endif // FREECAD_CLEANSTART_EXAMPLESMODEL_H diff --git a/src/Mod/CleanStart/App/PreCompiled.cpp b/src/Mod/CleanStart/App/PreCompiled.cpp new file mode 100644 index 0000000000..b17d7731bd --- /dev/null +++ b/src/Mod/CleanStart/App/PreCompiled.cpp @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * +# Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" diff --git a/src/Mod/CleanStart/App/PreCompiled.h b/src/Mod/CleanStart/App/PreCompiled.h new file mode 100644 index 0000000000..711517255f --- /dev/null +++ b/src/Mod/CleanStart/App/PreCompiled.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * +# Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef CLEANSTART_PRECOMPILED_H +#define CLEANSTART_PRECOMPILED_H + +#include + +#ifdef _MSC_VER +#pragma warning(disable : 5208) +#endif + +#ifdef _PreComp_ + +// standard +#include +#include +#include +#include +#include +#include +#include +#include + +// Qt (should never include GUI files, only QtCore) +#include +#include +#include + +#endif // _PreComp_ +#endif // CLEANSTART_PRECOMPILED_H diff --git a/src/Mod/CleanStart/App/RecentFilesModel.cpp b/src/Mod/CleanStart/App/RecentFilesModel.cpp new file mode 100644 index 0000000000..238007a368 --- /dev/null +++ b/src/Mod/CleanStart/App/RecentFilesModel.cpp @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#endif + +#include "RecentFilesModel.h" +#include +#include + +using namespace CleanStart; + +RecentFilesModel::RecentFilesModel(QObject* parent) : DisplayedFilesModel(parent) +{ + _parameterGroup = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/RecentFiles"); +} + +void RecentFilesModel::loadRecentFiles() +{ + beginResetModel(); + clear(); + auto numRows {_parameterGroup->GetInt("RecentFiles", 0)}; + for (int i = 0; i < numRows; ++i) { + auto entry = fmt::format("MRU{}", i); + auto path = _parameterGroup->GetASCII(entry.c_str(), ""); + addFile(QString::fromStdString(path)); + } + endResetModel(); +} diff --git a/src/Mod/CleanStart/App/RecentFilesModel.h b/src/Mod/CleanStart/App/RecentFilesModel.h new file mode 100644 index 0000000000..077c53c54b --- /dev/null +++ b/src/Mod/CleanStart/App/RecentFilesModel.h @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef FREECAD_CLEANSTART_RECENTFILESMODEL_H +#define FREECAD_CLEANSTART_RECENTFILESMODEL_H + +#include +#include +#include + +#include "DisplayedFilesModel.h" +#include "../CleanStartGlobal.h" + +namespace CleanStart +{ + +/// A model for displaying a list of files including a thumbnail or icon, plus various file statistics. +class CleanStartExport RecentFilesModel: public DisplayedFilesModel +{ + Q_OBJECT +public: + explicit RecentFilesModel(QObject* parent = nullptr); + + void loadRecentFiles(); + +private: + Base::Reference _parameterGroup; +}; + +} // namespace CleanStart + +#endif // FREECAD_CLEANSTART_RECENTFILESMODEL_H diff --git a/src/Mod/CleanStart/CMakeLists.txt b/src/Mod/CleanStart/CMakeLists.txt new file mode 100644 index 0000000000..7f6a38c845 --- /dev/null +++ b/src/Mod/CleanStart/CMakeLists.txt @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# /**************************************************************************** +# * * +# * Copyright (c) 2024 The FreeCAD Project Association AISBL * +# * * +# * This file is part of FreeCAD. * +# * * +# * FreeCAD is free software: you can redistribute it and/or modify it * +# * under the terms of the GNU Lesser General Public License as * +# * published by the Free Software Foundation, either version 2.1 of the * +# * License, or (at your option) any later version. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, but * +# * WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +# * Lesser General Public License for more details. * +# * * +# * You should have received a copy of the GNU Lesser General Public * +# * License along with FreeCAD. If not, see * +# * . * +# * * +# ***************************************************************************/ + +add_subdirectory(App) + +set(CleanStart_Scripts + Init.py + ) + +if (BUILD_GUI) + add_subdirectory(Gui) + list(APPEND CleanStart_Scripts InitGui.py) +endif (BUILD_GUI) + +add_custom_target(CleanStartScripts ALL + SOURCES ${CleanStart_Scripts} + ) + +fc_target_copy_resource(CleanStartScripts + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_BINARY_DIR}/Mod/CleanStart + ${CleanStart_Scripts}) + +INSTALL( + FILES + ${CleanStart_Scripts} + DESTINATION + Mod/CleanStart +) diff --git a/src/Mod/CleanStart/CleanStartGlobal.h b/src/Mod/CleanStart/CleanStartGlobal.h new file mode 100644 index 0000000000..c4d367d858 --- /dev/null +++ b/src/Mod/CleanStart/CleanStartGlobal.h @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include + +#ifndef LAUNCHER_GLOBAL_H +#define LAUNCHER_GLOBAL_H + + +// CleanStart +#ifndef CleanStartExport +#ifdef CleanStart_EXPORTS +#define CleanStartExport FREECAD_DECL_EXPORT +#else +#define CleanStartExport FREECAD_DECL_IMPORT +#endif +#endif + +// CleanStartGui +#ifndef CleanStartGuiExport +#ifdef CleanStartGui_EXPORTS +#define CleanStartGuiExport FREECAD_DECL_EXPORT +#else +#define CleanStartGuiExport FREECAD_DECL_IMPORT +#endif +#endif + +#endif // LAUNCHER_GLOBAL_H diff --git a/src/Mod/CleanStart/Gui/AppCleanStartGui.cpp b/src/Mod/CleanStart/Gui/AppCleanStartGui.cpp new file mode 100644 index 0000000000..47dbb42dd3 --- /dev/null +++ b/src/Mod/CleanStart/Gui/AppCleanStartGui.cpp @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#include +#include +#include +#include + +#include + +#include <3rdParty/GSL/include/gsl/pointers> + +#include "Workbench.h" + +void loadCleanStartResource() +{ + // add resources and reloads the translators + Q_INIT_RESOURCE(CleanStart); + Q_INIT_RESOURCE(CleanStart_translation); + Gui::Translator::instance()->refresh(); +} + +namespace CleanStartGui +{ + extern PyObject* initModule(); +} + + +namespace CleanStartGui +{ +class Module: public Py::ExtensionModule +{ +public: + Module() + : Py::ExtensionModule("CleanStartGui") + { + initialize("This module is the CleanStartGui module."); // register with Python + } +}; + +PyObject* initModule() +{ + auto newModule = gsl::owner(new Module); + return Base::Interpreter().addModule(newModule); // Transfer ownership +} + +} // namespace CleanStartGui + +/* Python entry */ +PyMOD_INIT_FUNC(CleanStartGui) +{ + Base::Console().Log("Loading GUI of CleanStart module... "); + PyObject* mod = CleanStartGui::initModule(); + CleanStartGui::Workbench::init(); + loadCleanStartResource(); + Base::Console().Log("done\n"); + + PyMOD_Return(mod); +} diff --git a/src/Mod/CleanStart/Gui/CMakeLists.txt b/src/Mod/CleanStart/Gui/CMakeLists.txt new file mode 100644 index 0000000000..01a7b02b4f --- /dev/null +++ b/src/Mod/CleanStart/Gui/CMakeLists.txt @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# /**************************************************************************** +# * * +# * Copyright (c) 2024 The FreeCAD Project Association AISBL * +# * * +# * This file is part of FreeCAD. * +# * * +# * FreeCAD is free software: you can redistribute it and/or modify it * +# * under the terms of the GNU Lesser General Public License as * +# * published by the Free Software Foundation, either version 2.1 of the * +# * License, or (at your option) any later version. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, but * +# * WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +# * Lesser General Public License for more details. * +# * * +# * You should have received a copy of the GNU Lesser General Public * +# * License along with FreeCAD. If not, see * +# * . * +# * * +# ***************************************************************************/ + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${PYTHON_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${ZLIB_INCLUDE_DIR} + ${XercesC_INCLUDE_DIRS} + ${QtCore_INCLUDE_DIRS} + ${QtWidgets_INCLUDE_DIRS} + ${QtSvg_INCLUDE_DIRS} + #${QtNetwork_INCLUDE_DIRS} + ${QtUiTools_INCLUDE_DIRS} + #${QtQuick_INCLUDE_DIRS} + #${QtQuickWidgets_INCLUDE_DIRS} +) + +set(CleanStartGui_LIBS + CleanStart + FreeCADGui + ) + +set(CleanStart_TR_QRC ${CMAKE_CURRENT_BINARY_DIR}/Resources/CleanStart_translation.qrc) +qt_find_and_add_translation(QM_SRCS "Resources/translations/*_*.ts" + ${CMAKE_CURRENT_BINARY_DIR}/Resources/translations) +qt_create_resource_file(${CleanStart_TR_QRC} ${QM_SRCS}) +qt_add_resources(CleanStart_QRC_SRCS Resources/CleanStart.qrc ${CleanStart_TR_QRC}) +# qtquick_compiler_add_resources(CleanStart_QRC_SRCS Resources/CleanStart.qrc ${CleanStart_TR_QRC} qml.qrc) + +SET(CleanStartGui_SRCS + ${CleanStart_QRC_SRCS} + ${CleanStartGui_UIC_SRCS} + AppCleanStartGui.cpp + Command.cpp + PreCompiled.cpp + PreCompiled.h + CleanStartView.cpp + CleanStartView.h + FileCardDelegate.cpp + FileCardDelegate.h + FileCardView.cpp + FileCardView.h + Workbench.cpp + Workbench.h + ) + +SET(CleanStartGuiIcon_SVG + Resources/icons/CleanStartWorkbench.svg + ) + +# TODO: Evaluate PCH use with Qt6/QtQuick/Qml +if (FREECAD_USE_PCH) + add_definitions(-D_PreComp_) + GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" PCH_SRCS ${CleanStartGui_SRCS}) + ADD_MSVC_PRECOMPILED_HEADER(CleanStartGui PreCompiled.h PreCompiled.cpp PCH_SRCS) +endif (FREECAD_USE_PCH) + +add_library(CleanStartGui SHARED ${CleanStartGui_SRCS} ${CleanStartGuiIcon_SVG}) +# target_link_libraries(CleanStartGui ${CleanStartGui_LIBS} Qt::Quick Qt::Qml Qt::QuickWidgets) +target_link_libraries(CleanStartGui ${CleanStartGui_LIBS}) + +SET_BIN_DIR(CleanStartGui CleanStartGui /Mod/CleanStart) +SET_PYTHON_PREFIX_SUFFIX(CleanStartGui) + +fc_copy_sources(CleanStartGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/CleanStart" ${CleanStartGuiIcon_SVG}) + +INSTALL(TARGETS CleanStartGui DESTINATION ${CMAKE_INSTALL_LIBDIR}) +INSTALL(FILES ${CleanStartGuiIcon_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/CleanStart/Resources/icons") diff --git a/src/Mod/CleanStart/Gui/CleanStartView.cpp b/src/Mod/CleanStart/Gui/CleanStartView.cpp new file mode 100644 index 0000000000..24dfb366e4 --- /dev/null +++ b/src/Mod/CleanStart/Gui/CleanStartView.cpp @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "CleanStartView.h" +#include "FileCardDelegate.h" +#include "FileCardView.h" +#include "Gui/Workbench.h" +#include +#include +#include +#include +#include +#include +#include <3rdParty/GSL/include/gsl/pointers> + +using namespace CleanStartGui; + +TYPESYSTEM_SOURCE_ABSTRACT(CleanStartGui::CleanStartView, Gui::MDIView) // NOLINT + +namespace { + +struct NewButton +{ + QString heading; + QString description; + QString iconPath; +}; + +gsl::owner createNewButton(const NewButton& newButton) +{ + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Start"); + const auto cardSpacing = static_cast(hGrp->GetInt("FileCardSpacing", 20)); // NOLINT + const auto newFileIconSize = static_cast(hGrp->GetInt("NewFileIconSize", 48)); // NOLINT + + auto button = gsl::owner(new QPushButton()); + auto mainLayout = gsl::owner(new QHBoxLayout(button)); + auto iconLabel = gsl::owner(new QLabel(button)); + mainLayout->addWidget(iconLabel); + QIcon baseIcon(newButton.iconPath); + iconLabel->setPixmap(baseIcon.pixmap(newFileIconSize, newFileIconSize)); + + auto textLayout = gsl::owner(new QVBoxLayout); + auto textLabelLine1 = gsl::owner(new QLabel(button)); + textLabelLine1->setText(QLatin1String("") + newButton.heading + QLatin1String("")); + auto textLabelLine2 = gsl::owner(new QLabel(button)); + textLabelLine2->setText(newButton.description); + textLabelLine2->setWordWrap(true); + textLayout->addWidget(textLabelLine1); + textLayout->addWidget(textLabelLine2); + textLayout->setSpacing(0); + mainLayout->addItem(textLayout); + + mainLayout->addStretch(); + + button->setMinimumHeight(newFileIconSize + cardSpacing); + return button; +} + +} + +CleanStartView::CleanStartView(Gui::Document* pcDocument, QWidget* parent) + : Gui::MDIView(pcDocument, parent) + , _contents(new QScrollArea(parent)) +{ + setObjectName(QLatin1String("CleanStartView")); + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Start"); + auto cardSpacing = hGrp->GetInt("FileCardSpacing", 20); // NOLINT + + auto scrolledWidget = gsl::owner(new QWidget(this)); + _contents->setWidget(scrolledWidget); + _contents->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + _contents->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); + _contents->setWidgetResizable(true); + auto layout = gsl::owner(new QVBoxLayout(scrolledWidget)); + layout->setSizeConstraint(QLayout::SizeConstraint::SetMinAndMaxSize); + + auto newFileLabel = gsl::owner(new QLabel(tr("New File"))); + layout->addWidget(newFileLabel); + auto gridLayout = gsl::owner(new QGridLayout); + layout->addLayout(gridLayout); + configureNewFileButtons(gridLayout); + + auto recentFilesLabel = gsl::owner(new QLabel(tr("Recent Files"))); + layout->addWidget(recentFilesLabel); + auto recentFilesListWidget = gsl::owner(new FileCardView(_contents)); + connect(recentFilesListWidget, &QListView::clicked, this, &CleanStartView::fileCardSelected); + layout->addWidget(recentFilesListWidget); + + auto examplesLabel = gsl::owner(new QLabel(tr("Examples"))); + layout->addWidget(examplesLabel); + auto examplesListWidget = gsl::owner(new FileCardView(_contents)); + connect(examplesListWidget, &QListView::clicked, this, &CleanStartView::fileCardSelected); + layout->addWidget(examplesListWidget); + + layout->setSpacing(static_cast(cardSpacing)); + layout->addStretch(); + + setCentralWidget(_contents); + + QString title = QCoreApplication::translate("Workbench", "Start"); + setWindowTitle(title); + + configureExamplesListWidget(examplesListWidget); + configureRecentFilesListWidget(recentFilesListWidget); +} + + +void CleanStartView::configureNewFileButtons(QGridLayout* layout) const +{ + auto newEmptyFile = createNewButton({tr("Empty file"), + tr("Create a new empty FreeCAD file"), + QLatin1String(":/icons/document-new.svg")}); + auto openFile = createNewButton({tr("Open File"), + tr("Open an existing CAD file or 3D model"), + QLatin1String(":/icons/document-open.svg")}); + auto partDesign = createNewButton({tr("Parametric Part"), + tr("Create a part with the Part Design workbench"), + QLatin1String(":/icons/PartDesignWorkbench.svg")}); + auto assembly = createNewButton({tr("Assembly"), + tr("Create an assembly project"), + QLatin1String(":/icons/AssemblyWorkbench.svg")}); + auto draft = createNewButton({tr("2D Draft"), + tr("Create a 2D Draft with the Draft workbench"), + QLatin1String(":/icons/DraftWorkbench.svg")}); + auto arch = createNewButton({tr("BIM/Architecture"), + tr("Create an architectural project"), + QLatin1String(":/icons/ArchWorkbench.svg")}); + + layout->addWidget(partDesign, 0, 0); + layout->addWidget(assembly, 0, 1); + layout->addWidget(draft, 0, 2); + layout->addWidget(arch, 1, 0); + layout->addWidget(newEmptyFile, 1, 1); + layout->addWidget(openFile, 1, 2); + + connect(newEmptyFile, &QPushButton::clicked, this, &CleanStartView::newEmptyFile); + connect(openFile, &QPushButton::clicked, this, &CleanStartView::openExistingFile); + connect(partDesign, &QPushButton::clicked, this, &CleanStartView::newPartDesignFile); + connect(assembly, &QPushButton::clicked, this, &CleanStartView::newAssemblyFile); + connect(draft, &QPushButton::clicked, this, &CleanStartView::newDraftFile); + connect(arch, &QPushButton::clicked, this, &CleanStartView::newArchFile); +} + +void CleanStartView::configureFileCardWidget(QListView* fileCardWidget) +{ + auto delegate = gsl::owner(new FileCardDelegate); + fileCardWidget->setItemDelegate(delegate); + fileCardWidget->setMinimumWidth(fileCardWidget->parentWidget()->width()); + fileCardWidget->setGridSize( + fileCardWidget->itemDelegate()->sizeHint(QStyleOptionViewItem(), + fileCardWidget->model()->index(0, 0))); +} + + +void CleanStartView::configureRecentFilesListWidget(QListView* recentFilesListWidget) +{ + _recentFilesModel.loadRecentFiles(); + recentFilesListWidget->setModel(&_recentFilesModel); + configureFileCardWidget(recentFilesListWidget); +} + + +void CleanStartView::configureExamplesListWidget(QListView* examplesListWidget) +{ + _examplesModel.loadExamples(); + examplesListWidget->setModel(&_examplesModel); + configureFileCardWidget(examplesListWidget); +} + + +void CleanStartView::newEmptyFile() const +{ + Gui::Application::Instance->commandManager().runCommandByName("Std_New"); + postStart(PostStartBehavior::switchWorkbench); +} + +void CleanStartView::newPartDesignFile() const +{ + Gui::Application::Instance->commandManager().runCommandByName("Std_New"); + Gui::Application::Instance->activateWorkbench("PartDesignWorkbench"); + Gui::Application::Instance->commandManager().runCommandByName("PartDesign_Body"); + postStart(PostStartBehavior::doNotSwitchWorkbench); +} + +void CleanStartView::openExistingFile() const +{ + auto originalDocument = Gui::Application::Instance->activeDocument(); + Gui::Application::Instance->commandManager().runCommandByName("Std_Open"); + if (Gui::Application::Instance->activeDocument() != originalDocument) { + // Only run this if the user chose a new document to open (that is, they didn't cancel the + // open file dialog) + postStart(PostStartBehavior::switchWorkbench); + } +} + +void CleanStartView::newAssemblyFile() const +{ + Gui::Application::Instance->commandManager().runCommandByName("Std_New"); + Gui::Application::Instance->activateWorkbench("AssemblyWorkbench"); + Gui::Application::Instance->commandManager().runCommandByName("Assembly_CreateAssembly"); + Gui::Application::Instance->commandManager().runCommandByName("Std_Refresh"); + postStart(PostStartBehavior::doNotSwitchWorkbench); +} + +void CleanStartView::newDraftFile() const +{ + Gui::Application::Instance->commandManager().runCommandByName("Std_New"); + Gui::Application::Instance->activateWorkbench("DraftWorkbench"); + Gui::Application::Instance->commandManager().runCommandByName("Std_ViewTop"); + postStart(PostStartBehavior::doNotSwitchWorkbench); +} + +void CleanStartView::newArchFile() const +{ + Gui::Application::Instance->commandManager().runCommandByName("Std_New"); + try { + Gui::Application::Instance->activateWorkbench("BIMWorkbench"); + } + catch (...) { + Gui::Application::Instance->activateWorkbench("ArchWorkbench"); + } + postStart(PostStartBehavior::doNotSwitchWorkbench); +} + +void CleanStartView::postStart(PostStartBehavior behavior) const +{ + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Start"); + + if (behavior == PostStartBehavior::switchWorkbench) { + auto wb = hGrp->GetASCII("AutoloadModule", ""); + if (wb == "$LastModule") { + wb = App::GetApplication() + .GetParameterGroupByPath("User parameter:BaseApp/Preferences/General") + ->GetASCII("LastModule", ""); + } + if (!wb.empty()) { + Gui::Application::Instance->activateWorkbench(wb.c_str()); + } + } + auto closeStart = hGrp->GetBool("closeStart", false); + if (closeStart) { + this->window()->close(); + } +} + + +void CleanStartView::fileCardSelected(const QModelIndex& index) +{ + auto file = index.data(static_cast(CleanStart::DisplayedFilesModelRoles::path)).toString(); + auto command = std::string("FreeCAD.loadFile('") + file.toStdString() + "')"; + try { + Base::Interpreter().runString(command.c_str()); + postStart(PostStartBehavior::doNotSwitchWorkbench); + } + catch (Base::PyException& e) { + Base::Console().Error(e.getMessage().c_str()); + } + catch (Base::Exception &e) { + Base::Console().Error(e.getMessage().c_str()); + } + catch (...) { + Base::Console().Error("An unknown error occurred"); + } +} diff --git a/src/Mod/CleanStart/Gui/CleanStartView.h b/src/Mod/CleanStart/Gui/CleanStartView.h new file mode 100644 index 0000000000..4d33e86370 --- /dev/null +++ b/src/Mod/CleanStart/Gui/CleanStartView.h @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef FREECAD_CLEANSTARTVIEW_H +#define FREECAD_CLEANSTARTVIEW_H + +#include +#include +#include + +#include "../App/DisplayedFilesModel.h" +#include "../App/RecentFilesModel.h" +#include "../App/ExamplesModel.h" + + +class QListView; +class QGridLayout; +class QScrollArea; + +namespace Gui +{ +class Document; +} + +namespace CleanStartGui +{ + +class CleanStartGuiExport CleanStartView: public Gui::MDIView +{ + Q_OBJECT + + TYPESYSTEM_HEADER_WITH_OVERRIDE(); // NOLINT + +public: + CleanStartView(Gui::Document* pcDocument, QWidget* parent); + + const char* getName() const override + { + return "CleanStartView"; + } + + void newEmptyFile() const; + void newPartDesignFile() const; + void openExistingFile() const; + void newAssemblyFile() const; + void newDraftFile() const; + void newArchFile() const; + +public: + enum class PostStartBehavior { + switchWorkbench, + doNotSwitchWorkbench + }; + +protected: + + void configureNewFileButtons(QGridLayout *layout) const; + static void configureFileCardWidget(QListView *fileCardWidget); + void configureRecentFilesListWidget(QListView *recentFilesListWidget); + void configureExamplesListWidget(QListView *examplesListWidget); + + void postStart(PostStartBehavior behavior) const; + + void fileCardSelected(const QModelIndex &index); + +private: + QScrollArea* _contents = nullptr; + CleanStart::RecentFilesModel _recentFilesModel; + CleanStart::ExamplesModel _examplesModel; + + +}; // namespace CleanStartGui + +} // namespace CleanStartGui + +#endif // FREECAD_CLEANSTARTVIEW_H diff --git a/src/Mod/CleanStart/Gui/Command.cpp b/src/Mod/CleanStart/Gui/Command.cpp new file mode 100644 index 0000000000..1098157e56 --- /dev/null +++ b/src/Mod/CleanStart/Gui/Command.cpp @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#include +#include + +#include <3rdParty/GSL/include/gsl/pointers> + +#include "Workbench.h" + + +using namespace std; + +DEF_STD_CMD(CmdCleanStart) + +CmdCleanStart::CmdCleanStart() + : Command("CleanStart_CleanStart") +{ + sAppModule = "CleanStart"; + sGroup = QT_TR_NOOP("CleanStart"); + sMenuText = QT_TR_NOOP("CleanStart"); + sToolTipText = QT_TR_NOOP("Displays the CleanStart in an MDI view"); + sWhatsThis = "CleanStart_CleanStart"; + sStatusTip = sToolTipText; + sPixmap = "CleanStartWorkbench"; +} + +void CmdCleanStart::activated(int iMsg) +{ + Q_UNUSED(iMsg); + CleanStartGui::Workbench::loadCleanStart(); +} + + +void CreateCleanStartCommands() +{ + Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); + auto newCommand = gsl::owner(new CmdCleanStart); + rcCmdMgr.addCommand(newCommand); // Transfer ownership +} diff --git a/src/Mod/CleanStart/Gui/FileCardDelegate.cpp b/src/Mod/CleanStart/Gui/FileCardDelegate.cpp new file mode 100644 index 0000000000..b5af64b46c --- /dev/null +++ b/src/Mod/CleanStart/Gui/FileCardDelegate.cpp @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "FileCardDelegate.h" +#include "../App/DisplayedFilesModel.h" +#include "App/Application.h" +#include <3rdParty/GSL/include/gsl/pointers> + +using namespace CleanStart; + +FileCardDelegate::FileCardDelegate(QObject *parent) + : QAbstractItemDelegate(parent) { + _parameterGroup = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Start"); +} + + +void FileCardDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const { + auto thumbnailSize = + static_cast(_parameterGroup->GetInt("FileThumbnailIconsSize", 64)); // NOLINT + auto cardWidth = thumbnailSize; + auto baseName = index.data(static_cast(DisplayedFilesModelRoles::baseName)).toString(); + auto size = index.data(static_cast(DisplayedFilesModelRoles::size)).toString(); + auto image = index.data(static_cast(DisplayedFilesModelRoles::image)).toByteArray(); + auto path = index.data(static_cast(DisplayedFilesModelRoles::path)).toString(); + painter->save(); + auto widget = gsl::owner(new QWidget()); + auto layout = gsl::owner(new QVBoxLayout()); + widget->setLayout(layout); + auto thumbnail = gsl::owner(new QLabel()); + auto pixmap = gsl::owner(new QPixmap()); + if (!image.isEmpty()) { + pixmap->loadFromData(image); + auto scaled = pixmap->scaled(QSize(thumbnailSize, thumbnailSize), + Qt::AspectRatioMode::KeepAspectRatio, + Qt::TransformationMode::SmoothTransformation); + thumbnail->setPixmap(scaled); + } else { + thumbnail->setPixmap(generateThumbnail(path)); + } + thumbnail->setFixedSize(thumbnailSize, thumbnailSize); + thumbnail->setSizePolicy(QSizePolicy::Policy::Fixed, QSizePolicy::Policy::Fixed); + auto elided = + painter->fontMetrics().elidedText(baseName, Qt::TextElideMode::ElideRight, cardWidth); + auto name = gsl::owner(new QLabel(elided)); + layout->addWidget(thumbnail); + layout->addWidget(name); + auto sizeLabel = gsl::owner(new QLabel(size)); + layout->addWidget(sizeLabel); + layout->addStretch(); + layout->setSpacing(0); + widget->resize(option.rect.size()); + painter->translate(option.rect.topLeft()); + widget->render(painter, QPoint(), QRegion(), QWidget::DrawChildren); + painter->restore(); + delete pixmap; +} + + +QSize FileCardDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { + Q_UNUSED(option) + Q_UNUSED(index) + auto thumbnailSize = _parameterGroup->GetInt("FileThumbnailIconsSize", 128); // NOLINT + auto cardSpacing = _parameterGroup->GetInt("FileCardSpacing", 20); // NOLINT + auto cardWidth = thumbnailSize + cardSpacing; + + auto font = QGuiApplication::font(); + auto qfm = QFontMetrics(font); + auto textHeight = 2 * qfm.lineSpacing(); + auto cardHeight = thumbnailSize + textHeight + cardSpacing; + + return {static_cast(cardWidth), static_cast(cardHeight)}; +} + +namespace { + QPixmap pixmapToSizedQImage(const QImage &pixmap, int size) { + return QPixmap::fromImage(pixmap).scaled(size, size, + Qt::AspectRatioMode::KeepAspectRatio, + Qt::TransformationMode::SmoothTransformation); + } +} + +QPixmap FileCardDelegate::generateThumbnail(const QString &path) const { + auto thumbnailSize = + static_cast(_parameterGroup->GetInt("FileThumbnailIconsSize", 64)); // NOLINT + if (path.endsWith(QLatin1String(".fcstd"), Qt::CaseSensitivity::CaseInsensitive)) { + QImageReader reader(QLatin1String(":/icons/freecad-doc.svg"));; + reader.setScaledSize({thumbnailSize, thumbnailSize}); + return QPixmap::fromImage(reader.read()); + } + if (path.endsWith(QLatin1String(".fcmacro"), Qt::CaseSensitivity::CaseInsensitive)) { + QImageReader reader(QLatin1String(":/icons/MacroEditor.svg"));; + reader.setScaledSize({thumbnailSize, thumbnailSize}); + return QPixmap::fromImage(reader.read()); + } + if (!QImageReader::imageFormat(path).isEmpty()) { + // It is an image: it can be its own thumbnail + QImageReader reader(path); + auto image = reader.read(); + return pixmapToSizedQImage(image, thumbnailSize); + } + QIcon icon = QFileIconProvider().icon(QFileInfo(path)); + if (!icon.isNull()) { + QPixmap pixmap = icon.pixmap(thumbnailSize); + if (!pixmap.isNull()) { + return pixmap; + } + } + QPixmap pixmap = QPixmap(thumbnailSize, thumbnailSize); + pixmap.fill(); + return pixmap; +} diff --git a/src/Mod/CleanStart/Gui/FileCardDelegate.h b/src/Mod/CleanStart/Gui/FileCardDelegate.h new file mode 100644 index 0000000000..454563c130 --- /dev/null +++ b/src/Mod/CleanStart/Gui/FileCardDelegate.h @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef FREECAD_CLEANSTART_FILECARDDELEGATE_H +#define FREECAD_CLEANSTART_FILECARDDELEGATE_H + +#include +#include + +#include + +class FileCardDelegate : public QAbstractItemDelegate { + +public: + + explicit FileCardDelegate(QObject *parent = nullptr); + + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; + +protected: + + QPixmap generateThumbnail(const QString &path) const; + +private: + + Base::Reference _parameterGroup; +}; + + +#endif //FREECAD_CLEANSTART_FILECARDDELEGATE_H diff --git a/src/Mod/CleanStart/Gui/FileCardView.cpp b/src/Mod/CleanStart/Gui/FileCardView.cpp new file mode 100644 index 0000000000..1ae1043468 --- /dev/null +++ b/src/Mod/CleanStart/Gui/FileCardView.cpp @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#include "FileCardView.h" + +#include +#include "../App/DisplayedFilesModel.h" + +namespace CleanStartGui +{ + + +FileCardView::FileCardView(QWidget *parent) : QListView(parent) +{ + QSizePolicy sizePolicy(QSizePolicy::Policy::MinimumExpanding, + QSizePolicy::Policy::MinimumExpanding); + sizePolicy.setHeightForWidth(true); + setSizePolicy(sizePolicy); + setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + setViewMode(QListView::ViewMode::IconMode); + setFlow(QListView::Flow::LeftToRight); + setResizeMode(QListView::ResizeMode::Adjust); + setUniformItemSizes(true); +} + +int FileCardView::heightForWidth(int width) const +{ + auto model = this->model(); + auto delegate = this->itemDelegate(); + if (!model || !delegate) { + return 0; + } + int numCards = model->rowCount(); + auto cardSize = delegate->sizeHint(QStyleOptionViewItem(), model->index(0, 0)); + int cardsPerRow = static_cast(width / cardSize.width()); + int numRows = static_cast (ceil(static_cast(numCards) / static_cast(cardsPerRow))); + int neededHeight = numRows * cardSize.height(); + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Start"); + int cardSpacing = static_cast(hGrp->GetInt("FileCardSpacing", 20)); // NOLINT + return neededHeight + cardSpacing*(numRows-1) + 2*cardSpacing; +} + +QSize FileCardView::sizeHint() const +{ + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Start"); + int cardSpacing = static_cast(hGrp->GetInt("FileCardSpacing", 20)); // NOLINT + + auto model = this->model(); + auto delegate = this->itemDelegate(); + if (!model || !delegate) { + // The model and/or delegate have not been set yet, this was an early startup call + return {cardSpacing, cardSpacing}; + } + int numCards = model->rowCount(); + auto cardSize = delegate->sizeHint(QStyleOptionViewItem(), model->index(0, 0)); + return {(cardSize.width()+cardSpacing) * numCards + cardSpacing, cardSize.height() + 2* cardSpacing}; +} + + +} // namespace CleanStart diff --git a/src/Mod/CleanStart/Gui/FileCardView.h b/src/Mod/CleanStart/Gui/FileCardView.h new file mode 100644 index 0000000000..2e8994858a --- /dev/null +++ b/src/Mod/CleanStart/Gui/FileCardView.h @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef FREECAD_CLEANSTART_FILECARDVIEW_H +#define FREECAD_CLEANSTART_FILECARDVIEW_H + +#include + +namespace CleanStartGui +{ + +class FileCardView : public QListView +{ + Q_OBJECT + +public: + explicit FileCardView(QWidget *parent = nullptr); + + int heightForWidth(int width) const override; + + QSize sizeHint() const override; + +}; + +} // namespace CleanStart + +#endif // FREECAD_CLEANSTART_FILECARDVIEW_H diff --git a/src/Mod/CleanStart/Gui/PreCompiled.cpp b/src/Mod/CleanStart/Gui/PreCompiled.cpp new file mode 100644 index 0000000000..b17d7731bd --- /dev/null +++ b/src/Mod/CleanStart/Gui/PreCompiled.cpp @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * +# Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" diff --git a/src/Mod/CleanStart/Gui/PreCompiled.h b/src/Mod/CleanStart/Gui/PreCompiled.h new file mode 100644 index 0000000000..3e6fc4cc7a --- /dev/null +++ b/src/Mod/CleanStart/Gui/PreCompiled.h @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * +# Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef CLEANSTARTGUI_PRECOMPILED_H +#define CLEANSTARTGUI_PRECOMPILED_H + +#include + +#ifdef _MSC_VER +#pragma warning(disable : 5208) +#endif + +#ifdef _PreComp_ + +// standard +#include +#include +#include +#include +#include +#include +#include +#include + +// Qt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // _PreComp_ +#endif // CLEANSTARTGUI_PRECOMPILED_H diff --git a/src/Mod/CleanStart/Gui/Resources/CleanStart.qrc b/src/Mod/CleanStart/Gui/Resources/CleanStart.qrc new file mode 100644 index 0000000000..a6f27c69a4 --- /dev/null +++ b/src/Mod/CleanStart/Gui/Resources/CleanStart.qrc @@ -0,0 +1,5 @@ + + + icons/CleanStartWorkbench.svg + + diff --git a/src/Mod/CleanStart/Gui/Resources/icons/CleanStartWorkbench.svg b/src/Mod/CleanStart/Gui/Resources/icons/CleanStartWorkbench.svg new file mode 100644 index 0000000000..92e7992912 --- /dev/null +++ b/src/Mod/CleanStart/Gui/Resources/icons/CleanStartWorkbench.svg @@ -0,0 +1,35 @@ + + +AAAsdWp1bWIAAAAeanVtZGMycGEAEQAQgAAAqgA4m3EDYzJwYQAAACxPanVtYgAAAEdqdW1kYzJtYQARABCAAACqADibcQN1cm46dXVpZDo0YjRiNjhiMC1jYWIyLTQ3NjgtYjgyMC0xMGZiMzRiMjIzNDAAAAABtWp1bWIAAAApanVtZGMyYXMAEQAQgAAAqgA4m3EDYzJwYS5hc3NlcnRpb25zAAAAANdqdW1iAAAAJmp1bWRjYm9yABEAEIAAAKoAOJtxA2MycGEuYWN0aW9ucwAAAACpY2JvcqFnYWN0aW9uc4GjZmFjdGlvbmtjMnBhLmVkaXRlZG1zb2Z0d2FyZUFnZW50bUFkb2JlIEZpcmVmbHlxZGlnaXRhbFNvdXJjZVR5cGV4U2h0dHA6Ly9jdi5pcHRjLm9yZy9uZXdzY29kZXMvZGlnaXRhbHNvdXJjZXR5cGUvY29tcG9zaXRlV2l0aFRyYWluZWRBbGdvcml0aG1pY01lZGlhAAAArWp1bWIAAAAoanVtZGNib3IAEQAQgAAAqgA4m3EDYzJwYS5oYXNoLmRhdGEAAAAAfWNib3KlamV4Y2x1c2lvbnOBomVzdGFydBkBo2ZsZW5ndGgZO0hkbmFtZW5qdW1iZiBtYW5pZmVzdGNhbGdmc2hhMjU2ZGhhc2hYIElELNIOhv56eICCdEZNoj2K8JEvFWRCJNlTbdf5JfACY3BhZEkAAAAAAAAAAAAAAAILanVtYgAAACRqdW1kYzJjbAARABCAAACqADibcQNjMnBhLmNsYWltAAAAAd9jYm9yqGhkYzp0aXRsZW9HZW5lcmF0ZWQgSW1hZ2VpZGM6Zm9ybWF0bWltYWdlL3N2Zyt4bWxqaW5zdGFuY2VJRHgseG1wOmlpZDo3ZWRhZGYxNi1jMzllLTQ5ZDUtYmNkZS00ZTBjNTc1YmQyZWJvY2xhaW1fZ2VuZXJhdG9yeDZBZG9iZV9JbGx1c3RyYXRvci8yOC4zIGFkb2JlX2MycGEvMC43LjYgYzJwYS1ycy8wLjI1LjJ0Y2xhaW1fZ2VuZXJhdG9yX2luZm+Bv2RuYW1lcUFkb2JlIElsbHVzdHJhdG9yZ3ZlcnNpb25kMjguM/9pc2lnbmF0dXJleBlzZWxmI2p1bWJmPWMycGEuc2lnbmF0dXJlamFzc2VydGlvbnOComN1cmx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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9lkBADaYjbNHBledrs8UvzcmIqg4q5h2I85dUCPn9QN1KzSHCFLAAEktdVGMxgi6L8yyKxQDXsxwIdEoCmi3IYtSe1SatqfzWegeTWgkpslSKyduJeUQbtePR6xJbavPMS1Li8dOlMInahvFdX8o/TSfg/exYQ/6aNF7/P/nscuzeu3ocpRXoNPlmaYfFxK1eLwOQL1Q2/KSuoQYOvq7mDGUA8LxdK0pN7IgRy70YUuXk5eXeVVb/aFXY7lwXeYuO+1inkxNNLY6Ndoe9iiu+XhXlhMNU2BiSYv40Ra8zOCuPfPKGTf3e/vLjW6HLo52X3G0DzD9uHaCZWYtZQ87IDR1+Kg= + + + + + + + + + + + + + + diff --git a/src/Mod/CleanStart/Gui/Workbench.cpp b/src/Mod/CleanStart/Gui/Workbench.cpp new file mode 100644 index 0000000000..8623e6afd4 --- /dev/null +++ b/src/Mod/CleanStart/Gui/Workbench.cpp @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "Workbench.h" +#include "CleanStartView.h" + +#include <3rdParty/GSL/include/gsl/pointers> + +using namespace CleanStartGui; + +TYPESYSTEM_SOURCE(CleanStartGui::Workbench, Gui::StdWorkbench) // NOLINT + +void CleanStartGui::Workbench::activated() +{ + loadCleanStart(); +} + +void CleanStartGui::Workbench::loadCleanStart() +{ + auto mw = Gui::getMainWindow(); + auto doc = Gui::Application::Instance->activeDocument(); + auto existingView = mw->findChild(QLatin1String("CleanStartView")); + if (!existingView) { + existingView = gsl::owner (new CleanStartView (doc, mw)); + mw->addWindow(existingView); // Transfers ownership + } + Gui::getMainWindow()->setActiveWindow(existingView); + existingView->show(); +} + +Gui::MenuItem* CleanStartGui::Workbench::setupMenuBar() const +{ + return Gui::StdWorkbench::setupMenuBar(); +} + +Gui::ToolBarItem* CleanStartGui::Workbench::setupToolBars() const +{ + return Gui::StdWorkbench::setupToolBars(); +} + +Gui::ToolBarItem* CleanStartGui::Workbench::setupCommandBars() const +{ + return Gui::StdWorkbench::setupCommandBars(); +} + +Gui::DockWindowItems* CleanStartGui::Workbench::setupDockWindows() const +{ + Gui::DockWindowItems* root = Gui::StdWorkbench::setupDockWindows(); + root->setVisibility(false); // hide all dock windows by default + root->setVisibility("Std_ComboView", true); // except of the combo view + root->setVisibility("Std_TaskView", true); // and the task view + return root; +} diff --git a/src/Mod/CleanStart/Gui/Workbench.h b/src/Mod/CleanStart/Gui/Workbench.h new file mode 100644 index 0000000000..0e89d1a602 --- /dev/null +++ b/src/Mod/CleanStart/Gui/Workbench.h @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2024 The FreeCAD Project Association AISBL * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + + +#ifndef LAUNCHERGUI_WORKBENCH_H +#define LAUNCHERGUI_WORKBENCH_H + +#include +#include + +namespace Gui { +class MDIView; +} + +namespace CleanStartGui +{ + +class Workbench: public Gui::StdWorkbench +{ + TYPESYSTEM_HEADER_WITH_OVERRIDE(); // NOLINT + +public: + Workbench() = default; + + /** Run some actions when the workbench gets activated. */ + void activated() override; + + static void loadCleanStart(); + +protected: + /** Defines the standard menus. */ + Gui::MenuItem* setupMenuBar() const override; + /** Defines the standard toolbars. */ + Gui::ToolBarItem* setupToolBars() const override; + /** Defines the standard command bars. */ + Gui::ToolBarItem* setupCommandBars() const override; + /** Returns a DockWindowItems structure of dock windows this workbench. */ + Gui::DockWindowItems* setupDockWindows() const override; + +}; // class Workbench + +} // namespace CleanStartGui +#endif // LAUNCHERGUI_WORKBENCH_H diff --git a/src/Mod/CleanStart/Init.py b/src/Mod/CleanStart/Init.py new file mode 100644 index 0000000000..c41703a22a --- /dev/null +++ b/src/Mod/CleanStart/Init.py @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# /************************************************************************** +# * +# Copyright (c) 2024 The FreeCAD Project Association AISBL * +# * +# This file is part of FreeCAD. * +# * +# FreeCAD is free software: you can redistribute it and/or modify it * +# under the terms of the GNU Lesser General Public License as * +# published by the Free Software Foundation, either version 2.1 of the * +# License, or (at your option) any later version. * +# * +# FreeCAD is distributed in the hope that it will be useful, but * +# WITHOUT ANY WARRANTY; without even the implied warranty of * +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +# Lesser General Public License for more details. * +# * +# You should have received a copy of the GNU Lesser General Public * +# License along with FreeCAD. If not, see * +# . * +# * +# **************************************************************************/ + +# Get the Parameter Group of this module +ParGrp = App.ParamGet("System parameter:Modules").GetGroup("CleanStart") + +# Set the needed information +ParGrp.SetString("WorkBenchName", "CleanStart") +ParGrp.SetString("WorkBenchModule", "CleanStart.py") diff --git a/src/Mod/CleanStart/InitGui.py b/src/Mod/CleanStart/InitGui.py new file mode 100644 index 0000000000..cf1e585af2 --- /dev/null +++ b/src/Mod/CleanStart/InitGui.py @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# /************************************************************************** +# * +# Copyright (c) 2024 The FreeCAD Project Association AISBL * +# * +# This file is part of FreeCAD. * +# * +# FreeCAD is free software: you can redistribute it and/or modify it * +# under the terms of the GNU Lesser General Public License as * +# published by the Free Software Foundation, either version 2.1 of the * +# License, or (at your option) any later version. * +# * +# FreeCAD is distributed in the hope that it will be useful, but * +# WITHOUT ANY WARRANTY; without even the implied warranty of * +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +# Lesser General Public License for more details. * +# * +# You should have received a copy of the GNU Lesser General Public * +# License along with FreeCAD. If not, see * +# . * +# * +# **************************************************************************/ + + +class CleanStartWorkbench(Workbench): + "CleanStartWorkbench workbench" + + def __init__(self): + self.__class__.Icon = ( + FreeCAD.getResourceDir() + "Mod/Start/Resources/icons/StartWorkbench.svg" + ) + self.__class__.MenuText = "Start (new!)" + self.__class__.ToolTip = "Start workbench" + + def Initialize(self): + import CleanStartGui + + def Activated(self): + pass + + def Deactivated(self): + pass + + def ContextMenu(self, recipient): + pass + + def GetClassName(self): + return "CleanStartGui::Workbench" + + +Gui.addWorkbench(CleanStartWorkbench()) diff --git a/src/Mod/CleanStart/README.md b/src/Mod/CleanStart/README.md new file mode 100644 index 0000000000..41e402c380 --- /dev/null +++ b/src/Mod/CleanStart/README.md @@ -0,0 +1,53 @@ +## CleanStart Workbench + +This Workbench is intended to eventually replace (and be renamed to) Start. Its main reason for existing is to +eliminate FreeCAD's dependency on QtWebEngine by redesigning Start to eliminate the HTML component. + +The long-term plan for this workbench is to migrate from Qt Widgets to QtQuick/QML with a C++ backend providing access +to things like FreeCAD's Recent Files list. This switch will happen sometime after we no longer have to support building +on Ubuntu 20.04 LTS, which still uses Qt 5.12. The cMake integration of QML and C++ together in a single project is +greatly improved in Qt 5.15 and later. + +In the meantime the workbench is written in C++ so that the models can be re-used later, and only the UI itself will +have to change. + +### Structure + +The main UI file for the Start screen is in `Gui/CleanStartView.cpp` -- that class is a `QScrollArea` that gets embedded +into a new FreeCAD `MDIView`. Inside the scroll area are three regions: + +1. **New File**. A set of `QPushButtons` with embedded `QLayouts` displaying an image and two lines of text. Currently +laid out manually in a `QGridLayout`, but eventually it would be nice to dynamically calculate that layout to allow the +buttons to exist on a single line when there is enough space for them. +2. **Recent Files**. One of two "File Card" regions, this shows a list of recent files. It uses the +Model-View-Controller architecture for flexibility and re-usability. In that architecture, the data being displayed is +called the "model", and the actual mechanism for doing the display is called the "view". Qt further differentiates +between the overall view and the display of the individual items in the view. The items are rendered by a "delegate" +when they are too complex to be displayed by the simple view (e.g. if you want images and text in a particular layout). + * The "model" in this case is `RecentFilesModel`, a simple read-only interface to +FreeCAD's preferences system, where it gets the list of recent files. That class is in`App/RecentFilesModel.*`. It is +implemented using a set of User Roles, one for each piece of data about a file. Not all data is available for all files. +For example, when given `const QModelIndex &index`, you can call `index.data(DisplayedFilesModelRoles::author)` to get +the "author" metadata item of an `FCStd` file. See the `DisplayedFilesModelRoles` enumeration for possible values. These +roles are also exposed to QML via their names. + * The View is a class derived from `QListView`, `Gui/FileCardView.*`, whose only function beyond the standard +`QListView` is to implement the "height for width" functionality, so the widget can properly resize based on the number +of file cards and the screen width, laying them out in a grid. + * The file cards are rendered using the `FileCardDelegate` class in `Gui/FileCardDelegate.*`. That class uses +a simple `QVBoxLayout` to paint the icon, filename, and file size. +3. **Examples**. Another "File Card" widget, using the same classes as Recent Files, but with a different model. In this +case the model is `ExamplesModel` in `App/ExamplesModel.*`. It fetches a read-only list of files from the FreeCAD +`resources/examples` directory and displays them. + +### UI Design + +This Workbench does the minimum amount of design customization, preferring to allow Stylesheet authors control over the +display via the normal QSS mechanisms in Qt. There are three FreeCAD Parameters that control the spacing between the +widgets and the size of the icons, all in the `BaseApp/Preferences/Mod/Start/` preferences group: +* `FileCardSpacing` (default: 20). The space between and around the individual File Cards. +* `FileThumbnailIconsSize` (default: 128). The size of the file thumbnail on the File Cards. +* `NewFileIconSize` (default: 48). The size of the icons on each of the "new file" buttons. + +At present none of these are directly exposed to the user, and the new Start workbench does not have a preferences +panel. The parameters are intended to be used by Preference Pack authors to assist in customization of FreeCAD themes. +It is likely that this will be expanded once feedback from theme designers is received. \ No newline at end of file