diff --git a/src/Mod/Start/Gui/CMakeLists.txt b/src/Mod/Start/Gui/CMakeLists.txt
index 5d6559e9fd..863164955f 100644
--- a/src/Mod/Start/Gui/CMakeLists.txt
+++ b/src/Mod/Start/Gui/CMakeLists.txt
@@ -53,14 +53,20 @@ SET(StartGui_SRCS
FileCardDelegate.h
FileCardView.cpp
FileCardView.h
+ FirstStartWidget.cpp
+ FirstStartWidget.h
FlowLayout.cpp
FlowLayout.h
+ GeneralSettingsWidget.cpp
+ GeneralSettingsWidget.h
Manipulator.cpp
Manipulator.h
PreCompiled.cpp
PreCompiled.h
StartView.cpp
StartView.h
+ ThemeSelectorWidget.cpp
+ ThemeSelectorWidget.h
)
SET(StartGuiIcon_SVG
@@ -68,6 +74,12 @@ SET(StartGuiIcon_SVG
Resources/icons/PartDesignWorkbench.svg
)
+SET(StartGuiThumbnail_PNG
+ Resources/thumbnails/Classic512.png
+ Resources/thumbnails/OpenDark512.png
+ Resources/thumbnails/OpenLight512.png
+ )
+
# TODO: Evaluate PCH use with Qt6/QtQuick/Qml
if (FREECAD_USE_PCH)
add_definitions(-D_PreComp_)
@@ -75,7 +87,7 @@ if (FREECAD_USE_PCH)
ADD_MSVC_PRECOMPILED_HEADER(StartGui PreCompiled.h PreCompiled.cpp PCH_SRCS)
endif (FREECAD_USE_PCH)
-add_library(StartGui SHARED ${StartGui_SRCS} ${StartGuiIcon_SVG})
+add_library(StartGui SHARED ${StartGui_SRCS} ${StartGuiIcon_SVG} ${StartGuiThumbnail_PNG})
# target_link_libraries(StartGui ${StartGui_LIBS} Qt::Quick Qt::Qml Qt::QuickWidgets)
target_link_libraries(StartGui ${StartGui_LIBS})
diff --git a/src/Mod/Start/Gui/FirstStartWidget.cpp b/src/Mod/Start/Gui/FirstStartWidget.cpp
new file mode 100644
index 0000000000..b506b382e7
--- /dev/null
+++ b/src/Mod/Start/Gui/FirstStartWidget.cpp
@@ -0,0 +1,108 @@
+// 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 "FirstStartWidget.h"
+#include "ThemeSelectorWidget.h"
+#include "GeneralSettingsWidget.h"
+
+#include
+#include
+
+using namespace StartGui;
+
+FirstStartWidget::FirstStartWidget(QWidget* parent)
+ : QGroupBox(parent)
+ , _themeSelectorWidget {nullptr}
+ , _generalSettingsWidget {nullptr}
+ , _welcomeLabel {nullptr}
+ , _descriptionLabel {nullptr}
+ , _doneButton {nullptr}
+{
+ setObjectName(QLatin1String("FirstStartWidget"));
+ setupUi();
+ qApp->installEventFilter(this);
+}
+
+void FirstStartWidget::setupUi()
+{
+ auto outerLayout = gsl::owner(new QVBoxLayout(this));
+ QString application = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
+ _welcomeLabel = gsl::owner(new QLabel);
+ outerLayout->addWidget(_welcomeLabel);
+ _descriptionLabel = gsl::owner(new QLabel);
+ outerLayout->addWidget(_descriptionLabel);
+
+ _themeSelectorWidget = gsl::owner(new ThemeSelectorWidget(this));
+ _generalSettingsWidget = gsl::owner(new GeneralSettingsWidget(this));
+
+ outerLayout->addWidget(_generalSettingsWidget);
+ outerLayout->addWidget(_themeSelectorWidget);
+
+ _doneButton = gsl::owner(new QPushButton);
+ auto buttonBar = gsl::owner(new QHBoxLayout);
+ buttonBar->addStretch();
+ buttonBar->addWidget(_doneButton);
+ outerLayout->addLayout(buttonBar);
+
+ connect(_doneButton, &QPushButton::clicked, this, &FirstStartWidget::doneClicked);
+ retranslateUi();
+}
+
+void FirstStartWidget::doneClicked()
+{
+ auto hGrp = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/Mod/Start");
+ hGrp->SetBool("FirstStart2024", false);
+ this->hide();
+}
+
+bool FirstStartWidget::eventFilter(QObject* object, QEvent* event)
+{
+ if (object == this && event->type() == QEvent::LanguageChange) {
+ this->retranslateUi();
+ }
+ return QWidget::eventFilter(object, event);
+}
+
+void FirstStartWidget::retranslateUi()
+{
+ _doneButton->setText(tr("Done"));
+ QString application = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
+ _welcomeLabel->setText(QLatin1String("") + tr("Welcome to %1").arg(application)
+ + QLatin1String("
"));
+ _descriptionLabel->setText(
+ tr("To get started, set your basic configuration options below.") + QLatin1String(" ")
+ + tr("These options (and many more) can be changed later in Preferences."));
+}
diff --git a/src/Mod/Start/Gui/FirstStartWidget.h b/src/Mod/Start/Gui/FirstStartWidget.h
new file mode 100644
index 0000000000..0965d80424
--- /dev/null
+++ b/src/Mod/Start/Gui/FirstStartWidget.h
@@ -0,0 +1,61 @@
+// 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_FIRSTSTARTWIDGET_H
+#define FREECAD_FIRSTSTARTWIDGET_H
+
+#include
+#include
+
+class QLabel;
+class QPushButton;
+
+namespace StartGui
+{
+
+class ThemeSelectorWidget;
+class GeneralSettingsWidget;
+
+class FirstStartWidget: public QGroupBox
+{
+ Q_OBJECT
+public:
+ explicit FirstStartWidget(QWidget* parent = nullptr);
+ bool eventFilter(QObject* object, QEvent* event) override;
+
+private:
+ void retranslateUi();
+ void setupUi();
+ void doneClicked();
+
+ ThemeSelectorWidget* _themeSelectorWidget;
+ GeneralSettingsWidget* _generalSettingsWidget;
+
+ QLabel* _welcomeLabel;
+ QLabel* _descriptionLabel;
+ QPushButton* _doneButton;
+};
+
+} // namespace StartGui
+
+#endif // FREECAD_FIRSTSTARTWIDGET_H
diff --git a/src/Mod/Start/Gui/GeneralSettingsWidget.cpp b/src/Mod/Start/Gui/GeneralSettingsWidget.cpp
new file mode 100644
index 0000000000..72da566fd1
--- /dev/null
+++ b/src/Mod/Start/Gui/GeneralSettingsWidget.cpp
@@ -0,0 +1,238 @@
+// 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
+#endif
+
+#include "GeneralSettingsWidget.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace StartGui;
+
+GeneralSettingsWidget::GeneralSettingsWidget(QWidget* parent)
+ : QWidget(parent)
+ , _languageLabel {nullptr}
+ , _unitSystemLabel {nullptr}
+ , _navigationStyleLabel {nullptr}
+ , _languageComboBox {nullptr}
+ , _unitSystemComboBox {nullptr}
+ , _navigationStyleComboBox {nullptr}
+{
+ setObjectName(QLatin1String("GeneralSettingsWidget"));
+ setupUi();
+ qApp->installEventFilter(this);
+}
+
+void GeneralSettingsWidget::setupUi()
+{
+ if (layout()) {
+ qDeleteAll(findChildren(QString(), Qt::FindDirectChildrenOnly));
+ delete layout();
+ }
+ _languageLabel = gsl::owner(new QLabel);
+ _navigationStyleLabel = gsl::owner(new QLabel);
+ _unitSystemLabel = gsl::owner(new QLabel);
+ createLanguageComboBox();
+ createUnitSystemComboBox();
+ createNavigationStyleComboBox();
+ createHorizontalUi();
+ retranslateUi();
+}
+
+void GeneralSettingsWidget::createHorizontalUi()
+{
+ auto mainLayout = gsl::owner(new QHBoxLayout(this));
+ const int extraSpace {36};
+ mainLayout->addWidget(_languageLabel);
+ mainLayout->addWidget(_languageComboBox);
+ mainLayout->addSpacing(extraSpace);
+ mainLayout->addWidget(_unitSystemLabel);
+ mainLayout->addWidget(_unitSystemComboBox);
+ mainLayout->addSpacing(extraSpace);
+ mainLayout->addWidget(_navigationStyleLabel);
+ mainLayout->addWidget(_navigationStyleComboBox);
+}
+
+
+QString GeneralSettingsWidget::createLabelText(const QString& translatedText) const
+{
+ static const auto h2Start = QLatin1String("");
+ static const auto h2End = QLatin1String("
");
+ return h2Start + translatedText + h2End;
+}
+
+gsl::owner GeneralSettingsWidget::createLanguageComboBox()
+{
+ ParameterGrp::handle hGrp =
+ App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General");
+ auto langToStr = Gui::Translator::instance()->activeLanguage();
+ QByteArray language = hGrp->GetASCII("Language", langToStr.c_str()).c_str();
+ auto comboBox = gsl::owner(new QComboBox);
+ comboBox->addItem(QString::fromLatin1("English"), QByteArray("English"));
+ Gui::TStringMap list = Gui::Translator::instance()->supportedLocales();
+ int index {0};
+ for (auto it = list.begin(); it != list.end(); ++it, ++index) {
+ QByteArray lang = it->first.c_str();
+ QString langname = QString::fromLatin1(lang.constData());
+
+ if (it->second == "sr-CS") {
+ // Qt does not treat sr-CS (Serbian, Latin) as a Latin-script variant by default: this
+ // forces it to do so.
+ it->second = "sr_Latn";
+ }
+
+ QLocale locale(QString::fromLatin1(it->second.c_str()));
+ QString native = locale.nativeLanguageName();
+ if (!native.isEmpty()) {
+ if (native[0].isLetter()) {
+ native[0] = native[0].toUpper();
+ }
+ langname = native;
+ }
+
+ comboBox->addItem(langname, lang);
+ if (language == lang) {
+ comboBox->setCurrentIndex(index);
+ }
+ }
+ _languageComboBox = comboBox;
+ connect(_languageComboBox,
+ qOverload(&QComboBox::currentIndexChanged),
+ this,
+ &GeneralSettingsWidget::onLanguageChanged);
+ return comboBox;
+}
+
+gsl::owner GeneralSettingsWidget::createUnitSystemComboBox()
+{
+ // Contents are created in retranslateUi()
+ auto comboBox = gsl::owner(new QComboBox);
+ _unitSystemComboBox = comboBox;
+ connect(_unitSystemComboBox,
+ qOverload(&QComboBox::currentIndexChanged),
+ this,
+ &GeneralSettingsWidget::onUnitSystemChanged);
+ return comboBox;
+}
+
+gsl::owner GeneralSettingsWidget::createNavigationStyleComboBox()
+{
+ // Contents are created in retranslateUi()
+ auto comboBox = gsl::owner(new QComboBox);
+ _navigationStyleComboBox = comboBox;
+ connect(_navigationStyleComboBox,
+ qOverload(&QComboBox::currentIndexChanged),
+ this,
+ &GeneralSettingsWidget::onNavigationStyleChanged);
+ return comboBox;
+}
+
+void GeneralSettingsWidget::onLanguageChanged(int index)
+{
+ if (index < 0) {
+ return; // happens when clearing the combo box in retranslateUi()
+ }
+ Gui::Translator::instance()->activateLanguage(
+ _languageComboBox->itemData(index).toByteArray().data());
+ ParameterGrp::handle hGrp =
+ App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General");
+ auto langToStr = Gui::Translator::instance()->activeLanguage();
+ hGrp->SetASCII("Language", langToStr.c_str());
+}
+
+void GeneralSettingsWidget::onUnitSystemChanged(int index)
+{
+ if (index < 0) {
+ return; // happens when clearing the combo box in retranslateUi()
+ }
+ Base::UnitsApi::setSchema(static_cast(index));
+ ParameterGrp::handle hGrp =
+ App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units");
+ hGrp->SetInt("UserSchema", index);
+}
+
+void GeneralSettingsWidget::onNavigationStyleChanged(int index)
+{
+ if (index < 0) {
+ return; // happens when clearing the combo box in retranslateUi()
+ }
+ auto navStyleName = _navigationStyleComboBox->itemData(index).toByteArray().data();
+ ParameterGrp::handle hGrp =
+ App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
+ hGrp->SetASCII("NavigationStyle", navStyleName);
+}
+
+bool GeneralSettingsWidget::eventFilter(QObject* object, QEvent* event)
+{
+ if (object == this && event->type() == QEvent::LanguageChange) {
+ this->retranslateUi();
+ }
+ return QWidget::eventFilter(object, event);
+}
+
+void GeneralSettingsWidget::retranslateUi()
+{
+ _languageLabel->setText(createLabelText(tr("Language")));
+ _unitSystemLabel->setText(createLabelText(tr("Unit System")));
+
+ _unitSystemComboBox->clear();
+ ParameterGrp::handle hGrpUnits =
+ App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units");
+ auto userSchema = hGrpUnits->GetInt("UserSchema", 0);
+ int num = static_cast(Base::UnitSystem::NumUnitSystemTypes);
+ for (int i = 0; i < num; i++) {
+ QString item = Base::UnitsApi::getDescription(static_cast(i));
+ _unitSystemComboBox->addItem(item, i);
+ }
+ _unitSystemComboBox->setCurrentIndex(userSchema);
+
+ _navigationStyleLabel->setText(createLabelText(tr("Navigation Style")));
+ _navigationStyleComboBox->clear();
+ ParameterGrp::handle hGrpNav =
+ App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
+ auto navStyleName =
+ hGrpNav->GetASCII("NavigationStyle", Gui::CADNavigationStyle::getClassTypeId().getName());
+ std::map styles = Gui::UserNavigationStyle::getUserFriendlyNames();
+ for (const auto& style : styles) {
+ QByteArray data(style.first.getName());
+ QString name = QApplication::translate(style.first.getName(), style.second.c_str());
+ _navigationStyleComboBox->addItem(name, data);
+ if (navStyleName == style.first.getName()) {
+ _navigationStyleComboBox->setCurrentIndex(_navigationStyleComboBox->count() - 1);
+ }
+ }
+}
diff --git a/src/Mod/Start/Gui/GeneralSettingsWidget.h b/src/Mod/Start/Gui/GeneralSettingsWidget.h
new file mode 100644
index 0000000000..79aa0dea54
--- /dev/null
+++ b/src/Mod/Start/Gui/GeneralSettingsWidget.h
@@ -0,0 +1,72 @@
+// 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_START_GENERALSETTINGSWIDGET_H
+#define FREECAD_START_GENERALSETTINGSWIDGET_H
+
+#include
+#include <3rdParty/GSL/include/gsl/pointers>
+
+class QLabel;
+class QComboBox;
+
+namespace StartGui
+{
+
+class GeneralSettingsWidget: public QWidget
+{
+ Q_OBJECT
+public:
+ explicit GeneralSettingsWidget(QWidget* parent = nullptr);
+
+ bool eventFilter(QObject* object, QEvent* event) override;
+
+private:
+ void retranslateUi();
+
+ void setupUi();
+ void createHorizontalUi();
+
+ QString createLabelText(const QString& translatedText) const;
+ gsl::owner createLanguageComboBox();
+ gsl::owner createUnitSystemComboBox();
+ gsl::owner createNavigationStyleComboBox();
+
+ void onLanguageChanged(int index);
+ void onUnitSystemChanged(int index);
+ void onNavigationStyleChanged(int index);
+
+ Qt::Orientation _orientation;
+
+ // Non-owning pointers to things that need to be re-translated when the language changes
+ QLabel* _languageLabel;
+ QLabel* _unitSystemLabel;
+ QLabel* _navigationStyleLabel;
+ QComboBox* _languageComboBox;
+ QComboBox* _unitSystemComboBox;
+ QComboBox* _navigationStyleComboBox;
+};
+
+} // namespace StartGui
+
+#endif // FREECAD_START_GENERALSETTINGSWIDGET_H
diff --git a/src/Mod/Start/Gui/PreCompiled.h b/src/Mod/Start/Gui/PreCompiled.h
index 11cc15a39d..86c1f0884f 100644
--- a/src/Mod/Start/Gui/PreCompiled.h
+++ b/src/Mod/Start/Gui/PreCompiled.h
@@ -44,22 +44,28 @@
// Qt
#include
+#include
#include
+#include
+#include
#include
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/Mod/Start/Gui/Resources/Start.qrc b/src/Mod/Start/Gui/Resources/Start.qrc
index 0104840591..bb09223edc 100644
--- a/src/Mod/Start/Gui/Resources/Start.qrc
+++ b/src/Mod/Start/Gui/Resources/Start.qrc
@@ -2,5 +2,8 @@
icons/StartCommandIcon.svg
icons/PartDesignWorkbench.svg
+ thumbnails/Classic512.png
+ thumbnails/OpenLight512.png
+ thumbnails/OpenDark512.png
diff --git a/src/Mod/Start/Gui/Resources/thumbnails/Classic512.png b/src/Mod/Start/Gui/Resources/thumbnails/Classic512.png
new file mode 100644
index 0000000000..367c5159da
Binary files /dev/null and b/src/Mod/Start/Gui/Resources/thumbnails/Classic512.png differ
diff --git a/src/Mod/Start/Gui/Resources/thumbnails/OpenDark512.png b/src/Mod/Start/Gui/Resources/thumbnails/OpenDark512.png
new file mode 100644
index 0000000000..3dfef600a2
Binary files /dev/null and b/src/Mod/Start/Gui/Resources/thumbnails/OpenDark512.png differ
diff --git a/src/Mod/Start/Gui/Resources/thumbnails/OpenLight512.png b/src/Mod/Start/Gui/Resources/thumbnails/OpenLight512.png
new file mode 100644
index 0000000000..9d659d267c
Binary files /dev/null and b/src/Mod/Start/Gui/Resources/thumbnails/OpenLight512.png differ
diff --git a/src/Mod/Start/Gui/StartView.cpp b/src/Mod/Start/Gui/StartView.cpp
index ed2d0f48b1..7adeda064c 100644
--- a/src/Mod/Start/Gui/StartView.cpp
+++ b/src/Mod/Start/Gui/StartView.cpp
@@ -37,6 +37,7 @@
#include "StartView.h"
#include "FileCardDelegate.h"
#include "FileCardView.h"
+#include "FirstStartWidget.h"
#include "FlowLayout.h"
#include "Gui/Workbench.h"
#include
@@ -99,6 +100,11 @@ gsl::owner createNewButton(const NewButton& newButton)
StartView::StartView(Gui::Document* pcDocument, QWidget* parent)
: Gui::MDIView(pcDocument, parent)
, _contents(new QScrollArea(parent))
+ , _newFileLabel {nullptr}
+ , _examplesLabel {nullptr}
+ , _recentFilesLabel {nullptr}
+ , _showOnStartupCheckBox {nullptr}
+ , _rewriteLabel {nullptr}
{
setObjectName(QLatin1String("StartView"));
auto hGrp = App::GetApplication().GetParameterGroupByPath(
@@ -114,44 +120,42 @@ StartView::StartView(Gui::Document* pcDocument, QWidget* parent)
layout->setSizeConstraint(QLayout::SizeConstraint::SetMinAndMaxSize);
// New WB notice: temporary to explain why all your setting disappeared
- auto newStartWBNotice = gsl::owner(
- new QLabel(tr("NOTE: The Start Workbench has been completely rewritten to remove all "
- "network access, and to remove its dependency on Chromium. This is still a "
- "work-in-progress, and not all settings from the previous version of Start "
- "have been migrated yet.")));
- newStartWBNotice->setWordWrap(true);
- layout->addWidget(newStartWBNotice);
+ _rewriteLabel = gsl::owner(new QLabel());
+ _rewriteLabel->setWordWrap(true);
+ layout->addWidget(_rewriteLabel);
// Launch start automatically?
- QString application = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
- auto launchAutomaticallyCheckbox =
- gsl::owner(new QCheckBox(tr("Show Start when starting %1").arg(application)));
+ _showOnStartupCheckBox = gsl::owner(new QCheckBox());
bool showOnStartup = hGrp->GetBool("ShowOnStartup", true);
- launchAutomaticallyCheckbox->setCheckState(showOnStartup ? Qt::CheckState::Checked
- : Qt::CheckState::Unchecked);
- connect(launchAutomaticallyCheckbox,
- &QCheckBox::toggled,
- this,
- &StartView::showOnStartupChanged);
- layout->addWidget(launchAutomaticallyCheckbox);
+ _showOnStartupCheckBox->setCheckState(showOnStartup ? Qt::CheckState::Checked
+ : Qt::CheckState::Unchecked);
+ connect(_showOnStartupCheckBox, &QCheckBox::toggled, this, &StartView::showOnStartupChanged);
+ layout->addWidget(_showOnStartupCheckBox);
- const QLatin1String h1Start("");
- const QLatin1String h1End("
");
+ auto firstStart = hGrp->GetBool("FirstStart2024", true); // NOLINT
+ if (firstStart) {
+ auto firstStartRegion = gsl::owner(new QHBoxLayout);
+ firstStartRegion->addStretch();
+ auto firstStartWidget = gsl::owner(new FirstStartWidget(this));
+ firstStartRegion->addWidget(firstStartWidget);
+ firstStartRegion->addStretch();
+ layout->addLayout(firstStartRegion);
+ }
- auto newFileLabel = gsl::owner(new QLabel(h1Start + tr("New File") + h1End));
- layout->addWidget(newFileLabel);
+ _newFileLabel = gsl::owner(new QLabel());
+ layout->addWidget(_newFileLabel);
auto flowLayout = gsl::owner(new FlowLayout);
layout->addLayout(flowLayout);
configureNewFileButtons(flowLayout);
- auto recentFilesLabel = gsl::owner(new QLabel(h1Start + tr("Recent Files") + h1End));
- layout->addWidget(recentFilesLabel);
+ _recentFilesLabel = gsl::owner(new QLabel());
+ layout->addWidget(_recentFilesLabel);
auto recentFilesListWidget = gsl::owner(new FileCardView(_contents));
connect(recentFilesListWidget, &QListView::clicked, this, &StartView::fileCardSelected);
layout->addWidget(recentFilesListWidget);
- auto examplesLabel = gsl::owner(new QLabel(h1Start + tr("Examples") + h1End));
- layout->addWidget(examplesLabel);
+ _examplesLabel = gsl::owner(new QLabel());
+ layout->addWidget(_examplesLabel);
auto examplesListWidget = gsl::owner(new FileCardView(_contents));
connect(examplesListWidget, &QListView::clicked, this, &StartView::fileCardSelected);
layout->addWidget(examplesListWidget);
@@ -161,11 +165,10 @@ StartView::StartView(Gui::Document* pcDocument, QWidget* parent)
setCentralWidget(_contents);
- QString title = QCoreApplication::translate("Workbench", "Start");
- setWindowTitle(title);
-
configureExamplesListWidget(examplesListWidget);
- configureRecentFilesListWidget(recentFilesListWidget, recentFilesLabel);
+ configureRecentFilesListWidget(recentFilesListWidget, _recentFilesLabel);
+
+ retranslateUi();
}
void StartView::configureNewFileButtons(QLayout* layout) const
@@ -202,7 +205,6 @@ void StartView::configureNewFileButtons(QLayout* layout) const
}
// TODO: Ensure all of the required WBs are actually available
- // TODO: Make this layout more flexible (e.g. use a single line if possible)
layout->addWidget(partDesign);
layout->addWidget(assembly);
layout->addWidget(draft);
@@ -406,3 +408,33 @@ void StartView::showOnStartupChanged(bool checked)
"User parameter:BaseApp/Preferences/Mod/Start");
hGrp->SetBool("ShowOnStartup", checked);
}
+
+void StartView::changeEvent(QEvent* event)
+{
+ if (event->type() == QEvent::LanguageChange) {
+ this->retranslateUi();
+ }
+ Gui::MDIView::changeEvent(event);
+}
+
+void StartView::retranslateUi()
+{
+ QString title = QCoreApplication::translate("Workbench", "Start");
+ setWindowTitle(title);
+
+ const QLatin1String h1Start("");
+ const QLatin1String h1End("
");
+
+ _newFileLabel->setText(h1Start + tr("New File") + h1End);
+ _examplesLabel->setText(h1Start + tr("Examples") + h1End);
+ _recentFilesLabel->setText(h1Start + tr("Recent Files") + h1End);
+
+ QString application = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
+ _showOnStartupCheckBox->setText(tr("Show this view when starting %1").arg(application));
+
+ _rewriteLabel->setText(
+ tr("NOTE: The Start Workbench has been completely rewritten to remove all "
+ "network access, and to remove its dependency on Chromium. This is still a "
+ "work-in-progress, and not all settings from the previous version of Start "
+ "have been migrated yet."));
+}
diff --git a/src/Mod/Start/Gui/StartView.h b/src/Mod/Start/Gui/StartView.h
index 8f9439c2ad..4ff41f7cf0 100644
--- a/src/Mod/Start/Gui/StartView.h
+++ b/src/Mod/Start/Gui/StartView.h
@@ -32,10 +32,11 @@
#include "../App/RecentFilesModel.h"
#include "../App/ExamplesModel.h"
-
+class QCheckBox;
+class QEvent;
+class QGridLayout;
class QLabel;
class QListView;
-class QGridLayout;
class QScrollArea;
namespace Gui
@@ -75,6 +76,8 @@ public:
};
protected:
+ void changeEvent(QEvent* e) override;
+
void configureNewFileButtons(QLayout* layout) const;
static void configureFileCardWidget(QListView* fileCardWidget);
void configureRecentFilesListWidget(QListView* recentFilesListWidget, QLabel* recentFilesLabel);
@@ -88,10 +91,18 @@ protected:
QString fileCardStyle() const;
private:
+ void retranslateUi();
+
QScrollArea* _contents = nullptr;
Start::RecentFilesModel _recentFilesModel;
Start::ExamplesModel _examplesModel;
+ QLabel* _newFileLabel;
+ QLabel* _examplesLabel;
+ QLabel* _recentFilesLabel;
+ QCheckBox* _showOnStartupCheckBox;
+ QLabel* _rewriteLabel;
+
}; // namespace StartGui
diff --git a/src/Mod/Start/Gui/ThemeSelectorWidget.cpp b/src/Mod/Start/Gui/ThemeSelectorWidget.cpp
new file mode 100644
index 0000000000..7226659a9e
--- /dev/null
+++ b/src/Mod/Start/Gui/ThemeSelectorWidget.cpp
@@ -0,0 +1,142 @@
+// 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
+#endif
+
+#include "ThemeSelectorWidget.h"
+#include <3rdParty/GSL/include/gsl/pointers>
+#include
+#include
+#include
+
+using namespace StartGui;
+
+ThemeSelectorWidget::ThemeSelectorWidget(QWidget* parent)
+ : QWidget(parent)
+ , _titleLabel {nullptr}
+ , _descriptionLabel {nullptr}
+ , _buttons {nullptr, nullptr, nullptr}
+{
+ setObjectName(QLatin1String("ThemeSelectorWidget"));
+ setupUi();
+ qApp->installEventFilter(this);
+}
+
+
+void ThemeSelectorWidget::setupButtons(QBoxLayout* layout)
+{
+ if (!layout) {
+ return;
+ }
+ std::map themeMap {{Theme::Classic, tr("Classic")},
+ {Theme::Light, tr("Light")},
+ {Theme::Dark, tr("Dark")}};
+ std::map iconMap {
+ {Theme::Classic, QIcon(QLatin1String(":/thumbnails/Classic512.png"))},
+ {Theme::Light, QIcon(QLatin1String(":/thumbnails/OpenLight512.png"))},
+ {Theme::Dark, QIcon(QLatin1String(":/thumbnails/OpenDark512.png"))}};
+ auto hGrp = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/MainWindow");
+ auto styleSheetName = QString::fromStdString(hGrp->GetASCII("StyleSheet"));
+ for (const auto& theme : themeMap) {
+ auto button = gsl::owner(new QToolButton());
+ button->setCheckable(true);
+ button->setAutoExclusive(true);
+ button->setToolButtonStyle(Qt::ToolButtonStyle::ToolButtonTextUnderIcon);
+ button->setText(theme.second);
+ button->setIcon(iconMap[theme.first]);
+ button->setIconSize(iconMap[theme.first].actualSize(QSize(256, 256)));
+ if (theme.first == Theme::Classic && styleSheetName.isEmpty()) {
+ button->setChecked(true);
+ }
+ else if (theme.first == Theme::Light
+ && styleSheetName.contains(QLatin1String("light"),
+ Qt::CaseSensitivity::CaseInsensitive)) {
+ button->setChecked(true);
+ }
+ else if (theme.first == Theme::Dark
+ && styleSheetName.contains(QLatin1String("dark"),
+ Qt::CaseSensitivity::CaseInsensitive)) {
+ button->setChecked(true);
+ }
+ connect(button, &QToolButton::clicked, this, [this, theme] {
+ themeChanged(theme.first);
+ });
+ layout->addWidget(button);
+ _buttons[static_cast(theme.first)] = button;
+ }
+}
+
+void ThemeSelectorWidget::setupUi()
+{
+ auto* outerLayout = gsl::owner(new QVBoxLayout(this));
+ auto* buttonLayout = gsl::owner(new QHBoxLayout);
+ _titleLabel = gsl::owner(new QLabel);
+ _descriptionLabel = gsl::owner(new QLabel);
+ outerLayout->addWidget(_titleLabel);
+ outerLayout->addWidget(_descriptionLabel);
+ outerLayout->addLayout(buttonLayout);
+ setupButtons(buttonLayout);
+ retranslateUi();
+}
+
+void ThemeSelectorWidget::themeChanged(Theme newTheme)
+{
+ // Run the appropriate preference pack:
+ auto prefPackManager = Gui::Application::Instance->prefPackManager();
+ switch (newTheme) {
+ case Theme::Classic:
+ prefPackManager->apply("Classic");
+ break;
+ case Theme::Dark:
+ prefPackManager->apply("Dark");
+ break;
+ case Theme::Light:
+ prefPackManager->apply("Light");
+ break;
+ }
+}
+
+bool ThemeSelectorWidget::eventFilter(QObject* object, QEvent* event)
+{
+ if (object == this && event->type() == QEvent::LanguageChange) {
+ this->retranslateUi();
+ }
+ return QWidget::eventFilter(object, event);
+}
+
+void ThemeSelectorWidget::retranslateUi()
+{
+ _titleLabel->setText(QLatin1String("") + tr("Theme") + QLatin1String("
"));
+ _descriptionLabel->setText(tr("More themes are available online using the Addon Manager"));
+ _buttons[static_cast(Theme::Classic)]->setText(tr("Classic", "Visual theme name"));
+ _buttons[static_cast(Theme::Light)]->setText(tr("Light", "Visual theme name"));
+ _buttons[static_cast(Theme::Dark)]->setText(tr("Dark", "Visual theme name"));
+}
diff --git a/src/Mod/Start/Gui/ThemeSelectorWidget.h b/src/Mod/Start/Gui/ThemeSelectorWidget.h
new file mode 100644
index 0000000000..f7d079f7ae
--- /dev/null
+++ b/src/Mod/Start/Gui/ThemeSelectorWidget.h
@@ -0,0 +1,67 @@
+// 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_START_THEMESELECTORWIDGET_H
+#define FREECAD_START_THEMESELECTORWIDGET_H
+
+#include
+#include
+
+class QBoxLayout;
+class QLabel;
+class QToolButton;
+
+namespace StartGui
+{
+
+enum class Theme
+{
+ Classic,
+ Light,
+ Dark
+};
+
+/// A widget to allow selection of the UI theme (color scheme).
+class ThemeSelectorWidget: public QWidget
+{
+ Q_OBJECT
+public:
+ explicit ThemeSelectorWidget(QWidget* parent = nullptr);
+ bool eventFilter(QObject* object, QEvent* event) override;
+
+protected:
+ void themeChanged(Theme newTheme);
+
+private:
+ void retranslateUi();
+ void setupUi();
+ void setupButtons(QBoxLayout* layout);
+
+ QLabel* _titleLabel;
+ QLabel* _descriptionLabel;
+ std::array _buttons;
+};
+
+} // namespace StartGui
+
+#endif // FREECAD_START_THEMESELECTORWIDGET_H
diff --git a/tests/src/Mod/Sketcher/App/planegcs/Constraints.cpp b/tests/src/Mod/Sketcher/App/planegcs/Constraints.cpp
index 105cb20df5..e113732b86 100644
--- a/tests/src/Mod/Sketcher/App/planegcs/Constraints.cpp
+++ b/tests/src/Mod/Sketcher/App/planegcs/Constraints.cpp
@@ -1,8 +1,5 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
-#ifdef WIN32
-#define _USE_MATH_DEFINES
-#endif
#include
#include "gtest/gtest.h"