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"