1
// SPDX-License-Identifier: LGPL-2.1-or-later
2
/****************************************************************************
4
* Copyright (c) 2024 The FreeCAD Project Association AISBL *
6
* This file is part of FreeCAD. *
8
* FreeCAD is free software: you can redistribute it and/or modify it *
9
* under the terms of the GNU Lesser General Public License as *
10
* published by the Free Software Foundation, either version 2.1 of the *
11
* License, or (at your option) any later version. *
13
* FreeCAD is distributed in the hope that it will be useful, but *
14
* WITHOUT ANY WARRANTY; without even the implied warranty of *
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16
* Lesser General Public License for more details. *
18
* You should have received a copy of the GNU Lesser General Public *
19
* License along with FreeCAD. If not, see *
20
* <https://www.gnu.org/licenses/>. *
22
***************************************************************************/
24
#include "PreCompiled.h"
26
#include <QGuiApplication>
33
#include "ThemeSelectorWidget.h"
34
#include <gsl/pointers>
35
#include <App/Application.h>
36
#include <Gui/Command.h>
37
#include <Gui/PreferencePackManager.h>
39
using namespace StartGui;
41
ThemeSelectorWidget::ThemeSelectorWidget(QWidget* parent)
43
, _titleLabel {nullptr}
44
, _descriptionLabel {nullptr}
45
, _buttons {nullptr, nullptr, nullptr}
47
setObjectName(QLatin1String("ThemeSelectorWidget"));
49
qApp->installEventFilter(this);
53
void ThemeSelectorWidget::setupButtons(QBoxLayout* layout)
58
std::map<Theme, QString> themeMap {{Theme::Classic, tr("FreeCAD Classic")},
59
{Theme::Dark, tr("FreeCAD Dark")},
60
{Theme::Light, tr("FreeCAD Light")}};
61
std::map<Theme, QIcon> iconMap {
62
{Theme::Classic, QIcon(QLatin1String(":/thumbnails/Theme_thumbnail_classic.png"))},
63
{Theme::Light, QIcon(QLatin1String(":/thumbnails/Theme_thumbnail_light.png"))},
64
{Theme::Dark, QIcon(QLatin1String(":/thumbnails/Theme_thumbnail_dark.png"))}};
65
auto hGrp = App::GetApplication().GetParameterGroupByPath(
66
"User parameter:BaseApp/Preferences/MainWindow");
67
auto styleSheetName = QString::fromStdString(hGrp->GetASCII("StyleSheet"));
68
for (const auto& theme : themeMap) {
69
auto button = gsl::owner<QToolButton*>(new QToolButton());
70
button->setCheckable(true);
71
button->setAutoExclusive(true);
72
button->setToolButtonStyle(Qt::ToolButtonStyle::ToolButtonTextUnderIcon);
73
button->setText(theme.second);
74
button->setIcon(iconMap[theme.first]);
75
button->setIconSize(iconMap[theme.first].actualSize(QSize(256, 256)));
76
if (theme.first == Theme::Classic && styleSheetName.isEmpty()) {
77
button->setChecked(true);
79
else if (theme.first == Theme::Light
80
&& styleSheetName.contains(QLatin1String("FreeCAD Light"),
81
Qt::CaseSensitivity::CaseInsensitive)) {
82
button->setChecked(true);
84
else if (theme.first == Theme::Dark
85
&& styleSheetName.contains(QLatin1String("FreeCAD Dark"),
86
Qt::CaseSensitivity::CaseInsensitive)) {
87
button->setChecked(true);
89
connect(button, &QToolButton::clicked, this, [this, theme] {
90
themeChanged(theme.first);
92
layout->addWidget(button);
93
_buttons[static_cast<int>(theme.first)] = button;
97
void ThemeSelectorWidget::setupUi()
99
auto* outerLayout = gsl::owner<QVBoxLayout*>(new QVBoxLayout(this));
100
auto* buttonLayout = gsl::owner<QHBoxLayout*>(new QHBoxLayout);
101
_titleLabel = gsl::owner<QLabel*>(new QLabel);
102
_descriptionLabel = gsl::owner<QLabel*>(new QLabel);
103
outerLayout->addWidget(_titleLabel);
104
outerLayout->addLayout(buttonLayout);
105
outerLayout->addWidget(_descriptionLabel);
106
setupButtons(buttonLayout);
108
connect(_descriptionLabel, &QLabel::linkActivated, this, &ThemeSelectorWidget::onLinkActivated);
111
void ThemeSelectorWidget::onLinkActivated(const QString& link)
113
auto const addonManagerLink = QStringLiteral("freecad:Std_AddonMgr");
115
if (link != addonManagerLink) {
119
// Set the user preferences to include only preference packs.
120
// This is a quick and dirty way to open Addon Manager with only themes.
122
App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Addons");
123
pref->SetInt("PackageTypeSelection", 3); // 3 stands for Preference Packs
124
pref->SetInt("StatusSelection", 0); // 0 stands for any installation status
126
Gui::Application::Instance->commandManager().runCommandByName("Std_AddonMgr");
129
void ThemeSelectorWidget::themeChanged(Theme newTheme)
131
// Run the appropriate preference pack:
132
auto prefPackManager = Gui::Application::Instance->prefPackManager();
135
prefPackManager->apply("FreeCAD Classic");
138
prefPackManager->apply("FreeCAD Dark");
141
prefPackManager->apply("FreeCAD Light");
144
ParameterGrp::handle hGrp =
145
App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Themes");
146
const unsigned long nonExistentColor = -1434171135;
147
const unsigned long defaultAccentColor = 1434171135;
148
unsigned long longAccentColor1 = hGrp->GetUnsigned("ThemeAccentColor1", nonExistentColor);
149
if (longAccentColor1 == nonExistentColor) {
150
hGrp->SetUnsigned("ThemeAccentColor1", defaultAccentColor);
151
hGrp->SetUnsigned("ThemeAccentColor2", defaultAccentColor);
152
hGrp->SetUnsigned("ThemeAccentColor3", defaultAccentColor);
156
bool ThemeSelectorWidget::eventFilter(QObject* object, QEvent* event)
158
if (object == this && event->type() == QEvent::LanguageChange) {
159
this->retranslateUi();
161
return QWidget::eventFilter(object, event);
164
void ThemeSelectorWidget::retranslateUi()
166
_titleLabel->setText(QLatin1String("<h2>") + tr("Theme") + QLatin1String("</h2>"));
167
_descriptionLabel->setText(tr("Looking for more themes? You can obtain them using "
168
"<a href=\"freecad:Std_AddonMgr\">Addon Manager</a>."));
169
_buttons[static_cast<int>(Theme::Dark)]->setText(tr("FreeCAD Dark", "Visual theme name"));
170
_buttons[static_cast<int>(Theme::Light)]->setText(tr("FreeCAD Light", "Visual theme name"));
171
_buttons[static_cast<int>(Theme::Classic)]->setText(tr("FreeCAD Classic", "Visual theme name"));