File indexing completed on 2024-05-05 04:46:59
0001 /* 0002 * <one line to give the program's name and a brief idea of what it does.> 0003 * Copyright (C) 2019 camilo <chiguitar@unal.edu.co> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 */ 0018 0019 #include "mauiapp.h" 0020 #include "fmh.h" 0021 #include "style.h" 0022 0023 #include <QDir> 0024 #include <QStandardPaths> 0025 #include <QQuickWindow> 0026 #include <QQuickItem> 0027 #include <QWindow> 0028 0029 #include <KLocalizedString> 0030 #include <KCoreAddons> 0031 0032 #if defined BUNDLE_LUV_ICONS 0033 #include <QIcon> 0034 #endif 0035 0036 #include <QQuickStyle> 0037 0038 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0039 #include <MauiMan3/thememanager.h> 0040 #else 0041 #include <MauiMan4/thememanager.h> 0042 #endif 0043 0044 #include "../mauikit_version.h" 0045 #include "moduleinfo.h" 0046 0047 MauiApp *MauiApp::m_instance = nullptr; 0048 0049 KAboutComponent MauiApp::aboutMauiKit() 0050 { 0051 return KAboutComponent("MauiKit", i18n("Multi-adaptable user interfaces."), MauiApp::getMauikitVersion(), "https://mauikit.org", KAboutLicense::GPL_V3); 0052 } 0053 0054 MauiApp::MauiApp() 0055 : QObject(nullptr) 0056 , m_themeSettings( new MauiMan::ThemeManager(this)) 0057 , m_controls(new CSDControls(this)) 0058 { 0059 qDebug() << "CREATING INSTANCE OF MAUI APP"; 0060 connect(qApp, &QCoreApplication::aboutToQuit, []() 0061 { 0062 qDebug() << "Lets remove MauiApp singleton instance"; 0063 delete m_instance; 0064 m_instance = nullptr; 0065 }); 0066 0067 KAboutData aboutData(KAboutData::applicationData()); 0068 if (aboutData.translators().isEmpty()) 0069 { 0070 aboutData.setTranslator(i18ndc(nullptr, "NAME OF TRANSLATORS", "Your names"), // 0071 i18ndc(nullptr, "EMAIL OF TRANSLATORS", "Your emails")); 0072 0073 } 0074 0075 const auto MauiData = MauiKitCore::aboutData(); 0076 aboutData.addComponent(MauiData.name(), 0077 MauiKitCore::buildVersion(), 0078 MauiData.version(), 0079 MauiData.webAddress(), 0080 MauiData.license().key()); 0081 0082 aboutData.addComponent("Qt", "", QT_VERSION_STR, "https://qt.io"); 0083 0084 aboutData.addComponent(QStringLiteral("KDE Frameworks"), "", KCoreAddons::versionString(), "https://kde.org"); 0085 0086 0087 #if defined BUNDLE_LUV_ICONS 0088 const auto luvData = MauiKitCore::aboutLuv(); 0089 aboutData.addComponent(luvData.name(), 0090 "", 0091 luvData.version(), 0092 luvData.webAddress(), 0093 luvData.license().key()); 0094 #endif 0095 0096 KAboutData::setApplicationData(aboutData); 0097 setDefaultMauiStyle(); 0098 } 0099 0100 QString MauiApp::getMauikitVersion() 0101 { 0102 return MAUIKIT_VERSION_STRING; 0103 } 0104 0105 QString MauiApp::getIconName() const 0106 { 0107 return m_iconName; 0108 } 0109 0110 void MauiApp::setIconName(const QString &value) 0111 { 0112 if (m_iconName == value) 0113 return; 0114 0115 m_iconName = value; 0116 Q_EMIT this->iconNameChanged(); 0117 } 0118 0119 QString MauiApp::getDonationPage() const 0120 { 0121 return m_donationPage; 0122 } 0123 0124 void MauiApp::setDonationPage(const QString &value) 0125 { 0126 if (m_donationPage == value) 0127 return; 0128 0129 m_donationPage = value; 0130 Q_EMIT this->donationPageChanged(); 0131 } 0132 0133 KAboutData MauiApp::getAbout() const 0134 { 0135 return KAboutData::applicationData(); 0136 } 0137 0138 void MauiApp::setDefaultMauiStyle() 0139 { 0140 #if defined BUNDLE_LUV_ICONS 0141 Q_INIT_RESOURCE(icons); 0142 QIcon::setThemeSearchPaths({":/icons/luv-icon-theme"}); 0143 QIcon::setThemeName("Luv"); 0144 #endif 0145 0146 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0147 QQuickStyle::setStyle("maui-style"); 0148 #else 0149 QQuickStyle::setStyle(QStringLiteral("QtQuick.Controls.Maui")); 0150 #endif 0151 } 0152 0153 MauiApp *MauiApp::qmlAttachedProperties(QObject *object) 0154 { 0155 Q_UNUSED(object) 0156 return MauiApp::instance(); 0157 } 0158 0159 CSDControls::CSDControls(QObject *parent) : QObject (parent) 0160 ,m_themeSettings( new MauiMan::ThemeManager(this)) 0161 { 0162 connect(m_themeSettings, &MauiMan::ThemeManager::enableCSDChanged, [this](bool enabled) 0163 { 0164 qDebug() << "CSD ENABLED CHANGED<<<<" << enabled; 0165 0166 getWindowControlsSettings(); 0167 }); 0168 0169 connect(m_themeSettings, &MauiMan::ThemeManager::windowControlsThemeChanged, [this](QString style) 0170 { 0171 m_styleName = style; 0172 setStyle(); 0173 0174 Q_EMIT styleNameChanged(); 0175 Q_EMIT sourceChanged(); 0176 }); 0177 0178 getWindowControlsSettings(); 0179 } 0180 0181 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0182 0183 static QString CSDLookupPath = "org.mauikit.controls/csd.5/%1/config.conf"; 0184 #else 0185 static QString CSDLookupPath = "org.mauikit.controls/csd.6/%1/config.conf"; 0186 #endif 0187 0188 void CSDControls::setStyle() 0189 { 0190 auto confFile = QStandardPaths::locate (QStandardPaths::GenericDataLocation, QString(CSDLookupPath).arg(m_styleName)); 0191 QFileInfo file(confFile); 0192 if(file.exists ()) 0193 { 0194 const auto dir = QUrl::fromLocalFile (file.dir ().absolutePath ()); 0195 0196 QSettings conf (confFile, QSettings::IniFormat); 0197 conf.beginGroup ("Decoration"); 0198 m_source = dir.toString()+"/"+ conf.value("Source").toString(); 0199 conf.endGroup (); 0200 } 0201 0202 qDebug() << "CSD QML SOURCXE" << m_source; 0203 m_rightWindowControls = QStringList {"I", "A", "X"}; 0204 } 0205 0206 void CSDControls::getWindowControlsSettings() 0207 { 0208 if(m_enabledCSD_blocked) 0209 return; 0210 0211 m_enableCSD = m_themeSettings->enableCSD(); 0212 Q_EMIT enableCSDChanged(); 0213 0214 /* #if (defined Q_OS_LINUX || defined Q_OS_FREEBSD) && !defined Q_OS_ANDROID 0215 0216 #ifdef FORMFACTOR_FOUND 0217 0218 if(m_formFactor->preferredMode() == 0) 0219 { 0220 m_enableCSD = m_themeSettings->enableCSD(); 0221 Q_EMIT enableCSDChanged(); 0222 0223 }else 0224 { 0225 m_enableCSD = false; 0226 Q_EMIT enableCSDChanged(); 0227 return; 0228 } 0229 #else //Fallback in case FormFactor is not found. and then check for the env var QT_QUICK_CONTROLS_MOBILE 0230 if (qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_MOBILE")) 0231 { 0232 if (QByteArrayList {"0", "false"}.contains(qgetenv("QT_QUICK_CONTROLS_MOBILE"))) 0233 { 0234 m_enableCSD = m_themeSettings->enableCSD(); 0235 Q_EMIT enableCSDChanged(); 0236 }else 0237 { 0238 return; 0239 } 0240 } 0241 #endif */ 0242 0243 m_styleName = m_themeSettings->windowControlsTheme(); 0244 setStyle(); 0245 } 0246 0247 bool CSDControls::enableCSD() const 0248 { 0249 return m_enableCSD; 0250 } 0251 0252 void CSDControls::setEnableCSD(const bool &value) 0253 { 0254 m_enabledCSD_blocked = true; 0255 if (m_enableCSD == value) 0256 return; 0257 0258 m_enableCSD = value; 0259 Q_EMIT enableCSDChanged(); 0260 } 0261 0262 void CSDControls::resetEnableCSD() 0263 { 0264 m_enabledCSD_blocked = false; 0265 getWindowControlsSettings(); 0266 } 0267 0268 QUrl CSDControls::source() const 0269 { 0270 return m_source; 0271 } 0272 0273 QString CSDControls::styleName() const 0274 { 0275 return m_styleName; 0276 } 0277 0278 CSDButton::CSDButton(QObject *parent): QObject(parent) 0279 { 0280 connect(this, &CSDButton::typeChanged, this, &CSDButton::setSources); 0281 // connect(this, &CSDButton::styleChanged, this, &CSDButton::setSources); 0282 connect(this, &CSDButton::stateChanged, this, &CSDButton::requestCurrentSource); 0283 // connect(MauiApp::instance()->controls(), &CSDControls::styleNameChanged, this, &CSDButton::setSources); 0284 0285 m_style = MauiApp::instance()->controls()->styleName(); 0286 setSources(); 0287 } 0288 0289 void CSDButton::setStyle(const QString& style) 0290 { 0291 if(m_style == style) 0292 { 0293 return; 0294 } 0295 0296 m_style = style; 0297 Q_EMIT styleChanged(); 0298 } 0299 0300 QString CSDButton::style() const 0301 { 0302 return m_style; 0303 } 0304 0305 QUrl CSDButton::source() const 0306 { 0307 return m_source; 0308 } 0309 0310 void CSDButton::setSources() 0311 { 0312 const auto confFile = QStandardPaths::locate (QStandardPaths::GenericDataLocation, QString(CSDLookupPath).arg(m_style)); 0313 0314 QFileInfo file(confFile); 0315 if(file.exists ()) 0316 { 0317 m_dir = QUrl::fromLocalFile (file.dir ().absolutePath ()); 0318 QSettings conf (confFile, QSettings::IniFormat); 0319 m_sources.insert (CSDButtonState::Normal, extractStateValue (conf, CSDButtonState::Normal)); 0320 m_sources.insert (CSDButtonState::Hover, extractStateValue (conf, CSDButtonState::Hover)); 0321 m_sources.insert (CSDButtonState::Pressed, extractStateValue (conf, CSDButtonState::Pressed)); 0322 m_sources.insert (CSDButtonState::Backdrop, extractStateValue (conf, CSDButtonState::Backdrop)); 0323 m_sources.insert (CSDButtonState::Disabled, extractStateValue (conf, CSDButtonState::Disabled)); 0324 } 0325 0326 this->requestCurrentSource (); 0327 } 0328 0329 CSDButton::CSDButtonState CSDButton::state() const 0330 { 0331 return m_state; 0332 } 0333 0334 QUrl CSDButton::extractStateValue(QSettings &settings, const CSDButton::CSDButtonState &state) 0335 { 0336 QUrl res; 0337 0338 settings.beginGroup (mapButtonType (m_type)); 0339 res = m_dir.toString ()+"/"+settings.value (mapButtonState (state)).toString (); 0340 settings.endGroup (); 0341 0342 if(QFile::exists (res.toLocalFile ())) 0343 { 0344 return res; 0345 }else 0346 { 0347 return QUrl("dialog-close"); //put here a fallback button 0348 } 0349 } 0350 0351 void CSDButton::requestCurrentSource() 0352 { 0353 m_source = this->m_sources.value (this->m_state); 0354 Q_EMIT this->sourceChanged (); 0355 } 0356 0357 QString CSDButton::mapButtonType(const CSDButtonType &type) 0358 { 0359 switch(type) 0360 { 0361 case Close: return "Close"; 0362 case Maximize: return "Maximize"; 0363 case Minimize: return "Minimize"; 0364 case Restore: return "Restore"; 0365 case Fullscreen: return "Fullscreen"; 0366 default: return ""; 0367 } 0368 } 0369 0370 QString CSDButton::mapButtonState(const CSDButtonState &type) 0371 { 0372 switch(type) 0373 { 0374 case Normal: return "Normal"; 0375 case Hover: return "Hover"; 0376 case Pressed: return "Pressed"; 0377 case Backdrop: return "Backdrop"; 0378 case Disabled: return "Disabled"; 0379 default: return ""; 0380 } 0381 } 0382 0383 void CSDButton::setState(const CSDButtonState &newState) 0384 { 0385 if (m_state == newState) 0386 return; 0387 m_state = newState; 0388 Q_EMIT stateChanged(); 0389 } 0390 0391 CSDControls *MauiApp::controls() const 0392 { 0393 return m_controls; 0394 } 0395 0396 CSDButton::CSDButtonType CSDButton::type() const 0397 { 0398 return m_type; 0399 } 0400 0401 void CSDButton::setType(CSDButtonType newType) 0402 { 0403 if (m_type == newType) 0404 return; 0405 0406 m_type = newType; 0407 Q_EMIT typeChanged(); 0408 } 0409 0410 CSDButton::CSDButtonType CSDButton::mapType(const QString &value) 0411 { 0412 if(value == "X") return CSDButton::CSDButtonType::Close; 0413 if(value == "I") return CSDButton::CSDButtonType::Minimize; 0414 if(value == "A") return CSDButton::CSDButtonType::Maximize; 0415 0416 return CSDButtonType::None; 0417 } 0418 0419 bool CSDButton::isHovered() const 0420 { 0421 return m_isHovered; 0422 } 0423 0424 void CSDButton::setIsHovered(bool newIsHovered) 0425 { 0426 if (m_isHovered == newIsHovered) 0427 return; 0428 m_isHovered = newIsHovered; 0429 if(m_isHovered) 0430 { 0431 this->setState (CSDButtonState::Hover); 0432 }else 0433 { 0434 this->setState (m_isFocused ? CSDButtonState::Normal : CSDButtonState::Backdrop); 0435 } 0436 Q_EMIT isHoveredChanged(); 0437 } 0438 0439 bool CSDButton::isMaximized() const 0440 { 0441 return m_isMaximized; 0442 } 0443 0444 void CSDButton::setIsMaximized(bool newIsMaximized) 0445 { 0446 if (m_isMaximized == newIsMaximized) 0447 return; 0448 m_isMaximized = newIsMaximized; 0449 if(m_type == CSDButtonType::Maximize && m_isMaximized) 0450 { 0451 this->setType (CSDButtonType::Restore); 0452 }else if(m_type == CSDButtonType::Restore && !m_isMaximized) 0453 { 0454 this->setType (CSDButtonType::Maximize); 0455 } 0456 Q_EMIT isMaximizedChanged(); 0457 } 0458 0459 bool CSDButton::isPressed() const 0460 { 0461 return m_isPressed; 0462 } 0463 0464 void CSDButton::setIsPressed(bool newIsPressed) 0465 { 0466 if (m_isPressed == newIsPressed) 0467 return; 0468 m_isPressed = newIsPressed; 0469 if(m_isPressed) 0470 { 0471 this->setState (CSDButtonState::Pressed); 0472 }else 0473 { 0474 this->setState (CSDButtonState::Normal); 0475 } 0476 Q_EMIT isPressedChanged(); 0477 } 0478 0479 bool CSDButton::isFocused() const 0480 { 0481 return m_isFocused; 0482 } 0483 0484 void CSDButton::setIsFocused(bool newIsFocused) 0485 { 0486 if (m_isFocused == newIsFocused) 0487 return; 0488 m_isFocused = newIsFocused; 0489 0490 if(m_isFocused) 0491 { 0492 this->setState (CSDButtonState::Normal); 0493 } 0494 else 0495 { 0496 this->setState (CSDButtonState::Backdrop); 0497 } 0498 Q_EMIT isFocusedChanged(); 0499 }