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.).
This commit is contained in:
Chris Hennes
2024-03-06 22:47:31 -06:00
parent 58be610253
commit 57bc297005
36 changed files with 2209 additions and 2 deletions

3
.gitmodules vendored
View File

@@ -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

View File

@@ -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)

1
src/3rdParty/GSL vendored Submodule

Submodule src/3rdParty/GSL added at b39e7e4b09

View File

@@ -12,6 +12,7 @@
<file>list-add.svg</file>
<file>freecad.svg</file>
<file>freecad-doc.png</file>
<file>freecad-doc.svg</file>
<file>bulb.svg</file>
<file>TextDocument.svg</file>
<file>button_down.svg</file>

View File

@@ -16,5 +16,6 @@
<file>panels/TaskAssemblyInsertLink.ui</file>
<file>preferences/Assembly.ui</file>
<file>icons/Assembly_CreateJointDistance.svg</file>
<file>icons/AssemblyWorkbench.svg</file>
</qresource>
</RCC>

View File

@@ -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)

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#include <Base/Interpreter.h>
#include <Base/Tools.h>
#include <Base/Console.h>
#include <Base/PyObjectBase.h>
#include <3rdParty/GSL/include/gsl/pointers>
namespace CleanStart
{
class Module: public Py::ExtensionModule<Module>
{
public:
Module()
: Py::ExtensionModule<Module>("CleanStart")
{
initialize("This module is the CleanStart module."); // register with Python
}
};
PyObject* initModule()
{
auto newModule = gsl::owner<Module *>(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);
}

View File

@@ -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 *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************/
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})

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QByteArray>
#include <QFile>
#include <QFileInfo>
#endif
#include "DisplayedFilesModel.h"
#include <App/Application.h>
#include <App/ProjectFile.h>
using namespace CleanStart;
namespace
{
std::string humanReadableSize(unsigned int bytes)
{
static const std::vector<std::string> 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<int>(_fileInfoCache.size());
}
QVariant DisplayedFilesModel::data(const QModelIndex& index, int roleAsInt) const
{
int row = index.row();
if (row < 0 || row >= static_cast<int>(_fileInfoCache.size())) {
return {};
}
auto mapEntry = _fileInfoCache.at(row);
auto role = static_cast<DisplayedFilesModelRoles>(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<int, QByteArray> DisplayedFilesModel::roleNames() const
{
static QHash<int, QByteArray> 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;
}

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef FREECAD_CLEANSTART_DISPLAYEDFILESMODEL_H
#define FREECAD_CLEANSTART_DISPLAYEDFILESMODEL_H
#include <QAbstractListModel>
#include <Base/Parameter.h>
#include <QtQml/QQmlTypeInfo>
#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<DisplayedFilesModelRoles, std::string>;
/// 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<int, QByteArray> 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<FileStats> _fileInfoCache;
QMap<QString, QByteArray> _imageCache;
};
} // namespace CleanStart
#endif // FREECAD_CLEANSTART_DISPLAYEDFILESMODEL_H

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QDir>
#endif
#include "ExamplesModel.h"
#include <App/Application.h>
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();
}

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef FREECAD_CLEANSTART_EXAMPLESMODEL_H
#define FREECAD_CLEANSTART_EXAMPLESMODEL_H
#include <QAbstractListModel>
#include <QDir>
#include <Base/Parameter.h>
#include <QtQml/QQmlTypeInfo>
#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

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef CLEANSTART_PRECOMPILED_H
#define CLEANSTART_PRECOMPILED_H
#include <FCConfig.h>
#ifdef _MSC_VER
#pragma warning(disable : 5208)
#endif
#ifdef _PreComp_
// standard
#include <cinttypes>
#include <cmath>
#include <iomanip>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <unordered_map>
// Qt (should never include GUI files, only QtCore)
#include <QDir>
#include <QFile>
#include <QFileInfo>
#endif // _PreComp_
#endif // CLEANSTART_PRECOMPILED_H

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include "RecentFilesModel.h"
#include <App/Application.h>
#include <App/ProjectFile.h>
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();
}

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef FREECAD_CLEANSTART_RECENTFILESMODEL_H
#define FREECAD_CLEANSTART_RECENTFILESMODEL_H
#include <QAbstractListModel>
#include <Base/Parameter.h>
#include <QtQml/QQmlTypeInfo>
#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<ParameterGrp> _parameterGroup;
};
} // namespace CleanStart
#endif // FREECAD_CLEANSTART_RECENTFILESMODEL_H

View File

@@ -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 *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************/
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
)

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include <FCGlobal.h>
#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

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <Base/PyObjectBase.h>
#include <Gui/Language/Translator.h>
#include <QString>
#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<Module>
{
public:
Module()
: Py::ExtensionModule<Module>("CleanStartGui")
{
initialize("This module is the CleanStartGui module."); // register with Python
}
};
PyObject* initModule()
{
auto newModule = gsl::owner<Module*>(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);
}

View File

@@ -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 *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************/
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")

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QCoreApplication>
#include <QGridLayout>
#include <QLabel>
#include <QListView>
#include <QPushButton>
#include <QScrollArea>
#include <QWidget>
#endif
#include "CleanStartView.h"
#include "FileCardDelegate.h"
#include "FileCardView.h"
#include "Gui/Workbench.h"
#include <Gui/Document.h>
#include <App/DocumentObject.h>
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#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<QPushButton*> createNewButton(const NewButton& newButton)
{
auto hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Start");
const auto cardSpacing = static_cast<int>(hGrp->GetInt("FileCardSpacing", 20)); // NOLINT
const auto newFileIconSize = static_cast<int>(hGrp->GetInt("NewFileIconSize", 48)); // NOLINT
auto button = gsl::owner<QPushButton*>(new QPushButton());
auto mainLayout = gsl::owner<QHBoxLayout*>(new QHBoxLayout(button));
auto iconLabel = gsl::owner<QLabel*>(new QLabel(button));
mainLayout->addWidget(iconLabel);
QIcon baseIcon(newButton.iconPath);
iconLabel->setPixmap(baseIcon.pixmap(newFileIconSize, newFileIconSize));
auto textLayout = gsl::owner<QVBoxLayout*>(new QVBoxLayout);
auto textLabelLine1 = gsl::owner<QLabel*>(new QLabel(button));
textLabelLine1->setText(QLatin1String("<b>") + newButton.heading + QLatin1String("</b>"));
auto textLabelLine2 = gsl::owner<QLabel*>(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<QWidget*>(new QWidget(this));
_contents->setWidget(scrolledWidget);
_contents->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
_contents->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
_contents->setWidgetResizable(true);
auto layout = gsl::owner<QVBoxLayout*>(new QVBoxLayout(scrolledWidget));
layout->setSizeConstraint(QLayout::SizeConstraint::SetMinAndMaxSize);
auto newFileLabel = gsl::owner<QLabel*>(new QLabel(tr("New File")));
layout->addWidget(newFileLabel);
auto gridLayout = gsl::owner<QGridLayout*>(new QGridLayout);
layout->addLayout(gridLayout);
configureNewFileButtons(gridLayout);
auto recentFilesLabel = gsl::owner<QLabel*>(new QLabel(tr("Recent Files")));
layout->addWidget(recentFilesLabel);
auto recentFilesListWidget = gsl::owner<FileCardView*>(new FileCardView(_contents));
connect(recentFilesListWidget, &QListView::clicked, this, &CleanStartView::fileCardSelected);
layout->addWidget(recentFilesListWidget);
auto examplesLabel = gsl::owner<QLabel*>(new QLabel(tr("Examples")));
layout->addWidget(examplesLabel);
auto examplesListWidget = gsl::owner<FileCardView*>(new FileCardView(_contents));
connect(examplesListWidget, &QListView::clicked, this, &CleanStartView::fileCardSelected);
layout->addWidget(examplesListWidget);
layout->setSpacing(static_cast<int>(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<FileCardDelegate*>(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<int>(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");
}
}

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef FREECAD_CLEANSTARTVIEW_H
#define FREECAD_CLEANSTARTVIEW_H
#include <Mod/CleanStart/CleanStartGlobal.h>
#include <Base/Type.h>
#include <Gui/MDIView.h>
#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

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#include <Gui/Application.h>
#include <Gui/Command.h>
#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<CmdCleanStart*>(new CmdCleanStart);
rcCmdMgr.addCommand(newCommand); // Transfer ownership
}

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QFile>
#include <QFileIconProvider>
#include <QImageReader>
#include <QPainter>
#include <QStyleOptionViewItem>
#include <QLabel>
#include <QModelIndex>
#include <QVBoxLayout>
#include <QGuiApplication>
#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<int>(_parameterGroup->GetInt("FileThumbnailIconsSize", 64)); // NOLINT
auto cardWidth = thumbnailSize;
auto baseName = index.data(static_cast<int>(DisplayedFilesModelRoles::baseName)).toString();
auto size = index.data(static_cast<int>(DisplayedFilesModelRoles::size)).toString();
auto image = index.data(static_cast<int>(DisplayedFilesModelRoles::image)).toByteArray();
auto path = index.data(static_cast<int>(DisplayedFilesModelRoles::path)).toString();
painter->save();
auto widget = gsl::owner<QWidget *>(new QWidget());
auto layout = gsl::owner<QVBoxLayout *>(new QVBoxLayout());
widget->setLayout(layout);
auto thumbnail = gsl::owner<QLabel *>(new QLabel());
auto pixmap = gsl::owner<QPixmap *>(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<QLabel *>(new QLabel(elided));
layout->addWidget(thumbnail);
layout->addWidget(name);
auto sizeLabel = gsl::owner<QLabel *>(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<int>(cardWidth), static_cast<int>(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<int>(_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;
}

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef FREECAD_CLEANSTART_FILECARDDELEGATE_H
#define FREECAD_CLEANSTART_FILECARDDELEGATE_H
#include <Base/Parameter.h>
#include <QImage>
#include <QAbstractItemDelegate>
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<ParameterGrp> _parameterGroup;
};
#endif //FREECAD_CLEANSTART_FILECARDDELEGATE_H

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#include "FileCardView.h"
#include <App/Application.h>
#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<int>(width / cardSize.width());
int numRows = static_cast<int> (ceil(static_cast<double>(numCards) / static_cast<double>(cardsPerRow)));
int neededHeight = numRows * cardSize.height();
auto hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Start");
int cardSpacing = static_cast<int>(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<int>(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

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef FREECAD_CLEANSTART_FILECARDVIEW_H
#define FREECAD_CLEANSTART_FILECARDVIEW_H
#include <QListView>
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

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef CLEANSTARTGUI_PRECOMPILED_H
#define CLEANSTARTGUI_PRECOMPILED_H
#include <FCConfig.h>
#ifdef _MSC_VER
#pragma warning(disable : 5208)
#endif
#ifdef _PreComp_
// standard
#include <cinttypes>
#include <cmath>
#include <iomanip>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <unordered_map>
// Qt
#include <QCoreApplication>
#include <QFile>
#include <QFileIconProvider>
#include <QGridLayout>
#include <QGuiApplication>
#include <QImageReader>
#include <QLabel>
#include <QListView>
#include <QModelIndex>
#include <QPainter>
#include <QPushButton>
#include <QScrollArea>
#include <QSpacerItem>
#include <QStyleOptionViewItem>
#include <QUrl>
#include <QVBoxLayout>
#include <QWidget>
#endif // _PreComp_
#endif // CLEANSTARTGUI_PRECOMPILED_H

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>icons/CleanStartWorkbench.svg</file>
</qresource>
</RCC>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QCoreApplication>
#include <QLayout>
#endif
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Gui/Command.h>
#include <Gui/DockWindowManager.h>
#include <Gui/MDIView.h>
#include <Gui/MainWindow.h>
#include <Gui/ToolBarManager.h>
#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<CleanStartView*>(QLatin1String("CleanStartView"));
if (!existingView) {
existingView = gsl::owner<CleanStartView*> (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;
}

View File

@@ -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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef LAUNCHERGUI_WORKBENCH_H
#define LAUNCHERGUI_WORKBENCH_H
#include <Gui/Workbench.h>
#include <memory>
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

View File

@@ -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 *
# <https://www.gnu.org/licenses/>. *
# *
# **************************************************************************/
# 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")

View File

@@ -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 *
# <https://www.gnu.org/licenses/>. *
# *
# **************************************************************************/
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())

View File

@@ -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.