├── README ├── docs ├── 76071_2.jpg ├── heic0506a.jpg ├── index.html ├── ksmoothdock.jpg └── opo0501a.jpg └── src ├── CMakeLists.txt ├── cmake_uninstall.cmake.in ├── ksd.ksmoothdock.desktop ├── main.cc ├── model ├── application_menu_config.cc ├── application_menu_config.h ├── application_menu_config_test.cc ├── config_helper.cc ├── config_helper.h ├── multi_dock_model.cc ├── multi_dock_model.h └── multi_dock_model_test.cc ├── utils ├── command_utils.h ├── draw_utils.h ├── font_utils.h ├── task_helper.cc ├── task_helper.h ├── wallpaper_helper.cc └── wallpaper_helper.h └── view ├── add_panel_dialog.cc ├── add_panel_dialog.h ├── add_panel_dialog.ui ├── add_panel_dialog_test.cc ├── appearance_settings_dialog.cc ├── appearance_settings_dialog.h ├── appearance_settings_dialog.ui ├── appearance_settings_dialog_test.cc ├── application_menu.cc ├── application_menu.h ├── application_menu_settings_dialog.cc ├── application_menu_settings_dialog.h ├── application_menu_settings_dialog.ui ├── application_menu_settings_dialog_test.cc ├── calendar.cc ├── calendar.h ├── clock.cc ├── clock.h ├── desktop_selector.cc ├── desktop_selector.h ├── desktop_selector_test.cc ├── dock_item.h ├── dock_panel.cc ├── dock_panel.h ├── dock_panel_test.cc ├── edit_launchers_dialog.cc ├── edit_launchers_dialog.h ├── edit_launchers_dialog.ui ├── edit_launchers_dialog_test.cc ├── icon_based_dock_item.cc ├── icon_based_dock_item.h ├── iconless_dock_item.cc ├── iconless_dock_item.h ├── multi_dock_view.cc ├── multi_dock_view.h ├── program.cc ├── program.h ├── separator.cc ├── separator.h ├── task_manager_settings_dialog.cc ├── task_manager_settings_dialog.h ├── task_manager_settings_dialog.ui ├── tooltip.cc ├── tooltip.h ├── wallpaper_settings_dialog.cc ├── wallpaper_settings_dialog.h └── wallpaper_settings_dialog.ui /README: -------------------------------------------------------------------------------- 1 | KSmoothDock is now DEPRECATED, please use Crystal Dock instead: https://github.com/dangvd/crystal-dock 2 | -------------------------------------------------------------------------------- /docs/76071_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangvd/ksmoothdock/d350b35ac2c6efc37d6a1be9c145bcde7ddbb0d8/docs/76071_2.jpg -------------------------------------------------------------------------------- /docs/heic0506a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangvd/ksmoothdock/d350b35ac2c6efc37d6a1be9c145bcde7ddbb0d8/docs/heic0506a.jpg -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | KSmoothDock - A cool desktop panel for KDE Plasma 5 6 | 7 | 27 | 28 | 29 | 30 |
31 | 32 |

KSmoothDock - A cool desktop panel for KDE Plasma 5

33 | 34 |

35 | 36 |

37 | 38 |

39 | KSmoothDock is a cool desktop panel with parabolic zooming effect for KDE Plasma 5, with the focus on smooth zooming effect and being simple and easy to use. 40 |

41 | 42 | 81 | 82 |
83 | 84 | 85 | -------------------------------------------------------------------------------- /docs/ksmoothdock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangvd/ksmoothdock/d350b35ac2c6efc37d6a1be9c145bcde7ddbb0d8/docs/ksmoothdock.jpg -------------------------------------------------------------------------------- /docs/opo0501a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangvd/ksmoothdock/d350b35ac2c6efc37d6a1be9c145bcde7ddbb0d8/docs/opo0501a.jpg -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(ksmoothdock) 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | add_compile_options(-Wall -Werror) 8 | add_definitions(-DQT_DEPRECATED_WARNINGS) 9 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 10 | set(CMAKE_AUTOMOC ON) 11 | set(CMAKE_AUTOUIC ON) 12 | 13 | find_package(ECM REQUIRED NO_MODULE) 14 | set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) 15 | 16 | find_package(Qt5 5.11 REQUIRED COMPONENTS DBus Gui Test Widgets) 17 | find_package(KF5 5.7 REQUIRED COMPONENTS Activities Config CoreAddons DBusAddons I18n 18 | IconThemes XmlGui WidgetsAddons WindowSystem) 19 | 20 | set(SRCS 21 | model/application_menu_config.cc 22 | model/config_helper.cc 23 | model/multi_dock_model.cc 24 | view/add_panel_dialog.cc 25 | view/appearance_settings_dialog.cc 26 | view/application_menu_settings_dialog.cc 27 | view/application_menu.cc 28 | view/calendar.cc 29 | view/clock.cc 30 | view/desktop_selector.cc 31 | view/dock_panel.cc 32 | view/edit_launchers_dialog.cc 33 | view/icon_based_dock_item.cc 34 | view/iconless_dock_item.cc 35 | view/multi_dock_view.cc 36 | view/program.cc 37 | view/separator.cc 38 | view/task_manager_settings_dialog.cc 39 | view/tooltip.cc 40 | view/wallpaper_settings_dialog.cc 41 | utils/task_helper.cc 42 | utils/wallpaper_helper.cc) 43 | add_library(ksmoothdock_lib ${SRCS}) 44 | 45 | set(LIBS Qt5::DBus Qt5::Gui Qt5::Widgets KF5::Activities KF5::ConfigCore KF5::ConfigGui 46 | KF5::CoreAddons KF5::DBusAddons KF5::I18n KF5::IconThemes KF5::XmlGui 47 | KF5::WidgetsAddons KF5::WindowSystem stdc++fs) 48 | target_link_libraries(ksmoothdock_lib ${LIBS}) 49 | 50 | add_executable(ksmoothdock main.cc) 51 | target_link_libraries(ksmoothdock ksmoothdock_lib ${LIBS}) 52 | 53 | # Install 54 | 55 | install(TARGETS ksmoothdock RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 56 | install(FILES ksd.ksmoothdock.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications) 57 | 58 | # Uninstall 59 | 60 | configure_file( 61 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" 62 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 63 | IMMEDIATE @ONLY) 64 | 65 | add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} 66 | -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 67 | 68 | # Test 69 | 70 | enable_testing() 71 | 72 | add_executable(appearance_settings_dialog_test 73 | view/appearance_settings_dialog_test.cc) 74 | target_link_libraries(appearance_settings_dialog_test 75 | Qt5::Test ksmoothdock_lib ${LIBS}) 76 | add_test(appearance_settings_dialog_test appearance_settings_dialog_test) 77 | 78 | add_executable(desktop_selector_test view/desktop_selector_test.cc) 79 | target_link_libraries(desktop_selector_test Qt5::Test ksmoothdock_lib ${LIBS}) 80 | add_test(desktop_selector_test desktop_selector_test) 81 | 82 | add_executable(edit_launchers_dialog_test view/edit_launchers_dialog_test.cc) 83 | target_link_libraries(edit_launchers_dialog_test Qt5::Test ksmoothdock_lib 84 | ${LIBS}) 85 | add_test(edit_launchers_dialog_test edit_launchers_dialog_test) 86 | 87 | add_executable(dock_panel_test view/dock_panel_test.cc) 88 | target_link_libraries(dock_panel_test Qt5::Test ksmoothdock_lib ${LIBS}) 89 | add_test(dock_panel_test dock_panel_test) 90 | 91 | add_executable(application_menu_config_test model/application_menu_config_test.cc) 92 | target_link_libraries(application_menu_config_test Qt5::Test ksmoothdock_lib ${LIBS}) 93 | add_test(application_menu_config_test application_menu_config_test) 94 | 95 | add_executable(add_panel_dialog_test view/add_panel_dialog_test.cc) 96 | target_link_libraries(add_panel_dialog_test Qt5::Test ksmoothdock_lib ${LIBS}) 97 | add_test(add_panel_dialog_test add_panel_dialog_test) 98 | 99 | add_executable(application_menu_settings_dialog_test 100 | view/application_menu_settings_dialog_test.cc) 101 | target_link_libraries(application_menu_settings_dialog_test 102 | Qt5::Test ksmoothdock_lib ${LIBS}) 103 | add_test(application_menu_settings_dialog_test 104 | application_menu_settings_dialog_test) 105 | 106 | add_executable(multi_dock_model_test model/multi_dock_model_test.cc) 107 | target_link_libraries(multi_dock_model_test Qt5::Test ksmoothdock_lib ${LIBS}) 108 | add_test(multi_dock_model_test multi_dock_model_test) 109 | -------------------------------------------------------------------------------- /src/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 2 | message(FATAL_ERROR "Cannot find install manifest: 3 | @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 5 | 6 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 7 | string(REGEX REPLACE "\n" ";" files "${files}") 8 | foreach(file ${files}) 9 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 10 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 11 | exec_program( 12 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 13 | OUTPUT_VARIABLE rm_out 14 | RETURN_VALUE rm_retval 15 | ) 16 | if(NOT "${rm_retval}" STREQUAL 0) 17 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 18 | endif(NOT "${rm_retval}" STREQUAL 0) 19 | else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 20 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.") 21 | endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 22 | endforeach(file) 23 | -------------------------------------------------------------------------------- /src/ksd.ksmoothdock.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=KSmoothDock 4 | GenericName=Desktop Panel 5 | Icon=user-desktop 6 | Exec=ksmoothdock 7 | Terminal=false 8 | Categories=Qt;KDE;Utility; 9 | -------------------------------------------------------------------------------- /src/main.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | int main(int argc, char** argv) { 31 | QApplication app(argc, argv); 32 | KDBusService service(KDBusService::Unique); 33 | 34 | KAboutData about( 35 | "ksmoothdock", 36 | "KSmoothDock", 37 | "6.3", 38 | i18n("A cool desktop panel for KDE Plasma 5"), 39 | KAboutLicense::GPL_V3, 40 | i18n("Copyright (C) 2022 Viet Dang (dangvd@gmail.com)"), 41 | "", 42 | "https://dangvd.github.io/ksmoothdock"); 43 | KAboutData::setApplicationData(about); 44 | QApplication::setWindowIcon(QIcon::fromTheme("user-desktop")); 45 | 46 | ksmoothdock::MultiDockModel model(QDir::homePath() + "/.ksmoothdock"); 47 | ksmoothdock::MultiDockView view(&model); 48 | view.show(); 49 | return app.exec(); 50 | } 51 | -------------------------------------------------------------------------------- /src/model/application_menu_config.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2019 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "application_menu_config.h" 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | namespace ksmoothdock { 35 | 36 | const std::vector ApplicationMenuConfig::kSessionSystemCategories = { 37 | {"Session", "Session", "system-switch-user", { 38 | {"Lock Screen", 39 | "", 40 | "system-lock-screen", 41 | "qdbus org.kde.screensaver /ScreenSaver Lock", 42 | ""}, 43 | {"Log Out", 44 | "", 45 | "system-log-out", 46 | "qdbus org.kde.ksmserver /KSMServer logout -1 0 3", 47 | ""}, 48 | {"Switch User", 49 | "", 50 | "system-switch-user", 51 | "qdbus org.kde.ksmserver /KSMServer openSwitchUserDialog", 52 | ""} 53 | } 54 | }, 55 | {"Power", "Power", "system-shutdown", { 56 | {"Suspend", 57 | "", 58 | "system-suspend", 59 | "qdbus org.kde.Solid.PowerManagement /org/freedesktop/PowerManagement " 60 | "Suspend", 61 | ""}, 62 | {"Hibernate", 63 | "", 64 | "system-suspend-hibernate", 65 | "qdbus org.kde.Solid.PowerManagement /org/freedesktop/PowerManagement " 66 | "Hibernate", 67 | ""}, 68 | {"Reboot", 69 | "", 70 | "system-reboot", 71 | "qdbus org.kde.ksmserver /KSMServer logout -1 1 3", 72 | ""}, 73 | {"Shut Down", 74 | "", 75 | "system-shutdown", 76 | "qdbus org.kde.ksmserver /KSMServer logout -1 2 3", 77 | ""} 78 | } 79 | } 80 | }; 81 | const ApplicationEntry ApplicationMenuConfig::kSearchEntry = { 82 | "Search", "", "system-search", "krunner", "" 83 | }; 84 | 85 | bool operator<(const ApplicationEntry &e1, const ApplicationEntry &e2) { 86 | return e1.name < e2.name; 87 | } 88 | 89 | ApplicationMenuConfig::ApplicationMenuConfig(const QStringList& entryDirs) 90 | : entryDirs_(entryDirs), 91 | fileWatcher_(entryDirs) { 92 | initCategories(); 93 | loadEntries(); 94 | connect(&fileWatcher_, SIGNAL(directoryChanged(const QString&)), 95 | this, SLOT(reload())); 96 | connect(&fileWatcher_, SIGNAL(fileChanged(const QString&)), 97 | this, SLOT(reload())); 98 | } 99 | 100 | void ApplicationMenuConfig::initCategories() { 101 | // We use the main categories as defined in: 102 | // https://specifications.freedesktop.org/menu-spec/latest/apa.html 103 | static constexpr int kNumCategories = 11; 104 | static const char* const kCategories[kNumCategories][3] = { 105 | // Name, display name, icon. 106 | // Sorted by display name. 107 | {"Development", "Development", "applications-development"}, 108 | {"Education", "Education", "applications-education"}, 109 | {"Game", "Games", "applications-games"}, 110 | {"Graphics", "Graphics", "applications-graphics"}, 111 | {"Network", "Internet", "applications-internet"}, 112 | {"AudioVideo", "Multimedia", "applications-multimedia"}, 113 | {"Office", "Office", "applications-office"}, 114 | {"Science", "Science", "applications-science"}, 115 | {"Settings", "Settings", "preferences-other"}, 116 | {"System", "System", "applications-system"}, 117 | {"Utility", "Utilities", "applications-utilities"}, 118 | }; 119 | categories_.reserve(kNumCategories); 120 | for (int i = 0; i < kNumCategories; ++i) { 121 | categories_.push_back(Category( 122 | kCategories[i][0], kCategories[i][1], kCategories[i][2])); 123 | categoryMap_[kCategories[i][0]] = i; 124 | } 125 | } 126 | 127 | bool ApplicationMenuConfig::loadEntries() { 128 | for (const QString& entryDir : entryDirs_) { 129 | if (!QDir::root().exists(entryDir)) { 130 | continue; 131 | } 132 | 133 | QDir dir(entryDir); 134 | QStringList files = dir.entryList({"*.desktop"}, QDir::Files, QDir::Name); 135 | if (files.isEmpty()) { 136 | continue; 137 | } 138 | 139 | for (int i = 0; i < files.size(); ++i) { 140 | const QString& file = entryDir + "/" + files.at(i); 141 | loadEntry(file); 142 | } 143 | } 144 | 145 | return true; 146 | } 147 | 148 | bool ApplicationMenuConfig::loadEntry(const QString &file) { 149 | KDesktopFile desktopFile(file); 150 | if (desktopFile.noDisplay()) { 151 | return false; 152 | } 153 | 154 | if (desktopFile.entryMap("Desktop Entry").contains("Hidden")) { 155 | const QString hidden = desktopFile.entryMap("Desktop Entry")["Hidden"]; 156 | if (hidden.trimmed().toLower() == "true") { 157 | return false; 158 | } 159 | } 160 | 161 | const QStringList categories = 162 | desktopFile.entryMap("Desktop Entry")["Categories"] 163 | .split(';', Qt::SkipEmptyParts); 164 | if (categories.isEmpty()) { 165 | return false; 166 | } 167 | 168 | for (int i = 0; i < categories.size(); ++i) { 169 | const std::string category = categories[i].toStdString(); 170 | if (categoryMap_.count(category) > 0) { 171 | const QString command = filterFieldCodes( 172 | desktopFile.entryMap("Desktop Entry")["Exec"]); 173 | ApplicationEntry newEntry(desktopFile.readName(), 174 | desktopFile.readGenericName(), 175 | desktopFile.readIcon(), 176 | command, 177 | file); 178 | auto& entries = categories_[categoryMap_[category]].entries; 179 | auto next = std::lower_bound(entries.begin(), entries.end(), newEntry); 180 | entries.insert(next, newEntry); 181 | 182 | entries_[newEntry.taskCommand.toStdString()] = &(*--next); 183 | } 184 | } 185 | return true; 186 | } 187 | 188 | void ApplicationMenuConfig::reload() { 189 | for (auto& category : categories_) { 190 | category.entries.clear(); 191 | } 192 | loadEntries(); 193 | emit configChanged(); 194 | } 195 | 196 | const ApplicationEntry* ApplicationMenuConfig::findApplication( 197 | const std::string& command) const { 198 | if (command == "systemsettings") { // Fix for System Settings. 199 | return (entries_.count("systemsettings5") > 0) ? entries_.at("systemsettings5") : nullptr; 200 | } 201 | return (entries_.count(command) > 0) ? entries_.at(command) : nullptr; 202 | } 203 | 204 | } // namespace ksmoothdock 205 | -------------------------------------------------------------------------------- /src/model/application_menu_config.h: -------------------------------------------------------------------------------- 1 | #ifndef KSMOOTHDOCK_APPLICATION_MENU_CONFIG_H_ 2 | #define KSMOOTHDOCK_APPLICATION_MENU_CONFIG_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | namespace ksmoothdock { 19 | 20 | // An application entry in the application menu. 21 | struct ApplicationEntry { 22 | // Name e.g. 'Chrome'. 23 | QString name; 24 | 25 | // Generic name e.g. 'Web Brower'. 26 | QString genericName; 27 | 28 | // Icon name e.g. 'chrome'. 29 | QString icon; 30 | 31 | // Command to execute e.g. '/usr/bin/google-chrome-stable'. 32 | QString command; 33 | 34 | // The task command, to compare with KWindowInfo.windowClassName, e.g. 'google-chrome' 35 | QString taskCommand; 36 | 37 | // The path to the desktop file e.g. '/usr/share/applications/chrome.desktop' 38 | QString desktopFile; 39 | 40 | ApplicationEntry(const QString& name2, const QString& genericName2, 41 | const QString& icon2, const QString& command2, 42 | const QString& desktopFile2) 43 | : name(name2), genericName(genericName2), icon(icon2), command(command2), 44 | taskCommand(getTaskCommand(command)), desktopFile(desktopFile2) {} 45 | }; 46 | 47 | bool operator<(const ApplicationEntry &e1, const ApplicationEntry &e2); 48 | 49 | // A category in the application menu. 50 | struct Category { 51 | // Name for the category e.g. 'Development' or 'Utility'. See: 52 | // https://specifications.freedesktop.org/menu-spec/latest/apa.html 53 | QString name; 54 | 55 | // Display name for the category e.g. 'Utilities'. 56 | QString displayName; 57 | 58 | // Icon name for the category e.g. 'applications-internet'. 59 | QString icon; 60 | 61 | // Application entries for this category. 62 | std::list entries; 63 | 64 | Category(const QString& name2, const QString& displayName2, 65 | const QString& icon2) 66 | : name(name2), displayName(displayName2), icon(icon2) {} 67 | 68 | Category(const QString& name2, const QString& displayName2, 69 | const QString& icon2, std::list entries2) 70 | : name(name2), displayName(displayName2), icon(icon2), entries(entries2) { 71 | } 72 | }; 73 | 74 | class ApplicationMenuConfig : public QObject { 75 | Q_OBJECT 76 | 77 | public: 78 | ApplicationMenuConfig(const QStringList& entryDirs = { 79 | "/usr/share/applications", 80 | "/usr/share/applications/kde4", 81 | QDir::homePath() + "/.local/share/applications"}); 82 | 83 | ~ApplicationMenuConfig() = default; 84 | 85 | static const std::vector kSessionSystemCategories; 86 | static const ApplicationEntry kSearchEntry; 87 | 88 | const std::vector& categories() const { return categories_; } 89 | 90 | const ApplicationEntry* findApplication(const std::string& command) const; 91 | const ApplicationEntry* findApplication(const QString& command) const { 92 | return findApplication(command.toStdString()); 93 | } 94 | 95 | signals: 96 | void configChanged(); 97 | 98 | public slots: 99 | void reload(); 100 | 101 | private: 102 | // Initializes application categories. 103 | void initCategories(); 104 | 105 | // Loads application entries from entryDir. 106 | bool loadEntries(); 107 | 108 | // Loads an application entry from the .desktop file. 109 | bool loadEntry(const QString& file); 110 | 111 | // The directories that contains the list of all application entries as 112 | // desktop files, e.g. /usr/share/applications 113 | const QStringList entryDirs_; 114 | 115 | // Application entries, organized by categories. 116 | std::vector categories_; 117 | // Map from category names to category indices in the above vector, 118 | // to make loading entries faster. 119 | std::unordered_map categoryMap_; 120 | // Map from commands to application entries for fast look-up. 121 | std::unordered_map entries_; 122 | 123 | QFileSystemWatcher fileWatcher_; 124 | 125 | friend class ApplicationMenuConfigTest; 126 | }; 127 | 128 | } 129 | 130 | #endif // KSMOOTHDOCK_APPLICATION_MENU_CONFIG_H_ 131 | -------------------------------------------------------------------------------- /src/model/application_menu_config_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2019 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "application_menu_config.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | namespace ksmoothdock { 30 | 31 | constexpr int kNumCategories = 11; 32 | 33 | class ApplicationMenuConfigTest: public QObject { 34 | Q_OBJECT 35 | 36 | private slots: 37 | void init() { 38 | QTemporaryDir configDir; 39 | } 40 | 41 | void loadEntries_singleDir(); 42 | void loadEntries_multipleDirs(); 43 | 44 | private: 45 | 46 | void writeEntry(const QString& filename, const ApplicationEntry& entry, 47 | const QString& categories, 48 | const std::unordered_map& extraKVs 49 | = {}) { 50 | KConfig config(filename, KConfig::SimpleConfig); 51 | KConfigGroup group(&config, "Desktop Entry"); 52 | group.writeEntry("Name", entry.name); 53 | group.writeEntry("GenericName", entry.genericName); 54 | group.writeEntry("Icon", entry.icon); 55 | group.writeEntry("Exec", entry.command); 56 | group.writeEntry("Categories", categories); 57 | for (const auto& kv : extraKVs) { 58 | group.writeEntry(QString::fromStdString(kv.first), 59 | QString::fromStdString(kv.second)); 60 | } 61 | config.sync(); 62 | } 63 | }; 64 | 65 | void ApplicationMenuConfigTest::loadEntries_singleDir() { 66 | QTemporaryDir entryDir; 67 | QVERIFY(entryDir.isValid()); 68 | writeEntry(entryDir.path() + "/1.desktop", 69 | {"Chrome", "Web Browser", "chrome", "chrome", ""}, 70 | "Network"); 71 | 72 | ApplicationMenuConfig ApplicationMenuConfig({ entryDir.path() }); 73 | 74 | QCOMPARE(static_cast(ApplicationMenuConfig.categories_.size()), 75 | kNumCategories); 76 | for (const auto& category : ApplicationMenuConfig.categories_) { 77 | if (category.name == "Network") { 78 | QCOMPARE(static_cast(category.entries.size()), 1); 79 | } else { 80 | QCOMPARE(static_cast(category.entries.size()), 0); 81 | } 82 | } 83 | } 84 | 85 | void ApplicationMenuConfigTest::loadEntries_multipleDirs() { 86 | QTemporaryDir entryDir1; 87 | QVERIFY(entryDir1.isValid()); 88 | writeEntry(entryDir1.path() + "/1.desktop", 89 | {"Chrome", "Web Browser", "chrome", "chrome", ""}, 90 | "Network"); 91 | writeEntry(entryDir1.path() + "/2.desktop", 92 | {"KMail", "Email Client", "kmail", "kmail", ""}, 93 | "Qt;KDE;Network"); 94 | writeEntry(entryDir1.path() + "/3.desktop", 95 | {"Xfce Settings", "", "xfce-settings", "xfce-settings", ""}, 96 | "Settings", 97 | {{"OnlyShowIn", "Xfce"}}); 98 | 99 | // Empty dir 100 | QTemporaryDir entryDir2; 101 | QVERIFY(entryDir2.isValid()); 102 | 103 | QTemporaryDir entryDir3; 104 | QVERIFY(entryDir3.isValid()); 105 | writeEntry(entryDir3.path() + "/1.desktop", 106 | {"KDE Settings", "", "systemsettings5", "systemsettings5", ""}, 107 | "Settings", 108 | {{"OnlyShowIn", "KDE"}}); 109 | writeEntry(entryDir3.path() + "/2.desktop", 110 | {"Gnome Settings", "", "gnome-settings", "gnome-settings", ""}, 111 | "Settings", 112 | {{"NotShowIn", "KDE"}}); 113 | writeEntry(entryDir3.path() + "/3.desktop", 114 | {"Chrome - HTML", "Web Browser", "chrome", "chrome", ""}, 115 | "Network", 116 | {{"NoDisplay", "true"}}); 117 | writeEntry(entryDir3.path() + "/4.desktop", 118 | {"Chrome - Old", "Web Browser", "chrome", "chrome", ""}, 119 | "Network", 120 | {{"Hidden", "true"}}); 121 | 122 | ApplicationMenuConfig ApplicationMenuConfig( 123 | { entryDir1.path(), entryDir1.path() + "/dir-not-exist", entryDir2.path(), 124 | entryDir3.path() }); 125 | 126 | QCOMPARE(static_cast(ApplicationMenuConfig.categories_.size()), 127 | kNumCategories); 128 | for (const auto& category : ApplicationMenuConfig.categories_) { 129 | if (category.name == "Network") { 130 | QCOMPARE(static_cast(category.entries.size()), 2); 131 | } else if (category.name == "Settings") { 132 | QCOMPARE(static_cast(category.entries.size()), 1); 133 | } else { 134 | QCOMPARE(static_cast(category.entries.size()), 0); 135 | } 136 | } 137 | } 138 | 139 | } // namespace ksmoothdock 140 | 141 | QTEST_MAIN(ksmoothdock::ApplicationMenuConfigTest) 142 | #include "application_menu_config_test.moc" 143 | -------------------------------------------------------------------------------- /src/model/config_helper.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "config_helper.h" 20 | 21 | #include 22 | #include 23 | 24 | namespace ksmoothdock { 25 | 26 | constexpr char ConfigHelper::kSingleDockConfig[]; 27 | constexpr char ConfigHelper::kSingleDockOldConfig[]; 28 | constexpr char ConfigHelper::kSingleDockLaunchers[]; 29 | 30 | constexpr char ConfigHelper::kConfigPattern[]; 31 | constexpr char ConfigHelper::kAppearanceConfig[]; 32 | constexpr char ConfigHelper::kIconOverrideRules[]; 33 | 34 | ConfigHelper::ConfigHelper(const QString& configDir) 35 | : configDir_{configDir} { 36 | if (!configDir_.exists()) { 37 | QDir::root().mkpath(configDir); 38 | } 39 | } 40 | 41 | std::vector> ConfigHelper::findAllDockConfigs() 42 | const { 43 | std::vector> allConfigs; 44 | QStringList files = configDir_.entryList( 45 | {kConfigPattern}, QDir::Files, QDir::Name); 46 | if (files.isEmpty()) { 47 | return allConfigs; 48 | } 49 | 50 | for (int i = 0; i < files.size(); ++i) { 51 | const QString& configFile = files.at(i); 52 | allConfigs.push_back(std::make_tuple( 53 | dockConfigPath(configFile), 54 | dockLaunchersPathForConfigFile(configFile))); 55 | } 56 | return allConfigs; 57 | } 58 | 59 | std::tuple ConfigHelper::findNextDockConfigs() const { 60 | for (int fileId = 1; ; ++fileId) { 61 | if (!configDir_.exists(dockConfigFile(fileId))) { 62 | return std::make_tuple(dockConfigPath(fileId), 63 | dockLaunchersPath(fileId)); 64 | } 65 | } 66 | } 67 | 68 | void ConfigHelper::copyLaunchersDir(const QString& launchersDir, 69 | const QString& newLaunchersDir) { 70 | QDir::root().mkpath(newLaunchersDir); 71 | QDir dir(launchersDir); 72 | QStringList files = dir.entryList({"*.desktop"}, QDir::Files, QDir::Name); 73 | for (int i = 0; i < files.size(); ++i) { 74 | const auto srcFile = launchersDir + "/" + files.at(i); 75 | const auto destFile = newLaunchersDir + "/" + files.at(i); 76 | QFile::copy(srcFile, destFile); 77 | } 78 | } 79 | 80 | void ConfigHelper::removeLaunchersDir(const QString& launchersDir) { 81 | QDir dir(launchersDir); 82 | QStringList files = dir.entryList({"*.desktop"}, QDir::Files, QDir::Name); 83 | for (int i = 0; i < files.size(); ++i) { 84 | const auto launcherFile = launchersDir + "/" + files.at(i); 85 | QFile::remove(launcherFile); 86 | } 87 | QDir::root().rmdir(launchersDir); 88 | } 89 | 90 | } // namespace ksmoothdock 91 | -------------------------------------------------------------------------------- /src/model/config_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_CONFIG_HELPER_H_ 20 | #define KSMOOTHDOCK_CONFIG_HELPER_H_ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | namespace ksmoothdock { 28 | 29 | // Helper class for working with configurations. 30 | class ConfigHelper { 31 | public: 32 | // [Deprecated] single-dock configs. 33 | // ksmoothdockrc will be renamed to ksmoothdockrc.old when it is converted 34 | // to the new multi-dock configs. 35 | static constexpr char kSingleDockConfig[] = "ksmoothdockrc"; 36 | static constexpr char kSingleDockOldConfig[] = "ksmoothdockrc.old"; 37 | static constexpr char kSingleDockLaunchers[] = "launchers"; 38 | 39 | // Individual dock configs. 40 | static constexpr char kConfigPattern[] = "panel_*.conf"; 41 | 42 | // Global appearance config. 43 | static constexpr char kAppearanceConfig[] = "appearance.conf"; 44 | 45 | // Global icon override rules (for task manager). 46 | static constexpr char kIconOverrideRules[] = "icon_override.rules"; 47 | 48 | explicit ConfigHelper(const QString& configDir); 49 | ~ConfigHelper() = default; 50 | 51 | // Gets the appearance config file path. 52 | QString appearanceConfigPath() const { 53 | return configDir_.filePath(kAppearanceConfig); 54 | } 55 | 56 | // Gets the icon override rules file path. 57 | QString iconOverrideRulesPath() const { 58 | return configDir_.filePath(kIconOverrideRules); 59 | } 60 | 61 | static QString wallpaperConfigKey(int desktop, int screen) { 62 | // Screen is 0-based. 63 | return QString("wallpaper") + QString::number(desktop) + 64 | ((screen == 0) ? "" : (QString("_") + QString::number(screen + 1))); 65 | } 66 | 67 | // Finds the configs of all existing docks. 68 | // Returns a list of a tuple of . 69 | std::vector> findAllDockConfigs() const; 70 | 71 | // Finds the next available configs for a new dock. 72 | std::tuple findNextDockConfigs() const; 73 | 74 | // Copies a launchers directory. 75 | static void copyLaunchersDir(const QString& launchersDir, 76 | const QString& newLaunchersDir); 77 | 78 | // Removes a launchers directory. 79 | static void removeLaunchersDir(const QString& launchersDir); 80 | 81 | // For conversion from old single-dock config to the new multi-dock config. 82 | 83 | // Whether this is a old version of KSmoothDock using single-dock config. 84 | bool isSingleDockConfig() const { 85 | return configDir_.exists(kSingleDockConfig) && 86 | !configDir_.exists(kAppearanceConfig); 87 | } 88 | 89 | // Gets the config file path of the old single-dock config. 90 | QString singleDockConfigPath() const { 91 | return configDir_.filePath(kSingleDockConfig); 92 | } 93 | 94 | // Gets the launchers dir path of the old single-dock config. 95 | QString singleDockLaunchersPath() const { 96 | return configDir_.filePath(kSingleDockLaunchers); 97 | } 98 | 99 | // Used when conversion from single-dock config to multi-dock config. 100 | QString dockConfigPathFromSingleDock() const { 101 | return dockConfigPath(1); 102 | } 103 | 104 | // Renames single-dock configs. Is meant to be called after conversion to 105 | // multi-dock config has been done. 106 | void renameSingleDockConfigs() { 107 | configDir_.rename(kSingleDockConfig, kSingleDockOldConfig); 108 | configDir_.rename(kSingleDockLaunchers, dockLaunchersDir(1)); 109 | } 110 | 111 | private: 112 | // Gets the config file name of a dock. 113 | static QString dockConfigFile(int fileId) { 114 | return QString("panel_") + QString::number(fileId) + ".conf"; 115 | } 116 | 117 | // Gets the config file path of a dock. 118 | QString dockConfigPath(int fileId) const { 119 | return configDir_.filePath(dockConfigFile(fileId)); 120 | } 121 | 122 | QString dockConfigPath(QString configFile) const { 123 | return configDir_.filePath(configFile); 124 | } 125 | 126 | static QString dockLaunchersDir(int fileId) { 127 | return QString("panel_") + QString::number(fileId) + "_launchers"; 128 | } 129 | 130 | // Gets the launchers dir path of a dock. 131 | QString dockLaunchersPath(int fileId) const { 132 | return configDir_.filePath(dockLaunchersDir(fileId)); 133 | } 134 | 135 | QString dockLaunchersPathForConfigFile(const QString& configFile) const { 136 | QString launchersDir = configFile; 137 | launchersDir.replace(".conf", "_launchers"); 138 | return configDir_.filePath(launchersDir); 139 | } 140 | 141 | QDir configDir_; 142 | 143 | friend class MultiDockModelTest; 144 | }; 145 | 146 | } // namespace ksmoothdock 147 | 148 | #endif // KSMOOTHDOCK_CONFIG_HELPER_H_ 149 | -------------------------------------------------------------------------------- /src/model/multi_dock_model_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "multi_dock_model.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | namespace ksmoothdock { 26 | 27 | class MultiDockModelTest: public QObject { 28 | Q_OBJECT 29 | 30 | private slots: 31 | void load_noDock(); 32 | 33 | void load_singleDock(); 34 | 35 | void load_multipleDocks(); 36 | 37 | private: 38 | void createDockConfig(const QTemporaryDir& configDir, int fileId) { 39 | QFile dockConfig(configDir.path() + "/" + 40 | ConfigHelper::dockConfigFile(fileId)); 41 | dockConfig.open(QIODevice::WriteOnly); 42 | } 43 | }; 44 | 45 | void MultiDockModelTest::load_noDock() { 46 | QTemporaryDir configDir; 47 | MultiDockModel model(configDir.path()); 48 | QCOMPARE(model.dockCount(), 0); 49 | } 50 | 51 | void MultiDockModelTest::load_singleDock() { 52 | QTemporaryDir configDir; 53 | QVERIFY(configDir.isValid()); 54 | createDockConfig(configDir, 1); 55 | 56 | MultiDockModel model(configDir.path()); 57 | QCOMPARE(model.dockCount(), 1); 58 | } 59 | 60 | void MultiDockModelTest::load_multipleDocks() { 61 | QTemporaryDir configDir; 62 | QVERIFY(configDir.isValid()); 63 | createDockConfig(configDir, 1); 64 | createDockConfig(configDir, 2); 65 | createDockConfig(configDir, 4); 66 | 67 | MultiDockModel model(configDir.path()); 68 | QCOMPARE(model.dockCount(), 3); 69 | } 70 | 71 | } // namespace ksmoothdock 72 | 73 | QTEST_MAIN(ksmoothdock::MultiDockModelTest) 74 | #include "multi_dock_model_test.moc" 75 | -------------------------------------------------------------------------------- /src/utils/command_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_COMMAND_UTILS_H_ 20 | #define KSMOOTHDOCK_COMMAND_UTILS_H_ 21 | 22 | #include 23 | 24 | #include 25 | 26 | namespace ksmoothdock { 27 | 28 | static constexpr char kShowDesktopCommand[] = "SHOW_DESKTOP"; 29 | static constexpr char kLockScreenCommand[] = 30 | "qdbus org.kde.screensaver /ScreenSaver Lock"; 31 | 32 | inline QString filterFieldCodes(const QString& command) { 33 | if (command.contains('%')) { 34 | return command.left(command.indexOf(' ')); 35 | } 36 | return command; 37 | } 38 | 39 | inline bool isCommandInternal(const QString& command) { 40 | return command == kShowDesktopCommand; 41 | } 42 | 43 | inline bool isCommandDBus(const QString& command) { 44 | return command.startsWith("qdbus"); 45 | } 46 | 47 | inline bool isCommandLockScreen(const QString& command) { 48 | return command == kLockScreenCommand; 49 | } 50 | 51 | inline std::string getTaskCommand(const std::string& appCommand) { 52 | namespace fs = std::filesystem; 53 | const auto command = appCommand.substr(0, appCommand.find_first_of(' ')); 54 | return fs::is_symlink(command) ? 55 | fs::path(fs::read_symlink(command)).filename() : 56 | fs::path(command).filename(); 57 | } 58 | 59 | inline QString getTaskCommand(const QString& appCommand) { 60 | return QString::fromStdString(getTaskCommand(appCommand.toStdString())); 61 | } 62 | 63 | inline bool areTheSameCommand(const QString& appTaskCommand, const QString& taskCommand) { 64 | // Fix for System Settings. 65 | if (taskCommand == "systemsettings" && appTaskCommand == "systemsettings5") { 66 | return true; 67 | } 68 | return appTaskCommand == taskCommand; 69 | } 70 | 71 | } // namespace ksmoothdock 72 | 73 | #endif // KSMOOTHDOCK_COMMAND_UTILS_H_ 74 | -------------------------------------------------------------------------------- /src/utils/draw_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_DRAW_UTILS_H_ 20 | #define KSMOOTHDOCK_DRAW_UTILS_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace ksmoothdock { 30 | 31 | inline void drawBorderedText(int x, int y, const QString& text, int borderWidth, 32 | QColor borderColor, QColor textColor, 33 | QPainter* painter) { 34 | painter->setPen(borderColor); 35 | for (int i = -borderWidth; i <= borderWidth; ++i) { 36 | for (int j = -borderWidth; j <= borderWidth; ++j) { 37 | painter->drawText(x + i, y + j, text); 38 | } 39 | } 40 | 41 | painter->setPen(textColor); 42 | painter->drawText(x, y, text); 43 | } 44 | 45 | inline void drawBorderedText(int x, int y, int width, int height, int flags, 46 | const QString& text, int borderWidth, 47 | QColor borderColor, QColor textColor, 48 | QPainter* painter) { 49 | painter->setPen(borderColor); 50 | for (int i = -borderWidth; i <= borderWidth; ++i) { 51 | for (int j = -borderWidth; j <= borderWidth; ++j) { 52 | painter->drawText(x + i, y + j, width, height, flags, text); 53 | } 54 | } 55 | 56 | painter->setPen(textColor); 57 | painter->drawText(x, y, width, height, flags, text); 58 | } 59 | 60 | inline void drawHighlightedIcon(QColor bgColor, int left, int top, int width, int height, 61 | int padding, int roundedRectRadius, QPainter* painter, 62 | float alpha = 0.42) { 63 | painter->setRenderHint(QPainter::Antialiasing); 64 | QColor fillColor = bgColor.lighter(500); 65 | fillColor.setAlphaF(alpha); 66 | QPainterPath path; 67 | path.addRoundedRect( 68 | QRect(left - padding, top - padding, width + 2 * padding, height + 2 * padding), 69 | roundedRectRadius, roundedRectRadius); 70 | painter->fillPath(path, QBrush(fillColor)); 71 | painter->setRenderHint(QPainter::Antialiasing, false); 72 | } 73 | 74 | } // namespace ksmoothdock 75 | 76 | #endif // KSMOOTHDOCK_DRAW_UTILS_H_ 77 | -------------------------------------------------------------------------------- /src/utils/font_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_FONT_UTILS_H_ 20 | #define KSMOOTHDOCK_FONT_UTILS_H_ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace ksmoothdock { 32 | 33 | // Returns a QFont with font size adjusted automatically according to the given 34 | // width, height, reference string and scale factor. 35 | inline QFont adjustFontSize(int w, int h, const QString& referenceString, 36 | float scaleFactor, const QString& fontFamily = "") { 37 | QFont font; 38 | QFontMetrics metrics(font); 39 | const QRect& rect = metrics.tightBoundingRect(referenceString); 40 | // Scale the font size according to the size of the dock. 41 | font.setPointSize(std::min(font.pointSize() * w / rect.width(), 42 | font.pointSize() * h / rect.height())); 43 | font.setPointSize(static_cast(font.pointSize() * scaleFactor)); 44 | if (!fontFamily.isEmpty()) { 45 | font.setFamily(fontFamily); 46 | } 47 | 48 | return font; 49 | } 50 | 51 | // Gets the list of base font families, i.e. just 'Noto Sans' 52 | // instead of 'Noto Sans Bold', 'Noto Sans CJK' etc. 53 | inline std::vector getBaseFontFamilies() { 54 | std::vector baseFamilies; 55 | QFontDatabase database; 56 | const auto families = database.families(QFontDatabase::Latin); 57 | for (int i = 0; i < families.size(); ++i) { 58 | bool isBaseFont = true; 59 | const auto family = families.at(i); 60 | if (database.isSmoothlyScalable(family)) { 61 | for (int j = 0; j < families.size(); ++j) { 62 | if (family.startsWith(families[j] + ' ')) { 63 | isBaseFont = false; 64 | break; 65 | } 66 | } 67 | if (isBaseFont) { 68 | baseFamilies.push_back(family); 69 | } 70 | } 71 | } 72 | return baseFamilies; 73 | } 74 | 75 | } // namespace ksmoothdock 76 | 77 | #endif // KSMOOTHDOCK_FONT_UTILS_H_ 78 | -------------------------------------------------------------------------------- /src/utils/task_helper.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "task_helper.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | namespace ksmoothdock { 34 | 35 | namespace { 36 | 37 | QString getProgram(const KWindowInfo& info) { 38 | return QString(info.windowClassName()); 39 | } 40 | 41 | QString getCommand(const KWindowInfo& info) { 42 | return QString(info.windowClassClass()).toLower(); 43 | } 44 | 45 | } // namespace 46 | 47 | bool TaskInfo::operator<(const TaskInfo& taskInfo) const { 48 | if (program == taskInfo.program) { 49 | // If same program, sort by creation time. 50 | bool found = false; 51 | for (const auto window : KWindowSystem::windows()) { 52 | if (window == wId) { 53 | found = true; 54 | } else if (window == taskInfo.wId) { 55 | return found; 56 | } 57 | } 58 | return true; 59 | } 60 | return program < taskInfo.program; 61 | } 62 | 63 | TaskHelper::TaskHelper() 64 | : currentDesktop_(KWindowSystem::currentDesktop()) { 65 | // Calling DBus to get current activity. This is more convenient than waiting for 66 | // KActivities::Consumer's status change then calling it. 67 | QDBusInterface activityManagerDBus("org.kde.ActivityManager", "/ActivityManager/Activities", 68 | "org.kde.ActivityManager.Activities"); 69 | if (activityManagerDBus.isValid()) { 70 | const QDBusReply reply = activityManagerDBus.call("CurrentActivity"); 71 | if (reply.isValid()) { 72 | currentActivity_ = reply.value(); 73 | } 74 | } 75 | 76 | connect(KWindowSystem::self(), &KWindowSystem::currentDesktopChanged, 77 | this, &TaskHelper::onCurrentDesktopChanged); 78 | connect(&activityManager_, &KActivities::Consumer::currentActivityChanged, 79 | this, &TaskHelper::onCurrentActivityChanged); 80 | } 81 | 82 | std::vector TaskHelper::loadTasks(int screen, bool currentDesktopOnly) { 83 | std::vector tasks; 84 | for (const auto wId : KWindowSystem::windows()) { 85 | if (isValidTask(wId, screen, currentDesktopOnly)) { 86 | tasks.push_back(getTaskInfo(wId)); 87 | } 88 | } 89 | 90 | std::stable_sort(tasks.begin(), tasks.end()); 91 | return tasks; 92 | } 93 | 94 | bool TaskHelper::isValidTask(WId wId) { 95 | if (!KWindowSystem::hasWId(wId)) { 96 | return false; 97 | } 98 | 99 | KWindowInfo info(wId, NET::WMState | NET::WMWindowType, NET::WM2WindowClass); 100 | if (!info.valid()) { 101 | return false; 102 | } 103 | 104 | const auto windowType = info.windowType(NET::DockMask | NET::DesktopMask); 105 | if (windowType != NET::Normal && windowType != NET::Unknown) { 106 | return false; 107 | } 108 | 109 | const auto state = info.state(); 110 | if (state & NET::SkipTaskbar) { 111 | return false; 112 | } 113 | 114 | // Filters out KSmoothDock dialogs. 115 | return getCommand(info) != "ksmoothdock"; 116 | } 117 | 118 | bool TaskHelper::isValidTask(WId wId, int screen, bool currentDesktopOnly, 119 | bool currentActivityOnly) { 120 | if (!isValidTask(wId)) { 121 | return false; 122 | } 123 | 124 | if (screen >= 0 && getScreen(wId) != screen) { 125 | return false; 126 | } 127 | 128 | if (currentDesktopOnly) { 129 | KWindowInfo info(wId, NET::WMDesktop); 130 | if (!info.valid() || (info.desktop() != currentDesktop_ && !info.onAllDesktops())) { 131 | return false; 132 | } 133 | } 134 | 135 | if (currentActivityOnly) { 136 | KWindowInfo info(wId, NET::Properties(), NET::WM2Activities); 137 | if (!info.valid() || 138 | (!info.activities().empty() && !info.activities().contains(currentActivity_))) { 139 | return false; 140 | } 141 | } 142 | 143 | return true; 144 | } 145 | 146 | /* static */ TaskInfo TaskHelper::getBasicTaskInfo(WId wId) { 147 | KWindowInfo info(wId, NET::Properties(), NET::WM2WindowClass); 148 | return TaskInfo(wId, getProgram(info)); 149 | } 150 | 151 | TaskInfo TaskHelper::getTaskInfo(WId wId) const { 152 | static constexpr int kIconLoadSize = 128; 153 | KWindowInfo info(wId, NET::WMVisibleName | NET::WMState, NET::WM2WindowClass); 154 | 155 | const auto program = getProgram(info); 156 | const auto command = getCommand(info); 157 | const auto name = info.visibleName(); 158 | QPixmap icon = KWindowSystem::icon(wId, kIconLoadSize, kIconLoadSize, true /* scale */); 159 | 160 | return TaskInfo(wId, program, command, name, icon, info.state() == NET::DemandsAttention); 161 | } 162 | 163 | int TaskHelper::getScreen(WId wId) { 164 | const auto screens = QGuiApplication::screens(); 165 | const auto screenCount = screens.size(); 166 | if (screenCount == 1) { 167 | return 0; 168 | } 169 | 170 | KWindowInfo info(wId, NET::WMFrameExtents); 171 | const auto& geometry = info.frameGeometry(); 172 | for (int screen = 0; screen < screenCount; ++screen) { 173 | const auto& screenGeometry = screens[screen]->geometry(); 174 | if (screenGeometry.intersects(geometry)) { 175 | return screen; 176 | } 177 | } 178 | return -1; 179 | } 180 | 181 | } // namespace ksmoothdock 182 | -------------------------------------------------------------------------------- /src/utils/task_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_TASK_HELPER_H_ 20 | #define KSMOOTHDOCK_TASK_HELPER_H_ 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | namespace ksmoothdock { 31 | 32 | struct TaskInfo { 33 | WId wId; 34 | QString program; // e.g. Dolphin 35 | QString command; // e.g. dolphin 36 | QString name; // e.g. home -- Dolphin 37 | QPixmap icon; 38 | bool demandsAttention; 39 | 40 | TaskInfo(WId wId2, const QString& program2) : wId(wId2), program(program2) {} 41 | TaskInfo(WId wId2, const QString& program2, const QString&command2, const QString& name2, 42 | const QPixmap& icon2, bool demandsAttention2) 43 | : wId(wId2), program(program2), command(command2), name(name2), icon(icon2), 44 | demandsAttention(demandsAttention2) {} 45 | TaskInfo(const TaskInfo& taskInfo) = default; 46 | TaskInfo& operator=(const TaskInfo& taskInfo) = default; 47 | 48 | bool operator<(const TaskInfo& taskInfo) const; 49 | }; 50 | 51 | class TaskHelper : public QObject { 52 | Q_OBJECT 53 | 54 | public: 55 | TaskHelper(); 56 | 57 | // Loads running tasks. 58 | // 59 | // Args: 60 | // screen: screen index to load, or -1 if loading for all screens. 61 | std::vector loadTasks(int screen, bool currentDesktopOnly); 62 | 63 | // Whether the task is valid for showing on the task manager. 64 | bool isValidTask(WId wId); 65 | 66 | // Whether the task is valid for showing on the task manager on specific screen. 67 | bool isValidTask(WId wId, int screen, bool currentDesktopOnly = true, 68 | bool currentActivityOnly = true); 69 | 70 | static TaskInfo getBasicTaskInfo(WId wId); 71 | 72 | TaskInfo getTaskInfo(WId wId) const; 73 | 74 | // Gets the screen that a task is running on. 75 | int getScreen(WId wId); 76 | 77 | public slots: 78 | void onCurrentDesktopChanged(int desktop) { 79 | currentDesktop_ = desktop; 80 | } 81 | 82 | void onCurrentActivityChanged(QString activity) { 83 | currentActivity_ = activity; 84 | } 85 | 86 | private: 87 | // KWindowSystem::currentDesktop() is buggy sometimes, for example, 88 | // on windowAdded() event, so we store it here ourselves. 89 | int currentDesktop_; 90 | 91 | // ID of the current activity. 92 | QString currentActivity_; 93 | 94 | KActivities::Consumer activityManager_; 95 | }; 96 | 97 | } // namespace ksmoothdock 98 | 99 | #endif // KSMOOTHDOCK_TASK_HELPER_H_ 100 | -------------------------------------------------------------------------------- /src/utils/wallpaper_helper.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "wallpaper_helper.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | namespace ksmoothdock { 29 | 30 | WallpaperHelper::WallpaperHelper(MultiDockModel* model) 31 | : model_(model), 32 | plasmaShellDBus_("org.kde.plasmashell", 33 | "/PlasmaShell", 34 | "org.kde.PlasmaShell") {} 35 | 36 | void WallpaperHelper::setPlasmaWallpapers() { 37 | if (!plasmaShellDBus_.isValid()) { // Not running in KDE Plasma 5. 38 | return; 39 | } 40 | 41 | if (!model_->hasPager()) { 42 | return; 43 | } 44 | 45 | for (int screen = 0; screen < QGuiApplication::screens().size(); 46 | ++screen) { 47 | if (!doSetPlasmaWallpaper(screen)) { 48 | return; 49 | } 50 | } 51 | } 52 | 53 | void WallpaperHelper::setPlasmaWallpaper(int screen) { 54 | if (!plasmaShellDBus_.isValid()) { // Not running in KDE Plasma 5. 55 | return; 56 | } 57 | 58 | if (!model_->hasPager()) { 59 | return; 60 | } 61 | 62 | doSetPlasmaWallpaper(screen); 63 | } 64 | 65 | bool WallpaperHelper::doSetPlasmaWallpaper(int screen) { 66 | const auto& wallpaper = model_->wallpaper(KWindowSystem::currentDesktop(), 67 | screen); 68 | if (wallpaper.isEmpty()) { 69 | return true; // nothing to do here. 70 | } 71 | 72 | if (!QFile::exists(wallpaper)) { 73 | KMessageBox::error(nullptr, 74 | i18n("Failed to load wallpaper from: ") + wallpaper); 75 | return false; 76 | } 77 | 78 | const QDBusMessage response = plasmaShellDBus_.call( 79 | "evaluateScript", 80 | "var allDesktops = desktops();" 81 | "d = allDesktops[" + QString::number(screen) + "];" + 82 | "d.wallpaperPlugin ='org.kde.image';" 83 | "d.currentConfigGroup = Array('Wallpaper', 'org.kde.image','General');" 84 | "d.writeConfig('Image','file://" 85 | + wallpaper + "')"); 86 | if (response.type() == QDBusMessage::ErrorMessage) { 87 | KMessageBox::error( 88 | nullptr, 89 | i18n("Failed to update wallpaper. Please make sure Plasma desktop " 90 | "widgets are unlocked in order to set wallpaper.")); 91 | return false; 92 | } 93 | 94 | return true; 95 | } 96 | 97 | } // namespace ksmoothdock 98 | -------------------------------------------------------------------------------- /src/utils/wallpaper_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_WALLPAPER_HELPER_H_ 20 | #define KSMOOTHDOCK_WALLPAPER_HELPER_H_ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | namespace ksmoothdock { 28 | 29 | // Helper class for working with desktop wallpapers. 30 | class WallpaperHelper : public QObject { 31 | Q_OBJECT 32 | 33 | public: 34 | explicit WallpaperHelper(MultiDockModel* model); 35 | ~WallpaperHelper() = default; 36 | 37 | public slots: 38 | // Sets wallpapers for the current desktop for all screens. 39 | void setPlasmaWallpapers(); 40 | 41 | // Sets the wallpaper for the current desktop for the specified screen only. 42 | void setPlasmaWallpaper(int screen); 43 | 44 | private: 45 | bool doSetPlasmaWallpaper(int screen); 46 | 47 | MultiDockModel* model_; 48 | 49 | QDBusInterface plasmaShellDBus_; 50 | }; 51 | 52 | } // namespace ksmoothdock 53 | 54 | #endif // KSMOOTHDOCK_WALLPAPER_HELPER_H_ 55 | -------------------------------------------------------------------------------- /src/view/add_panel_dialog.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "add_panel_dialog.h" 20 | #include "ui_add_panel_dialog.h" 21 | 22 | #include 23 | 24 | #include 25 | 26 | namespace ksmoothdock { 27 | 28 | AddPanelDialog::AddPanelDialog(QWidget* parent, MultiDockModel* model, 29 | int dockId) 30 | : QDialog(parent), 31 | ui(new Ui::AddPanelDialog), 32 | model_(model), 33 | dockId_(dockId), 34 | isSingleScreen_(true) { 35 | ui->setupUi(this); 36 | 37 | // Populate screen list. 38 | const int screenCount = QGuiApplication::screens().size(); 39 | for (int i = 1; i <= screenCount; ++i) { 40 | ui->screen->addItem(QString::number(i)); 41 | } 42 | ui->screen->setCurrentIndex(0); 43 | 44 | // Adjust the UI for single/multi-screen. 45 | isSingleScreen_ = (screenCount == 1); 46 | if (isSingleScreen_) { 47 | ui->screenLabel->setVisible(false); 48 | ui->screen->setVisible(false); 49 | } 50 | } 51 | 52 | AddPanelDialog::~AddPanelDialog() { 53 | delete ui; 54 | } 55 | 56 | void AddPanelDialog::setMode(Mode mode) { 57 | mode_ = mode; 58 | 59 | setWindowTitle((mode_ == Mode::Add) 60 | ? i18n("Add Panel") : (mode_ == Mode::Clone) 61 | ? i18n("Clone Panel") : i18n("Welcome to KSmoothDock!")); 62 | 63 | ui->headerLabel->setText((mode == Mode::Welcome) 64 | ? i18n("Please set up your first panel.") 65 | : i18n("Please set up your new panel.")); 66 | 67 | ui->showApplicationMenu->setChecked(mode == Mode::Welcome); 68 | ui->showPager->setChecked(mode == Mode::Welcome); 69 | ui->showTaskManager->setChecked(mode == Mode::Welcome); 70 | ui->showClock->setChecked(mode == Mode::Welcome); 71 | 72 | ui->componentsLabel->setVisible(mode != Mode::Clone); 73 | ui->showApplicationMenu->setVisible(mode != Mode::Clone); 74 | ui->showPager->setVisible(mode != Mode::Clone); 75 | ui->showTaskManager->setVisible(mode != Mode::Clone); 76 | ui->showClock->setVisible(mode != Mode::Clone); 77 | 78 | const int deltaY = (mode == Mode::Clone) ? 220 : 0; 79 | ui->positionLabel->move(40, 280 - deltaY); 80 | ui->position->move(290, 270 - deltaY); 81 | ui->screenLabel->move(40, 320 - deltaY); 82 | ui->screen->move(290, 320 - deltaY); 83 | ui->buttonBox->move(20, 390 - deltaY); 84 | resize(440, 450 - deltaY); 85 | 86 | // Adjust the UI for single/multi-screen. 87 | if (isSingleScreen_) { 88 | constexpr int kScreenDeltaY = 45; 89 | ui->buttonBox->move(ui->buttonBox->x(), ui->buttonBox->y() - kScreenDeltaY); 90 | resize(width(), height() - kScreenDeltaY); 91 | } 92 | } 93 | 94 | void AddPanelDialog::accept() { 95 | QDialog::accept(); 96 | auto position = static_cast(ui->position->currentIndex()); 97 | auto screen = ui->screen->currentIndex(); 98 | if (mode_ == Mode::Clone) { 99 | model_->cloneDock(dockId_, position, screen); 100 | } else { 101 | model_->addDock( 102 | position, screen, ui->showApplicationMenu->isChecked(), 103 | ui->showPager->isChecked(), ui->showTaskManager->isChecked(), 104 | ui->showClock->isChecked()); 105 | } 106 | } 107 | 108 | } // namespace ksmoothdock 109 | -------------------------------------------------------------------------------- /src/view/add_panel_dialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_ADD_PANEL_DIALOG_H_ 20 | #define KSMOOTHDOCK_ADD_PANEL_DIALOG_H_ 21 | 22 | #include 23 | 24 | #include 25 | 26 | namespace Ui { 27 | class AddPanelDialog; 28 | } 29 | 30 | namespace ksmoothdock { 31 | 32 | class AddPanelDialog : public QDialog { 33 | Q_OBJECT 34 | 35 | public: 36 | enum class Mode { Add, Clone, Welcome }; 37 | 38 | // Parameter dockId is only needed in Clone mode. 39 | AddPanelDialog(QWidget* parent, MultiDockModel* model, int dockId); 40 | ~AddPanelDialog(); 41 | 42 | void setMode(Mode mode); 43 | 44 | public slots: 45 | void accept() override; 46 | 47 | private: 48 | Ui::AddPanelDialog *ui; 49 | 50 | Mode mode_; 51 | MultiDockModel* model_; 52 | int dockId_; 53 | 54 | bool isSingleScreen_; 55 | 56 | friend class AddPanelDialogTest; 57 | }; 58 | 59 | } // namespace ksmoothdock 60 | 61 | #endif // KSMOOTHDOCK_ADD_PANEL_DIALOG_H_ 62 | -------------------------------------------------------------------------------- /src/view/add_panel_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AddPanelDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 440 10 | 450 11 | 12 | 13 | 14 | Add Panel 15 | 16 | 17 | 18 | 19 | 20 20 | 390 21 | 400 22 | 32 23 | 24 | 25 | 26 | Qt::Horizontal 27 | 28 | 29 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 30 | 31 | 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 40 39 | 280 40 | 210 41 | 23 42 | 43 | 44 | 45 | Panel position 46 | 47 | 48 | 49 | 50 | 51 | 290 52 | 270 53 | 111 54 | 36 55 | 56 | 57 | 58 | 1 59 | 60 | 61 | 62 | Top 63 | 64 | 65 | 66 | 67 | Bottom 68 | 69 | 70 | 71 | 72 | Left 73 | 74 | 75 | 76 | 77 | Right 78 | 79 | 80 | 81 | 82 | 83 | 84 | 40 85 | 320 86 | 210 87 | 23 88 | 89 | 90 | 91 | Screen 92 | 93 | 94 | 95 | 96 | 97 | 290 98 | 320 99 | 111 100 | 36 101 | 102 | 103 | 104 | 105 | 106 | 107 | 40 108 | 68 109 | 351 110 | 23 111 | 112 | 113 | 114 | Optional features 115 | 116 | 117 | 118 | 119 | 120 | 70 121 | 100 122 | 300 123 | 29 124 | 125 | 126 | 127 | Application Menu 128 | 129 | 130 | true 131 | 132 | 133 | 134 | 135 | 136 | 70 137 | 140 138 | 300 139 | 29 140 | 141 | 142 | 143 | Pager 144 | 145 | 146 | true 147 | 148 | 149 | 150 | 151 | 152 | 40 153 | 20 154 | 361 155 | 23 156 | 157 | 158 | 159 | Please set up your new panel. 160 | 161 | 162 | 163 | 164 | 165 | 70 166 | 180 167 | 300 168 | 29 169 | 170 | 171 | 172 | Clock 173 | 174 | 175 | true 176 | 177 | 178 | 179 | 180 | 181 | 70 182 | 220 183 | 311 184 | 30 185 | 186 | 187 | 188 | Show running tasks 189 | 190 | 191 | true 192 | 193 | 194 | 195 | 196 | 197 | 198 | buttonBox 199 | accepted() 200 | AddPanelDialog 201 | accept() 202 | 203 | 204 | 248 205 | 254 206 | 207 | 208 | 157 209 | 274 210 | 211 | 212 | 213 | 214 | buttonBox 215 | rejected() 216 | AddPanelDialog 217 | reject() 218 | 219 | 220 | 316 221 | 260 222 | 223 | 224 | 286 225 | 274 226 | 227 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /src/view/add_panel_dialog_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "add_panel_dialog.h" 20 | #include "ui_add_panel_dialog.h" 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace ksmoothdock { 29 | 30 | constexpr int kDockId = 1; 31 | 32 | class AddPanelDialogTest: public QObject { 33 | Q_OBJECT 34 | 35 | private slots: 36 | // Tests OK button in Add mode. 37 | void add_ok(); 38 | 39 | // Tests Cancel button in Add mode. 40 | void add_cancel(); 41 | 42 | // Tests OK button in Clone mode. 43 | void clone_ok(); 44 | 45 | // Tests Cancel button in Clone mode. 46 | void clone_cancel(); 47 | 48 | // Tests OK button in Welcome mode. 49 | void welcome_ok(); 50 | 51 | // Tests Cancel button in Welcome mode. 52 | void welcome_cancel(); 53 | 54 | private: 55 | void init(AddPanelDialog::Mode mode) { 56 | QTemporaryDir configDir; 57 | model_ = std::make_unique(configDir.path()); 58 | if (mode != AddPanelDialog::Mode::Welcome) { 59 | model_->addDock(); 60 | } 61 | int dockId = (mode == AddPanelDialog::Mode::Clone) ? kDockId : 0; 62 | dialog_ = std::make_unique(nullptr, model_.get(), dockId); 63 | dialog_->setMode(mode); 64 | } 65 | 66 | std::unique_ptr model_; 67 | std::unique_ptr dialog_; 68 | }; 69 | 70 | void AddPanelDialogTest::add_ok() { 71 | init(AddPanelDialog::Mode::Add); 72 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Ok), 73 | Qt::LeftButton); 74 | QCOMPARE(model_->dockCount(), 2); 75 | } 76 | 77 | void AddPanelDialogTest::add_cancel() { 78 | init(AddPanelDialog::Mode::Add); 79 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Cancel), 80 | Qt::LeftButton); 81 | QCOMPARE(model_->dockCount(), 1); 82 | } 83 | 84 | void AddPanelDialogTest::clone_ok() { 85 | init(AddPanelDialog::Mode::Clone); 86 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Ok), 87 | Qt::LeftButton); 88 | QCOMPARE(model_->dockCount(), 2); 89 | } 90 | 91 | void AddPanelDialogTest::clone_cancel() { 92 | init(AddPanelDialog::Mode::Clone); 93 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Cancel), 94 | Qt::LeftButton); 95 | QCOMPARE(model_->dockCount(), 1); 96 | } 97 | 98 | void AddPanelDialogTest::welcome_ok() { 99 | init(AddPanelDialog::Mode::Welcome); 100 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Ok), 101 | Qt::LeftButton); 102 | QCOMPARE(model_->dockCount(), 1); 103 | } 104 | 105 | void AddPanelDialogTest::welcome_cancel() { 106 | init(AddPanelDialog::Mode::Welcome); 107 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Cancel), 108 | Qt::LeftButton); 109 | QCOMPARE(model_->dockCount(), 0); 110 | } 111 | 112 | } // namespace ksmoothdock 113 | 114 | QTEST_MAIN(ksmoothdock::AddPanelDialogTest) 115 | #include "add_panel_dialog_test.moc" 116 | -------------------------------------------------------------------------------- /src/view/appearance_settings_dialog.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "appearance_settings_dialog.h" 20 | #include "ui_appearance_settings_dialog.h" 21 | 22 | #include 23 | 24 | namespace ksmoothdock { 25 | 26 | namespace { 27 | inline int alphaFToTransparencyPercent(float alphaF) { 28 | return static_cast(std::round(100 * (1 - alphaF))); 29 | } 30 | 31 | inline float transparencyPercentToAlphaF(int transparencyPercent) { 32 | return 1 - transparencyPercent / 100.0; 33 | } 34 | } 35 | 36 | AppearanceSettingsDialog::AppearanceSettingsDialog(QWidget* parent, 37 | MultiDockModel* model) 38 | : QDialog(parent), 39 | ui(new Ui::AppearanceSettingsDialog), 40 | model_(model) { 41 | ui->setupUi(this); 42 | 43 | backgroundColor_ = new KColorButton(this); 44 | backgroundColor_->setAlphaChannelEnabled(false); 45 | backgroundColor_->setGeometry(QRect(260, 150, 80, 40)); 46 | 47 | borderColor_ = new KColorButton(this); 48 | borderColor_->setAlphaChannelEnabled(false); 49 | borderColor_->setGeometry(QRect(660, 150, 80, 40)); 50 | 51 | connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), 52 | this, SLOT(buttonClicked(QAbstractButton*))); 53 | 54 | loadData(); 55 | } 56 | 57 | AppearanceSettingsDialog::~AppearanceSettingsDialog() { 58 | delete ui; 59 | } 60 | 61 | void AppearanceSettingsDialog::accept() { 62 | QDialog::accept(); 63 | saveData(); 64 | } 65 | 66 | void AppearanceSettingsDialog::buttonClicked(QAbstractButton* button) { 67 | auto role = ui->buttonBox->buttonRole(button); 68 | if (role == QDialogButtonBox::ApplyRole) { 69 | saveData(); 70 | } else if (role == QDialogButtonBox::ResetRole) { 71 | resetData(); 72 | } 73 | } 74 | 75 | void AppearanceSettingsDialog::loadData() { 76 | ui->minSize->setValue(model_->minIconSize()); 77 | ui->maxSize->setValue(model_->maxIconSize()); 78 | ui->spacingFactor->setValue(model_->spacingFactor()); 79 | QColor backgroundColor = model_->backgroundColor(); 80 | backgroundColor_->setColor(QColor(backgroundColor.rgb())); 81 | ui->backgroundTransparency->setValue(alphaFToTransparencyPercent(backgroundColor.alphaF())); 82 | ui->showBorder->setChecked(model_->showBorder()); 83 | borderColor_->setColor(model_->borderColor()); 84 | ui->tooltipFontSize->setValue(model_->tooltipFontSize()); 85 | } 86 | 87 | void AppearanceSettingsDialog::resetData() { 88 | ui->minSize->setValue(kDefaultMinSize); 89 | ui->maxSize->setValue(kDefaultMaxSize); 90 | ui->spacingFactor->setValue(kDefaultSpacingFactor); 91 | backgroundColor_->setColor(QColor(kDefaultBackgroundColor)); 92 | ui->backgroundTransparency->setValue(alphaFToTransparencyPercent(kDefaultBackgroundAlpha)); 93 | ui->showBorder->setChecked(kDefaultShowBorder); 94 | borderColor_->setColor(QColor(kDefaultBorderColor)); 95 | ui->tooltipFontSize->setValue(kDefaultTooltipFontSize); 96 | } 97 | 98 | void AppearanceSettingsDialog::saveData() { 99 | model_->setMinIconSize(ui->minSize->value()); 100 | model_->setMaxIconSize(ui->maxSize->value()); 101 | model_->setSpacingFactor(ui->spacingFactor->value()); 102 | QColor backgroundColor(backgroundColor_->color()); 103 | backgroundColor.setAlphaF(transparencyPercentToAlphaF(ui->backgroundTransparency->value())); 104 | model_->setBackgroundColor(backgroundColor); 105 | model_->setShowBorder(ui->showBorder->isChecked()); 106 | model_->setBorderColor(borderColor_->color()); 107 | model_->setTooltipFontSize(ui->tooltipFontSize->value()); 108 | model_->saveAppearanceConfig(); 109 | } 110 | 111 | } // namespace ksmoothdock 112 | -------------------------------------------------------------------------------- /src/view/appearance_settings_dialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_APPEARANCE_SETTINGS_DIALOG_H_ 20 | #define KSMOOTHDOCK_APPEARANCE_SETTINGS_DIALOG_H_ 21 | 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | 28 | namespace Ui { 29 | class AppearanceSettingsDialog; 30 | } 31 | 32 | namespace ksmoothdock { 33 | 34 | class AppearanceSettingsDialog : public QDialog { 35 | Q_OBJECT 36 | 37 | public: 38 | AppearanceSettingsDialog(QWidget* parent, MultiDockModel* model); 39 | ~AppearanceSettingsDialog(); 40 | 41 | void reload() { loadData(); } 42 | 43 | public slots: 44 | void accept() override; 45 | void buttonClicked(QAbstractButton* button); 46 | 47 | private: 48 | void loadData(); 49 | void resetData(); 50 | void saveData(); 51 | 52 | Ui::AppearanceSettingsDialog *ui; 53 | KColorButton* backgroundColor_; 54 | KColorButton* borderColor_; 55 | 56 | MultiDockModel* model_; 57 | 58 | friend class AppearanceSettingsDialogTest; 59 | }; 60 | 61 | } // namespace ksmoothdock 62 | 63 | #endif // KSMOOTHDOCK_APPEARANCE_SETTINGS_DIALOG_H_ 64 | -------------------------------------------------------------------------------- /src/view/appearance_settings_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AppearanceSettingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 801 10 | 360 11 | 12 | 13 | 14 | Appearance Settings 15 | 16 | 17 | 18 | 19 | 34 20 | 290 21 | 731 22 | 36 23 | 24 | 25 | 26 | Qt::Horizontal 27 | 28 | 29 | QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults 30 | 31 | 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 40 39 | 30 40 | 220 41 | 40 42 | 43 | 44 | 45 | Minimum icon size 46 | 47 | 48 | 49 | 50 | 51 | 260 52 | 30 53 | 70 54 | 40 55 | 56 | 57 | 58 | 16 59 | 60 | 61 | 64 62 | 63 | 64 | 8 65 | 66 | 67 | 68 | 69 | 70 | 440 71 | 30 72 | 220 73 | 40 74 | 75 | 76 | 77 | Maximum icon size 78 | 79 | 80 | 81 | 82 | 83 | 660 84 | 30 85 | 70 86 | 40 87 | 88 | 89 | 90 | 32 91 | 92 | 93 | 192 94 | 95 | 96 | 8 97 | 98 | 99 | 100 | 101 | 102 | 440 103 | 90 104 | 220 105 | 40 106 | 107 | 108 | 109 | Panel transparency 110 | 111 | 112 | 113 | 114 | 115 | 40 116 | 150 117 | 220 118 | 40 119 | 120 | 121 | 122 | Background color 123 | 124 | 125 | 126 | 127 | 128 | 440 129 | 210 130 | 220 131 | 40 132 | 133 | 134 | 135 | Show panel border 136 | 137 | 138 | 139 | 140 | 141 | 440 142 | 150 143 | 220 144 | 40 145 | 146 | 147 | 148 | Border color 149 | 150 | 151 | 152 | 153 | 154 | 40 155 | 210 156 | 220 157 | 40 158 | 159 | 160 | 161 | Tooltip font size 162 | 163 | 164 | 165 | 166 | 167 | 260 168 | 210 169 | 70 170 | 40 171 | 172 | 173 | 174 | 8 175 | 176 | 177 | 28 178 | 179 | 180 | 2 181 | 182 | 183 | 184 | 185 | 186 | 40 187 | 90 188 | 220 189 | 40 190 | 191 | 192 | 193 | Icon spacing factor 194 | 195 | 196 | 197 | 198 | 199 | 660 200 | 90 201 | 100 202 | 40 203 | 204 | 205 | 206 | % 207 | 208 | 209 | 100 210 | 211 | 212 | 5 213 | 214 | 215 | 100 216 | 217 | 218 | 219 | 220 | 221 | 260 222 | 90 223 | 70 224 | 40 225 | 226 | 227 | 228 | 1 229 | 230 | 231 | 0.100000000000000 232 | 233 | 234 | 0.900000000000000 235 | 236 | 237 | 0.100000000000000 238 | 239 | 240 | 0.500000000000000 241 | 242 | 243 | 244 | 245 | 246 | 247 | buttonBox 248 | accepted() 249 | AppearanceSettingsDialog 250 | accept() 251 | 252 | 253 | 248 254 | 254 255 | 256 | 257 | 157 258 | 274 259 | 260 | 261 | 262 | 263 | buttonBox 264 | rejected() 265 | AppearanceSettingsDialog 266 | reject() 267 | 268 | 269 | 316 270 | 260 271 | 272 | 273 | 286 274 | 274 275 | 276 | 277 | 278 | 279 | 280 | -------------------------------------------------------------------------------- /src/view/appearance_settings_dialog_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "appearance_settings_dialog.h" 20 | #include "ui_appearance_settings_dialog.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace ksmoothdock { 31 | 32 | class AppearanceSettingsDialogTest: public QObject { 33 | Q_OBJECT 34 | 35 | private slots: 36 | void init() { 37 | QTemporaryDir configDir; 38 | model_ = std::make_unique(configDir.path()); 39 | model_->setMinIconSize(48); 40 | model_->setMaxIconSize(128); 41 | model_->setSpacingFactor(0.5); 42 | QColor color("white"); 43 | color.setAlphaF(0.42); 44 | model_->setBackgroundColor(color); 45 | model_->setShowBorder(true); 46 | model_->setBorderColor(QColor("white")); 47 | model_->setTooltipFontSize(20); 48 | 49 | dialog_ = std::make_unique(nullptr, model_.get()); 50 | } 51 | 52 | // Tests UI initialization. 53 | void uiInit(); 54 | 55 | // Tests OK button/logic. 56 | void ok(); 57 | 58 | // Tests Apply button/logic. 59 | void apply(); 60 | 61 | // Tests Cancel button/logic. 62 | void cancel(); 63 | 64 | private: 65 | static bool compareDouble(double x, double y) { 66 | static constexpr double kDelta = 0.01; 67 | return std::abs(x - y) < kDelta; 68 | } 69 | 70 | std::unique_ptr model_; 71 | std::unique_ptr dialog_; 72 | }; 73 | 74 | void AppearanceSettingsDialogTest::uiInit() { 75 | QCOMPARE(dialog_->ui->minSize->value(), 48); 76 | QCOMPARE(dialog_->ui->maxSize->value(), 128); 77 | compareDouble(dialog_->ui->spacingFactor->value(), 0.5); 78 | QCOMPARE(dialog_->backgroundColor_->color(), QColor("white")); 79 | QCOMPARE(dialog_->ui->backgroundTransparency->value(), 58); 80 | QCOMPARE(dialog_->ui->showBorder->isChecked(), true); 81 | QCOMPARE(dialog_->borderColor_->color(), QColor("white")); 82 | QCOMPARE(dialog_->ui->tooltipFontSize->value(), 20); 83 | } 84 | 85 | void AppearanceSettingsDialogTest::ok() { 86 | dialog_->ui->minSize->setValue(40); 87 | dialog_->ui->maxSize->setValue(80); 88 | dialog_->ui->spacingFactor->setValue(0.2); 89 | dialog_->ui->backgroundTransparency->setValue(90); 90 | dialog_->backgroundColor_->setColor(QColor("green")); 91 | dialog_->ui->showBorder->setChecked(false); 92 | dialog_->borderColor_->setColor(QColor("blue")); 93 | dialog_->ui->tooltipFontSize->setValue(24); 94 | 95 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Ok), 96 | Qt::LeftButton); 97 | 98 | // Tests that the model has been updated. 99 | QCOMPARE(model_->minIconSize(), 40); 100 | QCOMPARE(model_->maxIconSize(), 80); 101 | compareDouble(dialog_->ui->spacingFactor->value(), 0.2); 102 | QCOMPARE(model_->backgroundColor().rgb(), QColor("green").rgb()); 103 | compareDouble(model_->backgroundColor().alphaF(), 0.1); 104 | QCOMPARE(model_->showBorder(), false); 105 | QCOMPARE(model_->borderColor(), QColor("blue")); 106 | QCOMPARE(model_->tooltipFontSize(), 24); 107 | } 108 | 109 | void AppearanceSettingsDialogTest::apply() { 110 | dialog_->ui->minSize->setValue(40); 111 | dialog_->ui->maxSize->setValue(80); 112 | dialog_->ui->spacingFactor->setValue(0.2); 113 | dialog_->ui->backgroundTransparency->setValue(90); 114 | dialog_->backgroundColor_->setColor(QColor("green")); 115 | dialog_->ui->showBorder->setChecked(false); 116 | dialog_->borderColor_->setColor(QColor("blue")); 117 | dialog_->ui->tooltipFontSize->setValue(24); 118 | 119 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Apply), 120 | Qt::LeftButton); 121 | 122 | // Tests that the model has been updated. 123 | QCOMPARE(model_->minIconSize(), 40); 124 | QCOMPARE(model_->maxIconSize(), 80); 125 | compareDouble(dialog_->ui->spacingFactor->value(), 0.2); 126 | QCOMPARE(model_->backgroundColor().rgb(), QColor("green").rgb()); 127 | compareDouble(model_->backgroundColor().alphaF(), 0.1); 128 | QCOMPARE(model_->showBorder(), false); 129 | QCOMPARE(model_->borderColor(), QColor("blue")); 130 | QCOMPARE(model_->tooltipFontSize(), 24); 131 | } 132 | 133 | void AppearanceSettingsDialogTest::cancel() { 134 | dialog_->ui->minSize->setValue(40); 135 | dialog_->ui->maxSize->setValue(80); 136 | dialog_->ui->spacingFactor->setValue(0.2); 137 | dialog_->ui->backgroundTransparency->setValue(90); 138 | dialog_->backgroundColor_->setColor(QColor("green")); 139 | dialog_->ui->showBorder->setChecked(false); 140 | dialog_->borderColor_->setColor(QColor("blue")); 141 | dialog_->ui->tooltipFontSize->setValue(24); 142 | 143 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Cancel), 144 | Qt::LeftButton); 145 | 146 | // Tests that the model has not been updated. 147 | QCOMPARE(model_->minIconSize(), 48); 148 | QCOMPARE(model_->maxIconSize(), 128); 149 | compareDouble(dialog_->ui->spacingFactor->value(), 0.5); 150 | QCOMPARE(model_->backgroundColor().rgb(), QColor("white").rgb()); 151 | compareDouble(model_->backgroundColor().alphaF(), 0.42); 152 | QCOMPARE(model_->showBorder(), true); 153 | QCOMPARE(model_->borderColor(), QColor("white")); 154 | QCOMPARE(model_->tooltipFontSize(), 20); 155 | } 156 | 157 | } // namespace ksmoothdock 158 | 159 | QTEST_MAIN(ksmoothdock::AppearanceSettingsDialogTest) 160 | #include "appearance_settings_dialog_test.moc" 161 | -------------------------------------------------------------------------------- /src/view/application_menu.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "application_menu.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "dock_panel.h" 35 | #include "program.h" 36 | #include 37 | 38 | namespace ksmoothdock { 39 | 40 | int ApplicationMenuStyle::pixelMetric( 41 | PixelMetric metric, const QStyleOption *option, const QWidget *widget) 42 | const { 43 | if (metric == QStyle::PM_SmallIconSize) { 44 | return kApplicationMenuIconSize; 45 | } 46 | return QProxyStyle::pixelMetric(metric, option, widget); 47 | } 48 | 49 | ApplicationMenu::ApplicationMenu( 50 | DockPanel *parent, MultiDockModel* model, Qt::Orientation orientation, 51 | int minSize, int maxSize) 52 | : IconBasedDockItem(parent, "" /* label */, orientation, "" /* iconName */, 53 | minSize, maxSize), 54 | model_(model), 55 | showingMenu_(false) { 56 | menu_.setStyle(&style_); 57 | menu_.setStyleSheet(getStyleSheet()); 58 | 59 | loadConfig(); 60 | buildMenu(); 61 | 62 | createContextMenu(); 63 | 64 | connect(&menu_, SIGNAL(aboutToShow()), parent_, 65 | SLOT(setStrutForApplicationMenu())); 66 | connect(&menu_, &QMenu::aboutToShow, this, 67 | [this]() { showingMenu_ = true; } ); 68 | connect(&menu_, SIGNAL(aboutToHide()), parent_, SLOT(setStrut())); 69 | connect(&menu_, &QMenu::aboutToHide, this, 70 | [this]() { showingMenu_ = false; } ); 71 | connect(model_, SIGNAL(applicationMenuConfigChanged()), 72 | this, SLOT(reloadMenu())); 73 | } 74 | 75 | void ApplicationMenu::draw(QPainter* painter) const { 76 | if (showingMenu_) { 77 | drawHighlightedIcon(model_->backgroundColor(), left_, top_, getWidth(), getHeight(), 78 | minSize_ / 4 - 4, size_ / 8, painter); 79 | } 80 | IconBasedDockItem::draw(painter); 81 | } 82 | 83 | void ApplicationMenu::mousePressEvent(QMouseEvent *e) { 84 | if (e->button() == Qt::LeftButton) { 85 | menu_.popup(parent_->applicationMenuPosition(getMenuSize())); 86 | } else if (e->button() == Qt::RightButton) { 87 | contextMenu_.popup(e->globalPos()); 88 | } 89 | } 90 | 91 | void ApplicationMenu::reloadMenu() { 92 | menu_.clear(); 93 | buildMenu(); 94 | } 95 | 96 | bool ApplicationMenu::eventFilter(QObject* object, QEvent* event) { 97 | QMenu* menu = dynamic_cast(object); 98 | if (menu) { 99 | if (event->type() == QEvent::Show) { 100 | menu->popup(parent_->applicationSubMenuPosition(getMenuSize(), 101 | menu->geometry())); 102 | // Filter this event. 103 | return true; 104 | } else if (event->type() == QEvent::MouseButtonPress) { 105 | QMouseEvent* mouseEvent = dynamic_cast(event); 106 | if (mouseEvent && mouseEvent->button() == Qt::LeftButton 107 | && menu->activeAction()) { 108 | startMousePos_ = mouseEvent->pos(); 109 | draggedEntry_ = menu->activeAction()->data().toString(); 110 | } 111 | } else if (event->type() == QEvent::MouseMove) { 112 | QMouseEvent* mouseEvent = dynamic_cast(event); 113 | if (mouseEvent && mouseEvent->buttons() & Qt::LeftButton) { 114 | const int distance 115 | = (mouseEvent->pos() - startMousePos_).manhattanLength(); 116 | if (distance >= QApplication::startDragDistance() 117 | && !draggedEntry_.isEmpty()) { 118 | // Start drag. 119 | QMimeData* mimeData = new QMimeData; 120 | mimeData->setData("text/uri-list", 121 | QUrl::fromLocalFile(draggedEntry_).toEncoded()); 122 | 123 | QDrag* drag = new QDrag(this); 124 | drag->setMimeData(mimeData); 125 | drag->exec(Qt::CopyAction); 126 | } 127 | } 128 | } 129 | } 130 | 131 | return QObject::eventFilter(object, event); 132 | } 133 | 134 | QString ApplicationMenu::getStyleSheet() { 135 | QColor bgColor = model_->backgroundColor(); 136 | QColor borderColor = model_->borderColor(); 137 | return " \ 138 | QMenu { \ 139 | background-color: " % bgColor.name(QColor::HexArgb) % ";" 140 | " margin: 1px; \ 141 | padding: 2px; \ 142 | border: 1px transparent; \ 143 | border-radius: 3px; \ 144 | } \ 145 | \ 146 | QMenu::item { \ 147 | font: bold; \ 148 | color: white; \ 149 | background-color: transparent; \ 150 | padding: 4px 45px 4px 45px; \ 151 | } \ 152 | \ 153 | QMenu::item:selected { \ 154 | background-color: " % bgColor.name(QColor::HexArgb) % ";" 155 | " border: 1px solid " % borderColor.name() % ";" 156 | " border-radius: 3px; \ 157 | } \ 158 | \ 159 | QMenu::separator { \ 160 | margin: 5px; \ 161 | height: 1px; \ 162 | background: " % borderColor.name() % ";" 163 | "}"; 164 | } 165 | 166 | void ApplicationMenu::loadConfig() { 167 | setLabel(model_->applicationMenuName()); 168 | setIconName(model_->applicationMenuIcon()); 169 | } 170 | 171 | void ApplicationMenu::buildMenu() { 172 | addToMenu(model_->applicationMenuCategories()); 173 | menu_.addSeparator(); 174 | addToMenu(ApplicationMenuConfig::kSessionSystemCategories); 175 | addEntry(ApplicationMenuConfig::kSearchEntry, &menu_); 176 | } 177 | 178 | void ApplicationMenu::addToMenu(const std::vector& categories) { 179 | for (const auto& category : categories) { 180 | if (category.entries.empty()) { 181 | continue; 182 | } 183 | 184 | QMenu* menu = menu_.addMenu(loadIcon(category.icon), category.displayName); 185 | menu->setStyle(&style_); 186 | for (const auto& entry : category.entries) { 187 | addEntry(entry, menu); 188 | } 189 | menu->installEventFilter(this); 190 | } 191 | } 192 | 193 | void ApplicationMenu::addEntry(const ApplicationEntry &entry, QMenu *menu) { 194 | QAction* action = menu->addAction(loadIcon(entry.icon), entry.name, this, 195 | [&entry]() { 196 | Program::launch(entry.command); 197 | }); 198 | action->setData(entry.desktopFile); 199 | } 200 | 201 | QIcon ApplicationMenu::loadIcon(const QString &icon) { 202 | return QIcon(KIconLoader::global()->loadIcon( 203 | icon, KIconLoader::NoGroup, kApplicationMenuIconSize)); 204 | } 205 | 206 | void ApplicationMenu::createContextMenu() { 207 | contextMenu_.addAction(QIcon::fromTheme("configure"), 208 | i18n("Application Menu &Settings"), 209 | parent_, 210 | [this] { parent_->showApplicationMenuSettingsDialog(); }); 211 | contextMenu_.addSeparator(); 212 | parent_->addPanelSettings(&contextMenu_); 213 | } 214 | 215 | } // namespace ksmoothdock 216 | -------------------------------------------------------------------------------- /src/view/application_menu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_APPLICATION_MENU_H_ 20 | #define KSMOOTHDOCK_APPLICATION_MENU_H_ 21 | 22 | #include "icon_based_dock_item.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | namespace ksmoothdock { 36 | 37 | constexpr int kApplicationMenuIconSize = 32; 38 | 39 | class ApplicationMenuStyle : public QProxyStyle { 40 | public: 41 | int pixelMetric(PixelMetric metric, const QStyleOption *option = Q_NULLPTR, 42 | const QWidget *widget = Q_NULLPTR) const override; 43 | }; 44 | 45 | 46 | // The application menu item on the dock. 47 | // 48 | // Left-clicking the item shows a cascading popup menu that contains entries 49 | // for all applications organized by categories. The menu uses a custom style 50 | // e.g. bigger icon size and the same translucent effect as the dock's. 51 | // 52 | // Supports drag-and-drop as a drag source. 53 | // What it means is that you can drag an application entry from the menu 54 | // to other widgets/applications. It doesn't support drag-and-drop within the 55 | // menu itself. 56 | class ApplicationMenu : public QObject, public IconBasedDockItem { 57 | Q_OBJECT 58 | 59 | public: 60 | ApplicationMenu( 61 | DockPanel* parent, 62 | MultiDockModel* model, 63 | Qt::Orientation orientation, 64 | int minSize, 65 | int maxSize); 66 | virtual ~ApplicationMenu() = default; 67 | 68 | void draw(QPainter* painter) const override; 69 | void mousePressEvent(QMouseEvent* e) override; 70 | void loadConfig() override; 71 | 72 | QSize getMenuSize() { return menu_.sizeHint(); } 73 | 74 | public slots: 75 | void reloadMenu(); 76 | 77 | protected: 78 | // Intercepts sub-menus's show events to adjust their position to improve 79 | // visibility. 80 | bool eventFilter(QObject* object, QEvent* event) override; 81 | 82 | private: 83 | QString getStyleSheet(); 84 | 85 | QIcon loadIcon(const QString& icon); 86 | 87 | // Builds the menu from the application entries; 88 | void buildMenu(); 89 | void addToMenu(const std::vector& categories); 90 | void addEntry(const ApplicationEntry& entry, QMenu* menu); 91 | 92 | void createContextMenu(); 93 | 94 | MultiDockModel* model_; 95 | 96 | // The cascading popup menu that contains all application entries. 97 | QMenu menu_; 98 | bool showingMenu_; 99 | 100 | ApplicationMenuStyle style_; 101 | 102 | // Drag support. 103 | 104 | // Starting mouse position, used for minimum drag distance check. 105 | QPoint startMousePos_; 106 | // The desktop file associated with the application entry being dragged. 107 | QString draggedEntry_; 108 | 109 | // Context (right-click) menu. 110 | QMenu contextMenu_; 111 | }; 112 | 113 | } // namespace ksmoothdock 114 | 115 | #endif // KSMOOTHDOCK_APPLICATION_MENU_H_ 116 | -------------------------------------------------------------------------------- /src/view/application_menu_settings_dialog.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "application_menu_settings_dialog.h" 20 | #include "ui_application_menu_settings_dialog.h" 21 | 22 | namespace ksmoothdock { 23 | 24 | ApplicationMenuSettingsDialog::ApplicationMenuSettingsDialog(QWidget* parent, 25 | MultiDockModel* model) 26 | : QDialog(parent), 27 | ui(new Ui::ApplicationMenuSettingsDialog), 28 | model_(model) { 29 | ui->setupUi(this); 30 | icon_ = new KIconButton(this); 31 | icon_->setGeometry(QRect(140, 80, 80, 80)); 32 | 33 | connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), 34 | this, SLOT(buttonClicked(QAbstractButton*))); 35 | 36 | loadData(); 37 | } 38 | 39 | ApplicationMenuSettingsDialog::~ApplicationMenuSettingsDialog() { 40 | delete ui; 41 | } 42 | 43 | void ApplicationMenuSettingsDialog::accept() { 44 | QDialog::accept(); 45 | saveData(); 46 | } 47 | 48 | void ApplicationMenuSettingsDialog::buttonClicked(QAbstractButton *button) { 49 | auto role = ui->buttonBox->buttonRole(button); 50 | if (role == QDialogButtonBox::ApplyRole) { 51 | saveData(); 52 | } 53 | } 54 | 55 | void ApplicationMenuSettingsDialog::loadData() { 56 | ui->name->setText(model_->applicationMenuName()); 57 | icon_->setIcon(model_->applicationMenuIcon()); 58 | ui->strut->setChecked(model_->applicationMenuStrut()); 59 | } 60 | 61 | void ApplicationMenuSettingsDialog::saveData() { 62 | model_->setApplicationMenuName(ui->name->text()); 63 | model_->setApplicationMenuIcon(icon_->icon()); 64 | model_->setApplicationMenuStrut(ui->strut->isChecked()); 65 | model_->saveAppearanceConfig(); 66 | } 67 | 68 | } // namespace ksmoothdock 69 | -------------------------------------------------------------------------------- /src/view/application_menu_settings_dialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_APPLICATION_MENU_SETTINGS_DIALOG_H_ 20 | #define KSMOOTHDOCK_APPLICATION_MENU_SETTINGS_DIALOG_H_ 21 | 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | 28 | namespace Ui { 29 | class ApplicationMenuSettingsDialog; 30 | } 31 | 32 | namespace ksmoothdock { 33 | 34 | class ApplicationMenuSettingsDialog : public QDialog { 35 | Q_OBJECT 36 | 37 | public: 38 | ApplicationMenuSettingsDialog(QWidget* parent, MultiDockModel* model); 39 | ~ApplicationMenuSettingsDialog(); 40 | 41 | void reload() { loadData(); } 42 | 43 | public slots: 44 | void accept() override; 45 | void buttonClicked(QAbstractButton* button); 46 | 47 | private: 48 | void loadData(); 49 | void saveData(); 50 | 51 | Ui::ApplicationMenuSettingsDialog *ui; 52 | KIconButton* icon_; 53 | 54 | MultiDockModel* model_; 55 | 56 | friend class ApplicationMenuSettingsDialogTest; 57 | }; 58 | 59 | } // namespace ksmoothdock 60 | 61 | #endif // KSMOOTHDOCK_APPLICATION_MENU_SETTINGS_DIALOG_H_ 62 | -------------------------------------------------------------------------------- /src/view/application_menu_settings_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ApplicationMenuSettingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 500 10 | 310 11 | 12 | 13 | 14 | Application Menu Settings 15 | 16 | 17 | 18 | 19 | 40 20 | 250 21 | 420 22 | 32 23 | 24 | 25 | 26 | Qt::Horizontal 27 | 28 | 29 | QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok 30 | 31 | 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 40 39 | 30 40 | 91 41 | 23 42 | 43 | 44 | 45 | Name 46 | 47 | 48 | 49 | 50 | 51 | 140 52 | 20 53 | 320 54 | 36 55 | 56 | 57 | 58 | 59 | 60 | 61 | 40 62 | 110 63 | 91 64 | 23 65 | 66 | 67 | 68 | Icon 69 | 70 | 71 | 72 | 73 | 74 | 40 75 | 190 76 | 421 77 | 29 78 | 79 | 80 | 81 | Reserve screen space when showing 82 | 83 | 84 | 85 | 86 | 87 | 88 | buttonBox 89 | accepted() 90 | ApplicationMenuSettingsDialog 91 | accept() 92 | 93 | 94 | 248 95 | 254 96 | 97 | 98 | 157 99 | 274 100 | 101 | 102 | 103 | 104 | buttonBox 105 | rejected() 106 | ApplicationMenuSettingsDialog 107 | reject() 108 | 109 | 110 | 316 111 | 260 112 | 113 | 114 | 286 115 | 274 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /src/view/application_menu_settings_dialog_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "application_menu_settings_dialog.h" 20 | #include "ui_application_menu_settings_dialog.h" 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace ksmoothdock { 29 | 30 | class ApplicationMenuSettingsDialogTest: public QObject { 31 | Q_OBJECT 32 | 33 | private slots: 34 | void init() { 35 | QTemporaryDir configDir; 36 | model_ = std::make_unique(configDir.path()); 37 | model_->setApplicationMenuName("Applications"); 38 | model_->setApplicationMenuIcon("start-here-kde"); 39 | 40 | dialog_ = std::make_unique(nullptr, 41 | model_.get()); 42 | } 43 | 44 | // Tests UI initialization. 45 | void uiInit(); 46 | 47 | // Tests OK button/logic. 48 | void ok(); 49 | 50 | // Tests Apply button/logic. 51 | void apply(); 52 | 53 | // Tests Cancel button/logic. 54 | void cancel(); 55 | 56 | private: 57 | std::unique_ptr model_; 58 | std::unique_ptr dialog_; 59 | }; 60 | 61 | void ApplicationMenuSettingsDialogTest::uiInit() { 62 | QCOMPARE(dialog_->ui->name->text(), QString("Applications")); 63 | QCOMPARE(dialog_->icon_->icon(), QString("start-here-kde")); 64 | } 65 | 66 | void ApplicationMenuSettingsDialogTest::ok() { 67 | dialog_->ui->name->setText("Start"); 68 | dialog_->icon_->setIcon("start-here"); 69 | 70 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Ok), 71 | Qt::LeftButton); 72 | 73 | // Tests that the model has been updated. 74 | QCOMPARE(model_->applicationMenuName(), QString("Start")); 75 | QCOMPARE(model_->applicationMenuIcon(), QString("start-here")); 76 | } 77 | 78 | void ApplicationMenuSettingsDialogTest::apply() { 79 | dialog_->ui->name->setText("Start"); 80 | dialog_->icon_->setIcon("start-here"); 81 | 82 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Apply), 83 | Qt::LeftButton); 84 | 85 | // Tests that the model has been updated. 86 | QCOMPARE(model_->applicationMenuName(), QString("Start")); 87 | QCOMPARE(model_->applicationMenuIcon(), QString("start-here")); 88 | } 89 | 90 | void ApplicationMenuSettingsDialogTest::cancel() { 91 | dialog_->ui->name->setText("Start"); 92 | dialog_->icon_->setIcon("start-here"); 93 | 94 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Cancel), 95 | Qt::LeftButton); 96 | 97 | // Tests that the model has not been updated. 98 | QCOMPARE(model_->applicationMenuName(), QString("Applications")); 99 | QCOMPARE(model_->applicationMenuIcon(), QString("start-here-kde")); 100 | } 101 | 102 | } // namespace ksmoothdock 103 | 104 | QTEST_MAIN(ksmoothdock::ApplicationMenuSettingsDialogTest) 105 | #include "application_menu_settings_dialog_test.moc" 106 | -------------------------------------------------------------------------------- /src/view/calendar.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "calendar.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | namespace ksmoothdock { 28 | 29 | Calendar::Calendar(QWidget* parent) 30 | : QDialog(parent), 31 | calendar_(this) { 32 | KWindowSystem::setState(winId(), NET::SkipTaskbar); 33 | setWindowTitle(i18n("Calendar")); 34 | calendar_.setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader); 35 | resize(calendar_.sizeHint()); 36 | } 37 | 38 | void Calendar::toggleCalendar() { 39 | calendar_.setSelectedDate(QDate::currentDate()); 40 | setVisible(!isVisible()); 41 | } 42 | 43 | } // namespace ksmoothdock 44 | -------------------------------------------------------------------------------- /src/view/calendar.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_CALENDAR_H_ 20 | #define KSMOOTHDOCK_CALENDAR_H_ 21 | 22 | #include 23 | #include 24 | 25 | namespace ksmoothdock { 26 | 27 | // A calendar widget. This is shown when the user clicks on the clock. 28 | class Calendar : public QDialog { 29 | public: 30 | Calendar(QWidget* parent); 31 | 32 | // Toggles showing the calendar. 33 | // 34 | // This also resets the selected date to the current date. 35 | void toggleCalendar(); 36 | 37 | private: 38 | QCalendarWidget calendar_; 39 | }; 40 | 41 | } // namespace ksmoothdock 42 | 43 | #endif // KSMOOTHDOCK_CALENDAR_H_ 44 | -------------------------------------------------------------------------------- /src/view/clock.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "clock.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | #include "dock_panel.h" 33 | #include "program.h" 34 | #include 35 | #include 36 | 37 | namespace ksmoothdock { 38 | 39 | constexpr float Clock::kWhRatio; 40 | constexpr float Clock::kDelta; 41 | 42 | Clock::Clock(DockPanel* parent, MultiDockModel* model, 43 | Qt::Orientation orientation, int minSize, int maxSize) 44 | : IconlessDockItem(parent, "" /* label */, orientation, minSize, maxSize, 45 | kWhRatio), 46 | model_(model), 47 | calendar_(parent), 48 | fontFamilyGroup_(this) { 49 | createMenu(); 50 | loadConfig(); 51 | 52 | QTimer* timer = new QTimer(this); 53 | connect(timer, SIGNAL(timeout()), this, SLOT(updateTime())); 54 | timer->start(1000); // update the time every second. 55 | } 56 | 57 | void Clock::draw(QPainter *painter) const { 58 | const QString timeFormat = model_->use24HourClock() ? "hh:mm" : "hh:mm AP"; 59 | const QString time = QTime::currentTime().toString(timeFormat); 60 | // The reference time used to calculate the font size. 61 | const QString referenceTime = QTime(8, 8).toString(timeFormat); 62 | 63 | painter->setFont(adjustFontSize(getWidth(), getHeight(), referenceTime, 64 | model_->clockFontScaleFactor(), 65 | model_->clockFontFamily())); 66 | painter->setRenderHint(QPainter::TextAntialiasing); 67 | 68 | if (size_ > minSize_) { 69 | drawBorderedText(left_, top_, getWidth(), getHeight(), Qt::AlignCenter, 70 | time, 2 /* borderWidth */, Qt::black, Qt::white, painter); 71 | } else { 72 | painter->setPen(Qt::white); 73 | painter->drawText(left_, top_, getWidth(), getHeight(), Qt::AlignCenter, 74 | time); 75 | } 76 | } 77 | 78 | void Clock::mousePressEvent(QMouseEvent *e) { 79 | if (e->button() == Qt::LeftButton) { 80 | calendar_.toggleCalendar(); 81 | } else if (e->button() == Qt::RightButton) { 82 | // In case other docks have changed the config. 83 | loadConfig(); 84 | menu_.popup(e->globalPos()); 85 | } 86 | } 87 | 88 | QString Clock::getLabel() const { 89 | return QLocale::system().toString(QDate::currentDate(), QLocale::LongFormat); 90 | } 91 | 92 | void Clock::updateTime() { 93 | parent_->update(); 94 | } 95 | 96 | void Clock::setDateAndTime() { 97 | Program::launch("kcmshell5 clock"); 98 | } 99 | 100 | void Clock::setFontScaleFactor(float fontScaleFactor) { 101 | largeFontAction_->setChecked( 102 | fontScaleFactor > kLargeClockFontScaleFactor - kDelta); 103 | mediumFontAction_->setChecked( 104 | fontScaleFactor > kMediumClockFontScaleFactor - kDelta && 105 | fontScaleFactor < kMediumClockFontScaleFactor + kDelta); 106 | smallFontAction_->setChecked( 107 | fontScaleFactor < kSmallClockFontScaleFactor + kDelta); 108 | } 109 | 110 | void Clock::setLargeFont() { 111 | setFontScaleFactor(kLargeClockFontScaleFactor); 112 | saveConfig(); 113 | } 114 | 115 | void Clock::setMediumFont() { 116 | setFontScaleFactor(kMediumClockFontScaleFactor); 117 | saveConfig(); 118 | } 119 | 120 | void Clock::setSmallFont() { 121 | setFontScaleFactor(kSmallClockFontScaleFactor); 122 | saveConfig(); 123 | } 124 | 125 | void Clock::createMenu() { 126 | menu_.addAction(QIcon::fromTheme("preferences-system-time"), 127 | i18n("Date and Time &Settings"), 128 | this, 129 | SLOT(setDateAndTime())); 130 | 131 | use24HourClockAction_ = menu_.addAction( 132 | i18n("Use 24-hour Clock"), this, 133 | [this] { 134 | saveConfig(); 135 | }); 136 | use24HourClockAction_->setCheckable(true); 137 | 138 | QMenu* fontSize = menu_.addMenu(i18n("Font Size")); 139 | largeFontAction_ = fontSize->addAction(i18n("Large Font"), 140 | this, 141 | SLOT(setLargeFont())); 142 | largeFontAction_->setCheckable(true); 143 | mediumFontAction_ = fontSize->addAction(i18n("Medium Font"), 144 | this, 145 | SLOT(setMediumFont())); 146 | mediumFontAction_->setCheckable(true); 147 | smallFontAction_ = fontSize->addAction(i18n("Small Font"), 148 | this, 149 | SLOT(setSmallFont())); 150 | smallFontAction_->setCheckable(true); 151 | 152 | QMenu* fontFamily = menu_.addMenu(i18n("Font Family")); 153 | for (const auto& family : getBaseFontFamilies()) { 154 | auto fontFamilyAction = fontFamily->addAction(family, this, [this, family]{ 155 | model_->setClockFontFamily(family); 156 | model_->saveAppearanceConfig(true /* repaintOnly */); 157 | }); 158 | fontFamilyAction->setCheckable(true); 159 | fontFamilyAction->setActionGroup(&fontFamilyGroup_); 160 | fontFamilyAction->setChecked(family == model_->clockFontFamily()); 161 | } 162 | 163 | menu_.addSeparator(); 164 | parent_->addPanelSettings(&menu_); 165 | } 166 | 167 | void Clock::loadConfig() { 168 | use24HourClockAction_->setChecked(model_->use24HourClock()); 169 | setFontScaleFactor(model_->clockFontScaleFactor()); 170 | } 171 | 172 | void Clock::saveConfig() { 173 | model_->setUse24HourClock(use24HourClockAction_->isChecked()); 174 | model_->setClockFontScaleFactor(fontScaleFactor()); 175 | model_->saveAppearanceConfig(true /* repaintOnly */); 176 | } 177 | 178 | } // namespace ksmoothdock 179 | -------------------------------------------------------------------------------- /src/view/clock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_CLOCK_H_ 20 | #define KSMOOTHDOCK_CLOCK_H_ 21 | 22 | #include "iconless_dock_item.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "calendar.h" 31 | #include 32 | 33 | namespace ksmoothdock { 34 | 35 | // A digital clock. 36 | class Clock : public QObject, public IconlessDockItem { 37 | Q_OBJECT 38 | 39 | public: 40 | Clock(DockPanel* parent, MultiDockModel* model, Qt::Orientation orientation, 41 | int minSize, int maxSize); 42 | virtual ~Clock() = default; 43 | 44 | void draw(QPainter* painter) const override; 45 | void mousePressEvent(QMouseEvent* e) override; 46 | void loadConfig() override; 47 | QString getLabel() const override; 48 | bool beforeTask(const QString& command) override { return false; } 49 | 50 | public slots: 51 | void updateTime(); 52 | 53 | void setDateAndTime(); 54 | 55 | void setFontScaleFactor(float fontScaleFactor); 56 | void setLargeFont(); 57 | void setMediumFont(); 58 | void setSmallFont(); 59 | 60 | private: 61 | static constexpr float kWhRatio = 2.8; 62 | static constexpr float kDelta = 0.01; 63 | 64 | float fontScaleFactor() { 65 | return largeFontAction_->isChecked() 66 | ? kLargeClockFontScaleFactor 67 | : mediumFontAction_->isChecked() ? kMediumClockFontScaleFactor 68 | : kSmallClockFontScaleFactor; 69 | } 70 | 71 | // Creates the context menu. 72 | void createMenu(); 73 | 74 | void saveConfig(); 75 | 76 | MultiDockModel* model_; 77 | 78 | Calendar calendar_; 79 | 80 | // Context menu. 81 | QMenu menu_; 82 | 83 | QAction* use24HourClockAction_; 84 | QAction* largeFontAction_; 85 | QAction* mediumFontAction_; 86 | QAction* smallFontAction_; 87 | 88 | QActionGroup fontFamilyGroup_; 89 | }; 90 | 91 | } // namespace ksmoothdock 92 | 93 | #endif // KSMOOTHDOCK_CLOCK_H_ 94 | -------------------------------------------------------------------------------- /src/view/desktop_selector.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "desktop_selector.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include "dock_panel.h" 32 | #include 33 | #include 34 | 35 | namespace ksmoothdock { 36 | 37 | DesktopSelector::DesktopSelector(DockPanel* parent, MultiDockModel* model, 38 | Qt::Orientation orientation, int minSize, 39 | int maxSize, int desktop, int screen) 40 | : IconBasedDockItem(parent, 41 | i18n("Desktop ") + QString::number(desktop), 42 | orientation, "" /* no icon yet */, minSize, maxSize), 43 | model_(model), 44 | desktop_(desktop), 45 | screen_(screen), 46 | desktopWidth_(parent->screenGeometry().width()), 47 | desktopHeight_(parent->screenGeometry().height()), 48 | hasCustomWallpaper_(false) { 49 | createMenu(); 50 | loadConfig(); 51 | } 52 | 53 | void DesktopSelector::draw(QPainter* painter) const { 54 | if (hasCustomWallpaper_) { 55 | IconBasedDockItem::draw(painter); 56 | } else { 57 | // Draw rectangles with desktop numbers if no custom wallpapers set. 58 | QColor fillColor = model_->backgroundColor().lighter(); 59 | fillColor.setAlphaF(0.42); 60 | painter->fillRect(left_, top_, getWidth(), getHeight(), QBrush(fillColor)); 61 | } 62 | 63 | if (model_->showDesktopNumber()) { 64 | painter->setFont(adjustFontSize(getWidth(), getHeight(), 65 | "0" /* reference string */, 66 | 0.5 /* scale factor */)); 67 | painter->setRenderHint(QPainter::TextAntialiasing); 68 | drawBorderedText(left_, top_, getWidth(), getHeight(), Qt::AlignCenter, 69 | QString::number(desktop_), 1 /* borderWidth */, Qt::black, 70 | Qt::white, painter); 71 | } 72 | 73 | // Draw the border for the current desktop. 74 | if (isCurrentDesktop()) { 75 | painter->setPen(model_->borderColor()); 76 | painter->drawRect(left_ - 1, top_ - 1, getWidth() + 1, getHeight() + 1); 77 | } 78 | } 79 | 80 | void DesktopSelector::mousePressEvent(QMouseEvent* e) { 81 | if (e->button() == Qt::LeftButton) { 82 | if (isCurrentDesktop()) { 83 | KWindowSystem::setShowingDesktop(!KWindowSystem::showingDesktop()); 84 | } else { 85 | KWindowSystem::setCurrentDesktop(desktop_); 86 | } 87 | } else if (e->button() == Qt::RightButton) { 88 | // In case other DesktopSelectors have changed the config. 89 | showDesktopNumberAction_->setChecked(model_->showDesktopNumber()); 90 | menu_.popup(e->globalPos()); 91 | } 92 | } 93 | 94 | void DesktopSelector::loadConfig() { 95 | const auto& wallpaper = model_->wallpaper(desktop_, screen_); 96 | if (!wallpaper.isEmpty() && QFile::exists(wallpaper)) { 97 | setIconScaled(QPixmap(wallpaper)); 98 | hasCustomWallpaper_ = true; 99 | } 100 | 101 | showDesktopNumberAction_->setChecked(model_->showDesktopNumber()); 102 | } 103 | 104 | void DesktopSelector::saveConfig() { 105 | model_->setShowDesktopNumber(showDesktopNumberAction_->isChecked()); 106 | model_->saveAppearanceConfig(true /* repaintOnly */); 107 | } 108 | 109 | void DesktopSelector::setIconScaled(const QPixmap& icon) { 110 | if (icon.width() * desktopHeight_ != icon.height() * desktopWidth_) { 111 | QPixmap scaledIcon = icon.scaled(desktopWidth_, desktopHeight_); 112 | setIcon(scaledIcon); 113 | } else { 114 | setIcon(icon); 115 | } 116 | } 117 | 118 | void DesktopSelector::createMenu() { 119 | menu_.addAction( 120 | QIcon::fromTheme("preferences-desktop-wallpaper"), 121 | i18n("Set Wallpaper for Desktop ") + QString::number(desktop_), 122 | parent_, 123 | [this] { 124 | parent_->showWallpaperSettingsDialog(desktop_); 125 | }); 126 | showDesktopNumberAction_ = menu_.addAction( 127 | i18n("Show Desktop Number"), this, 128 | [this] { 129 | saveConfig(); 130 | }); 131 | showDesktopNumberAction_->setCheckable(true); 132 | 133 | menu_.addSeparator(); 134 | parent_->addPanelSettings(&menu_); 135 | } 136 | 137 | } // namespace ksmoothdock 138 | -------------------------------------------------------------------------------- /src/view/desktop_selector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_DESKTOP_SELECTOR_H_ 20 | #define KSMOOTHDOCK_DESKTOP_SELECTOR_H_ 21 | 22 | #include "icon_based_dock_item.h" 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | 35 | namespace ksmoothdock { 36 | 37 | // Pager icons. 38 | class DesktopSelector : public QObject, public IconBasedDockItem { 39 | Q_OBJECT 40 | 41 | public: 42 | DesktopSelector(DockPanel* parent, MultiDockModel* model, 43 | Qt::Orientation orientation, int minSize, int maxSize, 44 | int desktop, int screen); 45 | 46 | virtual ~DesktopSelector() = default; 47 | 48 | int getWidthForSize(int size) const override { 49 | return isHorizontal() ? (size * desktopWidth_ / desktopHeight_) : size; 50 | } 51 | 52 | int getHeightForSize(int size) const override { 53 | return isHorizontal() ? size : (size * desktopHeight_ / desktopWidth_); 54 | } 55 | 56 | void draw(QPainter* painter) const override; 57 | void mousePressEvent(QMouseEvent* e) override; 58 | void loadConfig() override; 59 | 60 | // Sets the icon but scales the pixmap to the screen's width/height ratio. 61 | void setIconScaled(const QPixmap& icon); 62 | 63 | private: 64 | bool isCurrentDesktop() const { 65 | return KWindowSystem::currentDesktop() == desktop_; 66 | } 67 | 68 | void createMenu(); 69 | 70 | void saveConfig(); 71 | 72 | MultiDockModel* model_; 73 | 74 | // The desktop that this desktop selector manages, 1-based. 75 | int desktop_; 76 | // The screen that the parent panel is on, 0-based. 77 | int screen_; 78 | KConfig* config_; 79 | 80 | // Context (right-click) menu. 81 | QMenu menu_; 82 | 83 | QAction* showDesktopNumberAction_; 84 | 85 | int desktopWidth_; 86 | int desktopHeight_; 87 | 88 | bool hasCustomWallpaper_; 89 | }; 90 | 91 | } // namespace ksmoothdock 92 | 93 | #endif // KSMOOTHDOCK_DESKTOP_SELECTOR_H_ 94 | -------------------------------------------------------------------------------- /src/view/desktop_selector_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "desktop_selector.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "multi_dock_view.h" 30 | 31 | namespace ksmoothdock { 32 | 33 | constexpr int kDockId = 1; 34 | constexpr int kDesktop = 1; 35 | constexpr int kScreen = 0; 36 | constexpr int kMinSize = 64; 37 | constexpr int kMaxSize = 64; 38 | 39 | class DesktopSelectorTest: public QObject { 40 | Q_OBJECT 41 | 42 | private slots: 43 | void init() { 44 | QTemporaryDir configDir; 45 | model_ = std::make_unique(configDir.path()); 46 | model_->addDock(); 47 | view_ = std::make_unique(model_.get()); 48 | dock_ = std::make_unique(view_.get(), model_.get(), kDockId); 49 | } 50 | 51 | // Tests that the icon is scaled to screen's width/height ratio if needed. 52 | void setIconScaled(); 53 | 54 | private: 55 | std::unique_ptr model_; 56 | std::unique_ptr view_; 57 | std::unique_ptr dock_; 58 | }; 59 | 60 | void DesktopSelectorTest::setIconScaled() { 61 | QTemporaryFile iconFile; 62 | QVERIFY(iconFile.open()); 63 | QPixmap icon(100, 100); 64 | icon.save(iconFile.fileName(), "PNG"); 65 | model_->setWallpaper(kDesktop, kScreen, iconFile.fileName()); 66 | 67 | DesktopSelector desktopSelector(dock_.get(), model_.get(), Qt::Horizontal, 68 | kMinSize, kMaxSize, kDesktop, kScreen); 69 | 70 | QCOMPARE(desktopSelector.getIcon(kMinSize).height(), kMinSize); 71 | const int desktopWidth = dock_->screenGeometry().width(); 72 | const int desktopHeight = dock_->screenGeometry().height(); 73 | // Gives room to rounding difference. 74 | QVERIFY(std::abs(desktopSelector.getIcon(kMinSize).width() - 75 | desktopWidth * kMinSize / desktopHeight) <= 1); 76 | } 77 | 78 | } // namespace ksmoothdock 79 | 80 | QTEST_MAIN(ksmoothdock::DesktopSelectorTest) 81 | #include "desktop_selector_test.moc" 82 | -------------------------------------------------------------------------------- /src/view/dock_item.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_DOCK_ITEM_H_ 20 | #define KSMOOTHDOCK_DOCK_ITEM_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | namespace ksmoothdock { 30 | 31 | class DockPanel; 32 | 33 | // Base class for all dock items, e.g. launchers and pager icons. 34 | // 35 | // It's a design decision that DockItem is not a sub-class of QWidget, to make 36 | // the dock's parabolic zooming effect smoother. 37 | class DockItem { 38 | public: 39 | DockItem(DockPanel* parent, const QString& label, 40 | Qt::Orientation orientation, int minSize, int maxSize) 41 | : parent_(parent), label_(label), orientation_(orientation), 42 | minSize_(minSize), maxSize_(maxSize), size_(minSize) {} 43 | virtual ~DockItem() {} 44 | 45 | // Gets the width of the item given a size. 46 | virtual int getWidthForSize(int size) const = 0; 47 | 48 | // Gets the height of the item given a size. 49 | virtual int getHeightForSize(int size) const = 0; 50 | 51 | // Draws itself on the parent's canvas. 52 | virtual void draw(QPainter* painter) const = 0; 53 | 54 | // Mouse press event handler. 55 | virtual void mousePressEvent(QMouseEvent* e) = 0; 56 | 57 | // Some dock items (e.g. Application Menu or Clock) have their own global 58 | // (i.e. not dock-specific) config that they need to reload when the config 59 | // has been changed by another dock (not their parent dock). 60 | virtual void loadConfig() {} 61 | 62 | // Handles adding the task, e.g. for a Program dock item. 63 | virtual bool addTask(const TaskInfo& task) { return false; } 64 | 65 | // Handles updating the task, e.g. for a Program dock item. 66 | virtual bool updateTask(const TaskInfo& task) { return false; } 67 | 68 | // Handles removing the task, e.g. for a Program dock item. 69 | virtual bool removeTask(WId wId) { return false; } 70 | 71 | // Does this (Program) dock item already have this task? 72 | virtual bool hasTask(WId wId) { return false; } 73 | 74 | // Will this item be ordered before the Program item for this task? 75 | virtual bool beforeTask(const QString& command) { return true; } 76 | 77 | // Should be removed for example if a Program item has no task and is not pinned. 78 | virtual bool shouldBeRemoved() { return false; } 79 | 80 | // This is virtual so dynamic label can be implemented in its subclasses. 81 | virtual QString getLabel() const { return label_; } 82 | void setLabel(const QString& label) { label_ = label; } 83 | 84 | bool isHorizontal() const { return orientation_ == Qt::Horizontal; } 85 | 86 | void setAnimationStartAsCurrent() { 87 | startLeft_ = left_; 88 | startTop_ = top_; 89 | startSize_ = size_; 90 | } 91 | 92 | void setAnimationEndAsCurrent() { 93 | endLeft_ = left_; 94 | endTop_ = top_; 95 | endSize_ = size_; 96 | } 97 | 98 | void startAnimation(int numSteps) { 99 | left_ = startLeft_; 100 | top_ = startTop_; 101 | size_ = startSize_; 102 | currentStep_ = 0; 103 | numSteps_ = numSteps; 104 | } 105 | 106 | void nextAnimationStep() { 107 | ++currentStep_; 108 | if (currentStep_ <= numSteps_) { 109 | left_ = startLeft_ + (endLeft_ - startLeft_) * currentStep_ / numSteps_; 110 | top_ = startTop_ + (endTop_ - startTop_) * currentStep_ / numSteps_; 111 | size_ = startSize_ + (endSize_ - startSize_) * currentStep_ / numSteps_; 112 | } 113 | } 114 | 115 | // Gets max width, i.e. the width when the item is max zoomed. 116 | int getMaxWidth() const { 117 | return getWidthForSize(maxSize_); 118 | } 119 | 120 | // Gets max height, i.e. the width when the item is max zoomed. 121 | int getMaxHeight() const { 122 | return getHeightForSize(maxSize_); 123 | } 124 | 125 | // Gets min width, i.e. when the item is not zoomed in. 126 | int getMinWidth() const { 127 | return getWidthForSize(minSize_); 128 | } 129 | 130 | // Gets min height, i.e. when the item is not zoomed in. 131 | int getMinHeight() const { 132 | return getHeightForSize(minSize_); 133 | } 134 | 135 | int getWidth() const { 136 | return getWidthForSize(size_); 137 | } 138 | 139 | int getHeight() const { 140 | return getHeightForSize(size_); 141 | } 142 | 143 | protected: 144 | DockPanel* parent_; 145 | QString label_; // Label of the dock item. 146 | Qt::Orientation orientation_; // Orientation (horizontal/vertical). 147 | int minSize_; 148 | int maxSize_; 149 | 150 | int size_; 151 | int left_; 152 | int top_; 153 | // Center when minimized, as x or y depends on whether the orientation is 154 | // horizontal or vertical. This is used when calculating the size of the item 155 | // when the dock is in parabolic zoom. 156 | int minCenter_; 157 | 158 | // For animation. 159 | int startLeft_; 160 | int startTop_; 161 | int startSize_; 162 | int endLeft_; 163 | int endTop_; 164 | int endSize_; 165 | int currentStep_; 166 | int numSteps_; 167 | 168 | private: 169 | friend class DockPanel; 170 | }; 171 | 172 | } // namespace ksmoothdock 173 | 174 | #endif // KSMOOTHDOCK_DOCK_ITEM_H_ 175 | -------------------------------------------------------------------------------- /src/view/dock_panel_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "dock_panel.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include "multi_dock_view.h" 29 | 30 | namespace ksmoothdock { 31 | 32 | constexpr int kDockId = 1; 33 | 34 | class DockPanelTest: public QObject { 35 | Q_OBJECT 36 | 37 | private slots: 38 | void init() { 39 | QTemporaryDir configDir; 40 | model_ = std::make_unique(configDir.path()); 41 | model_->addDock(); 42 | view_ = std::make_unique(model_.get()); 43 | dock_ = std::make_unique(view_.get(), model_.get(), kDockId); 44 | } 45 | 46 | // Tests setting position. 47 | void setPosition(); 48 | 49 | // Tests setting Auto Hide on/off. 50 | void autoHide(); 51 | 52 | // Tests toggling the application menu. 53 | void toggleApplicationMenu(); 54 | 55 | // Tests toggling the pager. 56 | void togglePager(); 57 | 58 | // Tests toggling the clock. 59 | void toggleClock(); 60 | 61 | private: 62 | void verifyPosition(PanelPosition position) { 63 | QCOMPARE(dock_->position_, position); 64 | QCOMPARE(dock_->orientation_, 65 | (position == PanelPosition::Bottom 66 | || position == PanelPosition::Top) 67 | ? Qt::Horizontal : Qt::Vertical); 68 | if (dock_->orientation_ == Qt::Horizontal) { 69 | QVERIFY(dock_->width() > dock_->height()); 70 | } else { 71 | QVERIFY(dock_->width() < dock_->height()); 72 | } 73 | QCOMPARE(dock_->positionTop_->isChecked(), position == PanelPosition::Top); 74 | QCOMPARE(dock_->positionBottom_->isChecked(), 75 | position == PanelPosition::Bottom); 76 | QCOMPARE(dock_->positionLeft_->isChecked(), 77 | position == PanelPosition::Left); 78 | QCOMPARE(dock_->positionRight_->isChecked(), 79 | position == PanelPosition::Right); 80 | } 81 | 82 | void verifyAutoHide(bool enabled) { 83 | QCOMPARE(dock_->autoHide(), enabled); 84 | QCOMPARE(dock_->visibilityAutoHideAction_->isChecked(), enabled); 85 | if (enabled) { 86 | QVERIFY(dock_->width() == 1 || dock_->height() == 1); 87 | } 88 | } 89 | 90 | void verifyApplicationMenu(bool enabled, int itemCount) { 91 | QCOMPARE(dock_->showApplicationMenu_, enabled); 92 | QCOMPARE(dock_->applicationMenuAction_->isChecked(), enabled); 93 | QCOMPARE(dock_->itemCount(), itemCount); 94 | } 95 | 96 | void verifyPager(bool enabled, int itemCount) { 97 | QCOMPARE(dock_->showPager_, enabled); 98 | QCOMPARE(dock_->pagerAction_->isChecked(), enabled); 99 | QCOMPARE(dock_->itemCount(), itemCount); 100 | } 101 | 102 | void verifyClock(bool enabled, int itemCount) { 103 | QCOMPARE(dock_->showClock_, enabled); 104 | QCOMPARE(dock_->clockAction_->isChecked(), enabled); 105 | QCOMPARE(dock_->itemCount(), itemCount); 106 | } 107 | 108 | std::unique_ptr model_; 109 | std::unique_ptr view_; 110 | std::unique_ptr dock_; 111 | }; 112 | 113 | void DockPanelTest::setPosition() { 114 | verifyPosition(PanelPosition::Bottom); 115 | dock_->positionLeft_->trigger(); 116 | verifyPosition(PanelPosition::Left); 117 | dock_->positionRight_->trigger(); 118 | verifyPosition(PanelPosition::Right); 119 | dock_->positionTop_->trigger(); 120 | verifyPosition(PanelPosition::Top); 121 | dock_->positionBottom_->trigger(); 122 | verifyPosition(PanelPosition::Bottom); 123 | } 124 | 125 | void DockPanelTest::autoHide() { 126 | verifyAutoHide(false); 127 | dock_->visibilityAutoHideAction_->trigger(); 128 | verifyAutoHide(true); 129 | dock_->visibilityAlwaysVisibleAction_->trigger(); 130 | verifyAutoHide(false); 131 | } 132 | 133 | void DockPanelTest::toggleApplicationMenu() { 134 | const int itemCount = dock_->itemCount(); 135 | dock_->applicationMenuAction_->trigger(); 136 | verifyApplicationMenu(false, itemCount - 1); 137 | dock_->applicationMenuAction_->trigger(); 138 | verifyApplicationMenu(true, itemCount); 139 | } 140 | 141 | void DockPanelTest::togglePager() { 142 | // TODO(dangvd) 143 | } 144 | 145 | void DockPanelTest::toggleClock() { 146 | const int itemCount = dock_->itemCount(); 147 | dock_->clockAction_->trigger(); 148 | verifyClock(false, itemCount - 1); 149 | dock_->clockAction_->trigger(); 150 | verifyClock(true, itemCount); 151 | } 152 | 153 | } // namespace ksmoothdock 154 | 155 | QTEST_MAIN(ksmoothdock::DockPanelTest) 156 | #include "dock_panel_test.moc" 157 | -------------------------------------------------------------------------------- /src/view/edit_launchers_dialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_EDIT_LAUNCHERS_DIALOG_H_ 20 | #define KSMOOTHDOCK_EDIT_LAUNCHERS_DIALOG_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | namespace Ui { 38 | class EditLaunchersDialog; 39 | } 40 | 41 | namespace ksmoothdock { 42 | 43 | // User data for the items in QListWidget/QComboBox. 44 | struct LauncherInfo { 45 | // The name(label) is already stored as item text in QListWidget/QComboBox. 46 | QString iconName; 47 | QString command; 48 | 49 | LauncherInfo() {} 50 | LauncherInfo(QString iconName2, QString command2) 51 | : iconName(iconName2), command(command2) {} 52 | }; 53 | 54 | QDataStream &operator<<(QDataStream &out, const LauncherInfo& launcher); 55 | QDataStream &operator>>(QDataStream &in, LauncherInfo& launcher); 56 | 57 | class EditLaunchersDialog; 58 | 59 | class LauncherList : public QListWidget { 60 | public: 61 | explicit LauncherList(EditLaunchersDialog* parent); 62 | 63 | protected: 64 | void dragEnterEvent(QDragEnterEvent *event) override; 65 | void dragMoveEvent(QDragMoveEvent* event) override; 66 | void dropEvent(QDropEvent *event) override; 67 | 68 | private: 69 | EditLaunchersDialog* parent_; 70 | }; 71 | 72 | class EditLaunchersDialog : public QDialog { 73 | Q_OBJECT 74 | 75 | public: 76 | EditLaunchersDialog(QWidget* parent, MultiDockModel* model, int dockId); 77 | ~EditLaunchersDialog() = default; 78 | 79 | void reload() { loadData(); } 80 | 81 | void addLauncher(const QString& name, const QString& command, 82 | const QString& iconName); 83 | 84 | public slots: 85 | void accept() override; 86 | void buttonClicked(QAbstractButton* button); 87 | 88 | void refreshSelectedLauncher(QListWidgetItem* current, 89 | QListWidgetItem* previous); 90 | 91 | void addLauncher(); 92 | void addSeparator(); 93 | void removeSelectedLauncher(); 94 | void removeAllLaunchers(); 95 | void updateSelectedLauncher(); 96 | 97 | void openLink(const QString& link); 98 | 99 | void browseCommand(); 100 | void updateInternalCommand(int index); 101 | void updateDBusCommand(int index); 102 | void updateWebCommand(int index); 103 | void updateDirCommand(int index); 104 | void resetCommandLists(); 105 | 106 | private: 107 | static constexpr int kListIconSize = 48; 108 | 109 | void loadData(); 110 | void saveData(); 111 | 112 | QIcon getListItemIcon(const QString& iconName) { 113 | return QIcon(KIconLoader::global()->loadIcon(iconName, 114 | KIconLoader::NoGroup, kListIconSize)); 115 | } 116 | 117 | void populateInternalCommands(); 118 | void populateDBusCommands(); 119 | void populateWebCommands(); 120 | void populateDirCommands(); 121 | 122 | void clearItemDetails(); 123 | 124 | Ui::EditLaunchersDialog *ui; 125 | LauncherList *launchers_; 126 | KIconButton *icon_; 127 | 128 | MultiDockModel* model_; 129 | int dockId_; 130 | 131 | friend class EditLaunchersDialogTest; 132 | }; 133 | 134 | } // namespace ksmoothdock 135 | 136 | Q_DECLARE_METATYPE(ksmoothdock::LauncherInfo); 137 | 138 | #endif // KSMOOTHDOCK_EDIT_LAUNCHERS_DIALOG_H_ 139 | -------------------------------------------------------------------------------- /src/view/edit_launchers_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | EditLaunchersDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1200 10 | 645 11 | 12 | 13 | 14 | Edit Launchers 15 | 16 | 17 | 18 | 19 | 80 20 | 580 21 | 960 22 | 35 23 | 24 | 25 | 26 | Qt::Horizontal 27 | 28 | 29 | QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok 30 | 31 | 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 20 39 | 530 40 | 350 41 | 30 42 | 43 | 44 | 45 | Note: <a href=https://github.com/dangvd/ksmoothdock/wiki/Documentation#editLaunchers_dragAndDrop>Drag and drop</a> is supported. 46 | 47 | 48 | Qt::RichText 49 | 50 | 51 | 52 | 53 | 54 | 420 55 | 80 56 | 180 57 | 40 58 | 59 | 60 | 61 | Add 62 | 63 | 64 | 65 | .. 66 | 67 | 68 | 69 | 70 | 71 | 420 72 | 220 73 | 180 74 | 40 75 | 76 | 77 | 78 | Remove 79 | 80 | 81 | 82 | .. 83 | 84 | 85 | 86 | 87 | 88 | 420 89 | 360 90 | 180 91 | 40 92 | 93 | 94 | 95 | Update 96 | 97 | 98 | 99 | .. 100 | 101 | 102 | 103 | 104 | 105 | 650 106 | 25 107 | 100 108 | 30 109 | 110 | 111 | 112 | Name 113 | 114 | 115 | 116 | 117 | 118 | 760 119 | 20 120 | 421 121 | 36 122 | 123 | 124 | 125 | 126 | 127 | 128 | 650 129 | 105 130 | 100 131 | 30 132 | 133 | 134 | 135 | Command 136 | 137 | 138 | 139 | 140 | 141 | 760 142 | 100 143 | 421 144 | 36 145 | 146 | 147 | 148 | 149 | 150 | 151 | 760 152 | 160 153 | 371 154 | 38 155 | 156 | 157 | 158 | Browse Command 159 | 160 | 161 | 162 | 163 | 164 | 760 165 | 215 166 | 371 167 | 36 168 | 169 | 170 | 171 | 172 | 173 | 174 | 760 175 | 270 176 | 371 177 | 36 178 | 179 | 180 | 181 | 182 | 183 | 184 | 760 185 | 325 186 | 371 187 | 36 188 | 189 | 190 | 191 | 192 | 193 | 194 | 650 195 | 470 196 | 100 197 | 30 198 | 199 | 200 | 201 | Icon 202 | 203 | 204 | 205 | 206 | 207 | 420 208 | 290 209 | 180 210 | 40 211 | 212 | 213 | 214 | Remove All 215 | 216 | 217 | 218 | .. 219 | 220 | 221 | 222 | 223 | 224 | 760 225 | 380 226 | 371 227 | 36 228 | 229 | 230 | 231 | 232 | 233 | 234 | 420 235 | 150 236 | 180 237 | 40 238 | 239 | 240 | 241 | Add Separator 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | buttonBox 252 | accepted() 253 | EditLaunchersDialog 254 | accept() 255 | 256 | 257 | 248 258 | 254 259 | 260 | 261 | 157 262 | 274 263 | 264 | 265 | 266 | 267 | buttonBox 268 | rejected() 269 | EditLaunchersDialog 270 | reject() 271 | 272 | 273 | 316 274 | 260 275 | 276 | 277 | 286 278 | 274 279 | 280 | 281 | 282 | 283 | 284 | -------------------------------------------------------------------------------- /src/view/edit_launchers_dialog_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "edit_launchers_dialog.h" 20 | #include "ui_edit_launchers_dialog.h" 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | namespace ksmoothdock { 32 | 33 | constexpr int kDockId = 1; 34 | constexpr int kDefaultLauncherCount = 10; 35 | 36 | class EditLaunchersDialogTest: public QObject { 37 | Q_OBJECT 38 | 39 | private slots: 40 | void init() { 41 | QTemporaryDir configDir; 42 | model_ = std::make_unique(configDir.path()); 43 | model_->addDock(); 44 | dialog_ = std::make_unique(nullptr, model_.get(), 45 | kDockId); 46 | } 47 | 48 | // Tests OK button/logic. 49 | void ok(); 50 | 51 | // Tests Apply button/logic. 52 | void apply(); 53 | 54 | // Tests Cancel button/logic. 55 | void cancel(); 56 | 57 | private: 58 | int launcherCount() { 59 | return static_cast(model_->dockLauncherConfigs(kDockId).size()); 60 | } 61 | 62 | std::unique_ptr model_; 63 | std::unique_ptr dialog_; 64 | }; 65 | 66 | void EditLaunchersDialogTest::ok() { 67 | dialog_->addLauncher("Text Editor", "kate", "kate"); 68 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Ok), 69 | Qt::LeftButton); 70 | 71 | // Verify. 72 | QCOMPARE(launcherCount(), kDefaultLauncherCount + 1); 73 | } 74 | 75 | void EditLaunchersDialogTest::apply() { 76 | dialog_->addLauncher("Text Editor", "kate", "kate"); 77 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Apply), 78 | Qt::LeftButton); 79 | 80 | // Verify. 81 | QCOMPARE(launcherCount(), kDefaultLauncherCount + 1); 82 | } 83 | 84 | void EditLaunchersDialogTest::cancel() { 85 | dialog_->addLauncher("Text Editor", "kate", "kate"); 86 | QTest::mouseClick(dialog_->ui->buttonBox->button(QDialogButtonBox::Cancel), 87 | Qt::LeftButton); 88 | 89 | // Verify. 90 | QCOMPARE(launcherCount(), kDefaultLauncherCount); 91 | } 92 | 93 | } // namespace ksmoothdock 94 | 95 | QTEST_MAIN(ksmoothdock::EditLaunchersDialogTest) 96 | #include "edit_launchers_dialog_test.moc" 97 | -------------------------------------------------------------------------------- /src/view/icon_based_dock_item.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "icon_based_dock_item.h" 20 | 21 | #include 22 | 23 | #include 24 | 25 | namespace ksmoothdock { 26 | 27 | const int IconBasedDockItem::kIconLoadSize; 28 | 29 | IconBasedDockItem::IconBasedDockItem(DockPanel* parent, const QString& label, Qt::Orientation orientation, 30 | const QString& iconName, int minSize, int maxSize) 31 | : DockItem(parent, label, orientation, minSize, maxSize), 32 | icons_(maxSize - minSize + 1) { 33 | setIconName(iconName); 34 | } 35 | 36 | IconBasedDockItem::IconBasedDockItem(DockPanel* parent, const QString& label, 37 | Qt::Orientation orientation, const QPixmap& icon, 38 | int minSize, int maxSize) 39 | : DockItem(parent, label, orientation, minSize, maxSize), 40 | icons_(maxSize - minSize + 1) { 41 | setIcon(icon); 42 | } 43 | 44 | void IconBasedDockItem::draw(QPainter* painter) const { 45 | painter->drawPixmap(left_, top_, icons_[size_ - minSize_]); 46 | } 47 | 48 | void IconBasedDockItem::setIcon(const QPixmap& icon) { 49 | generateIcons(icon); 50 | } 51 | 52 | void IconBasedDockItem::setIconName(const QString& iconName) { 53 | if (!iconName.isEmpty()) { 54 | iconName_ = iconName; 55 | QPixmap icon = KIconLoader::global()->loadIcon(iconName, 56 | KIconLoader::NoGroup, kIconLoadSize); 57 | setIcon(icon); 58 | } 59 | } 60 | 61 | const QPixmap& IconBasedDockItem::getIcon(int size) const { 62 | if (size < minSize_) { 63 | size = minSize_; 64 | } else if (size > maxSize_) { 65 | size = maxSize_; 66 | } 67 | return icons_[size - minSize_]; 68 | } 69 | 70 | void IconBasedDockItem::generateIcons(const QPixmap& icon) { 71 | QImage image = icon.toImage(); // Convert to QImage for fast scaling. 72 | for (int size = minSize_; size <= maxSize_; ++size) { 73 | icons_[size - minSize_] = QPixmap::fromImage( 74 | (orientation_ == Qt::Horizontal) 75 | ? image.scaledToHeight(size, Qt::SmoothTransformation) 76 | : image.scaledToWidth(size, Qt::SmoothTransformation)); 77 | } 78 | } 79 | 80 | } // namespace ksmoothdock 81 | -------------------------------------------------------------------------------- /src/view/icon_based_dock_item.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_ICON_BASED_DOCK_ITEM_H_ 20 | #define KSMOOTHDOCK_ICON_BASED_DOCK_ITEM_H_ 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "dock_item.h" 30 | 31 | namespace ksmoothdock { 32 | 33 | // Base class for icon-based dock items, such as launchers and pager icons. 34 | class IconBasedDockItem : public DockItem { 35 | public: 36 | IconBasedDockItem(DockPanel* parent, const QString& label, Qt::Orientation orientation, 37 | const QString& iconName, int minSize, int maxSize); 38 | IconBasedDockItem(DockPanel* parent, const QString& label, Qt::Orientation orientation, 39 | const QPixmap& icon, int minSize, int maxSize); 40 | virtual ~IconBasedDockItem() {} 41 | 42 | int getWidthForSize(int size) const override { 43 | return getIcon(size).width(); 44 | } 45 | 46 | int getHeightForSize(int size) const override { 47 | return getIcon(size).height(); 48 | } 49 | 50 | void draw(QPainter* painter) const override; 51 | 52 | // Sets the icon on the fly. 53 | void setIcon(const QPixmap& icon); 54 | void setIconName(const QString& iconName); 55 | const QPixmap& getIcon(int size) const; 56 | QString getIconName() const { return iconName_; } 57 | 58 | protected: 59 | std::vector icons_; 60 | 61 | QString iconName_; 62 | 63 | private: 64 | static const int kIconLoadSize = 128; 65 | 66 | void generateIcons(const QPixmap& icon); 67 | 68 | friend class DockPanel; 69 | }; 70 | 71 | } // namespace ksmoothdock 72 | 73 | #endif // KSMOOTHDOCK_ICON_BASED_DOCK_ITEM_H_ 74 | -------------------------------------------------------------------------------- /src/view/iconless_dock_item.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "iconless_dock_item.h" 20 | 21 | namespace ksmoothdock { 22 | 23 | int IconlessDockItem::getWidthForSize(int size) const { 24 | return isHorizontal() ? static_cast(size * whRatio_) : size; 25 | } 26 | 27 | int IconlessDockItem::getHeightForSize(int size) const { 28 | return isHorizontal() ? size : static_cast(reverseWhRatio_ 29 | ? (size * whRatio_) 30 | : (size / whRatio_)); 31 | } 32 | 33 | } // namespace ksmoothdock 34 | -------------------------------------------------------------------------------- /src/view/iconless_dock_item.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_ICONLESS_DOCK_ITEM_H_ 20 | #define KSMOOTHDOCK_ICONLESS_DOCK_ITEM_H_ 21 | 22 | #include "dock_item.h" 23 | 24 | namespace ksmoothdock { 25 | 26 | // Base class for dock items without an icon, such as clock. 27 | class IconlessDockItem : public DockItem { 28 | public: 29 | IconlessDockItem(DockPanel* parent, const QString& label, 30 | Qt::Orientation orientation, int minSize, int maxSize, 31 | float whRatio, bool reverseWhRatio = false) 32 | : DockItem(parent, label, orientation, minSize, maxSize), 33 | whRatio_(whRatio), reverseWhRatio_(reverseWhRatio) {} 34 | virtual ~IconlessDockItem() {} 35 | 36 | int getWidthForSize(int size) const override; 37 | int getHeightForSize(int size) const override; 38 | 39 | protected: 40 | // Width/height ratio. 41 | float whRatio_; 42 | 43 | // Iff true, reverse width/height ratio when the orientation is vertical. 44 | bool reverseWhRatio_; 45 | }; 46 | 47 | } // namespace ksmoothdock 48 | 49 | #endif // KSMOOTHDOCK_ICONLESS_DOCK_ITEM_H_ 50 | -------------------------------------------------------------------------------- /src/view/multi_dock_view.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "multi_dock_view.h" 20 | 21 | #include 22 | 23 | #include "add_panel_dialog.h" 24 | 25 | namespace ksmoothdock { 26 | 27 | MultiDockView::MultiDockView(MultiDockModel* model) 28 | : model_(model), 29 | wallpaperHelper_(model) { 30 | connect(model_, SIGNAL(dockAdded(int)), this, SLOT(onDockAdded(int))); 31 | connect(model_, SIGNAL(wallpaperChanged(int)), &wallpaperHelper_, 32 | SLOT(setPlasmaWallpaper(int))); 33 | connect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), 34 | &wallpaperHelper_, SLOT(setPlasmaWallpapers())); 35 | loadData(); 36 | } 37 | 38 | void MultiDockView::show() { 39 | for (const auto& dock : docks_) { 40 | dock.second->show(); 41 | } 42 | wallpaperHelper_.setPlasmaWallpapers(); 43 | } 44 | 45 | void MultiDockView::exit() { 46 | for (const auto& dock : docks_) { 47 | dock.second->close(); 48 | } 49 | } 50 | 51 | void MultiDockView::onDockAdded(int dockId) { 52 | docks_[dockId] = std::make_unique(this, model_, dockId); 53 | docks_[dockId]->show(); 54 | } 55 | 56 | void MultiDockView::loadData() { 57 | docks_.clear(); 58 | for (int dockId = 1; dockId <= model_->dockCount(); ++dockId) { 59 | docks_[dockId] = std::make_unique(this, model_, dockId); 60 | } 61 | 62 | if (docks_.empty()) { 63 | AddPanelDialog dialog(nullptr, model_, 0 /* dockId not needed */); 64 | dialog.setMode(AddPanelDialog::Mode::Welcome); 65 | dialog.exec(); 66 | } 67 | } 68 | 69 | } // namespace ksmoothdock 70 | -------------------------------------------------------------------------------- /src/view/multi_dock_view.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_MULTI_DOCK_VIEW_H_ 20 | #define KSMOOTHDOCK_MULTI_DOCK_VIEW_H_ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include "dock_panel.h" 28 | #include 29 | #include 30 | 31 | namespace ksmoothdock { 32 | 33 | // The view. 34 | class MultiDockView : public QObject { 35 | Q_OBJECT 36 | 37 | public: 38 | // No pointer ownership. 39 | explicit MultiDockView(MultiDockModel* model); 40 | ~MultiDockView() = default; 41 | 42 | void show(); 43 | 44 | public slots: 45 | void exit(); 46 | 47 | void onDockAdded(int dockId); 48 | 49 | private: 50 | void loadData(); 51 | 52 | // Creates a default dock if none exists. 53 | void createDefaultDock(); 54 | 55 | MultiDockModel* model_; // No ownership. 56 | std::unordered_map> docks_; 57 | WallpaperHelper wallpaperHelper_; 58 | }; 59 | 60 | } // namespace ksmoothdock 61 | 62 | #endif // KSMOOTHDOCK_MULTI_DOCK_VIEW_H_ 63 | -------------------------------------------------------------------------------- /src/view/program.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2019 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "program.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "dock_panel.h" 33 | #include 34 | #include 35 | 36 | namespace ksmoothdock { 37 | 38 | Program::Program(DockPanel* parent, MultiDockModel* model, const QString& label, 39 | Qt::Orientation orientation, const QString& iconName, int minSize, 40 | int maxSize, const QString& command, const QString& taskCommand, bool pinned) 41 | : IconBasedDockItem(parent, label, orientation, iconName, minSize, maxSize), 42 | model_(model), 43 | command_(command), 44 | taskCommand_(taskCommand), 45 | pinned_(pinned), 46 | demandsAttention_(false), 47 | attentionStrong_(false) { 48 | createMenu(); 49 | 50 | animationTimer_.setInterval(500); 51 | connect(&animationTimer_, &QTimer::timeout, this, [this]() { 52 | attentionStrong_ = !attentionStrong_; 53 | parent_->update(); 54 | }); 55 | } 56 | 57 | void Program::draw(QPainter *painter) const { 58 | if ((!tasks_.empty() && active()) || attentionStrong_) { 59 | drawHighlightedIcon(model_->backgroundColor(), left_, top_, getWidth(), getHeight(), 60 | 5, size_ / 8, painter); 61 | } else if (!tasks_.empty()) { 62 | drawHighlightedIcon(model_->backgroundColor(), left_, top_, getWidth(), getHeight(), 63 | 5, size_ / 8, painter, 0.25); 64 | } 65 | IconBasedDockItem::draw(painter); 66 | } 67 | 68 | void Program::mousePressEvent(QMouseEvent* e) { 69 | if (e->button() == Qt::LeftButton) { // Run the application. 70 | if (command_ == kShowDesktopCommand) { 71 | KWindowSystem::setShowingDesktop(!KWindowSystem::showingDesktop()); 72 | } else if (isCommandLockScreen(command_)) { 73 | parent_->leaveEvent(nullptr); 74 | QTimer::singleShot(500, []() { 75 | lockScreen(); 76 | }); 77 | } else { 78 | if (tasks_.empty()) { 79 | launch(); 80 | } else { 81 | const auto mod = QGuiApplication::keyboardModifiers(); 82 | if (mod & Qt::ShiftModifier) { 83 | launch(); 84 | } else { 85 | const auto activeTask = getActiveTask(); 86 | if (activeTask >= 0) { 87 | if (tasks_.size() == 1) { 88 | KWindowSystem::minimizeWindow(tasks_[0].wId); 89 | } else { 90 | // Cycles through tasks. 91 | auto nextTask = (activeTask < static_cast(tasks_.size() - 1)) ? 92 | (activeTask + 1) : 0; 93 | KWindowSystem::forceActiveWindow(tasks_[nextTask].wId); 94 | } 95 | } else { 96 | for (unsigned i = 0; i < tasks_.size(); ++i) { 97 | KWindowSystem::forceActiveWindow(tasks_[i].wId); 98 | } 99 | } 100 | } 101 | } 102 | } 103 | } else if (e->button() == Qt::RightButton) { 104 | menu_.popup(e->globalPos()); 105 | } 106 | } 107 | 108 | QString Program::getLabel() const { 109 | const unsigned taskCount = tasks_.size(); 110 | return (taskCount > 1) ? 111 | label_ + " (" + QString::number(tasks_.size()) + " instances)" : 112 | label_; 113 | } 114 | 115 | bool Program::addTask(const TaskInfo& task) { 116 | if (areTheSameCommand(taskCommand_, task.command)) { 117 | tasks_.push_back(ProgramTask(task.wId, task.name, task.demandsAttention)); 118 | if (task.demandsAttention) { 119 | setDemandsAttention(true); 120 | } 121 | return true; 122 | } 123 | return false; 124 | } 125 | 126 | bool Program::updateTask(const TaskInfo& task) { 127 | if (!areTheSameCommand(taskCommand_, task.command)) { 128 | return false; 129 | } 130 | 131 | for (auto& existingTask : tasks_) { 132 | if (existingTask.wId == task.wId) { 133 | existingTask.demandsAttention = task.demandsAttention; 134 | updateDemandsAttention(); 135 | return true; 136 | } 137 | } 138 | 139 | return false; 140 | } 141 | 142 | bool Program::removeTask(WId wId) { 143 | for (int i = 0; i < static_cast(tasks_.size()); ++i) { 144 | if (tasks_[i].wId == wId) { 145 | tasks_.erase(tasks_.begin() + i); 146 | return true; 147 | } 148 | } 149 | return false; 150 | } 151 | 152 | bool Program::hasTask(WId wId) { 153 | for (const auto& task : tasks_) { 154 | if (task.wId == wId) { 155 | return true; 156 | } 157 | } 158 | return false; 159 | } 160 | 161 | bool Program::beforeTask(const QString& command) { 162 | return taskCommand_ < command; 163 | } 164 | 165 | void Program::launch() { 166 | launch(command_); 167 | parent_->showWaitCursor(); 168 | parent_->update(); 169 | } 170 | 171 | void Program::pinUnpin() { 172 | pinned_ = !pinned_; 173 | if (pinned_) { 174 | model_->addLauncher(parent_->dockId(), LauncherConfig(label_, iconName_, command_)); 175 | } else { // !pinned 176 | model_->removeLauncher(parent_->dockId(), command_); 177 | if (shouldBeRemoved()) { 178 | parent_->delayedRefresh(); 179 | } 180 | } 181 | } 182 | 183 | void Program::launch(const QString& command) { 184 | QStringList list = QProcess::splitCommand(command); 185 | if (!QProcess::startDetached(list.at(0), list.mid(1))) { 186 | KMessageBox::error(nullptr, 187 | i18n("Could not run command: ") + command); 188 | } 189 | } 190 | 191 | void Program::createMenu() { 192 | menu_.addAction(QIcon::fromTheme("configure"), i18n("Edit &Launchers"), parent_, 193 | [this] { parent_->showEditLaunchersDialog(); }); 194 | 195 | if (model_->showTaskManager(parent_->dockId())) { 196 | menu_.addAction(QIcon::fromTheme("configure"), 197 | i18n("Task Manager &Settings"), 198 | parent_, 199 | [this] { parent_->showTaskManagerSettingsDialog(); }); 200 | } 201 | 202 | if (!isCommandInternal(command_) && !isCommandDBus(command_)) { 203 | menu_.addAction(QIcon::fromTheme("list-add"), i18n("&New Instance"), this, 204 | [this] { launch(); }); 205 | } 206 | 207 | pinAction_ = menu_.addAction( 208 | i18n("Pinned"), this, 209 | [this] { 210 | pinUnpin(); 211 | }); 212 | pinAction_->setCheckable(true); 213 | pinAction_->setChecked(pinned_); 214 | 215 | menu_.addSeparator(); 216 | parent_->addPanelSettings(&menu_); 217 | } 218 | 219 | void Program::setDemandsAttention(bool value) { 220 | if (demandsAttention_ == value) { 221 | return; 222 | } 223 | 224 | demandsAttention_ = value; 225 | if (demandsAttention_) { 226 | animationTimer_.start(); 227 | } else if (animationTimer_.isActive()) { 228 | animationTimer_.stop(); 229 | } 230 | } 231 | 232 | void Program::updateDemandsAttention() { 233 | for (const auto& task : tasks_) { 234 | if (task.demandsAttention) { 235 | setDemandsAttention(true); 236 | return; 237 | } 238 | } 239 | setDemandsAttention(false); 240 | } 241 | 242 | } // namespace ksmoothdock 243 | -------------------------------------------------------------------------------- /src/view/program.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2019 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_PROGRAM_H_ 20 | #define KSMOOTHDOCK_PROGRAM_H_ 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include "icon_based_dock_item.h" 32 | 33 | #include 34 | #include 35 | 36 | namespace ksmoothdock { 37 | 38 | struct ProgramTask { 39 | WId wId; 40 | QString name; // e.g. home -- Dolphin 41 | bool demandsAttention; 42 | 43 | ProgramTask(WId wId2, QString name2, bool demandsAttention2) 44 | : wId(wId2), name(name2), demandsAttention(demandsAttention2) {} 45 | }; 46 | 47 | class Program : public QObject, public IconBasedDockItem { 48 | Q_OBJECT 49 | 50 | public: 51 | Program(DockPanel* parent, MultiDockModel* model, const QString& label, 52 | Qt::Orientation orientation, const QString& iconName, int minSize, 53 | int maxSize, const QString& command, const QString& taskCommand, bool pinned); 54 | 55 | ~Program() override = default; 56 | 57 | void draw(QPainter* painter) const override; 58 | 59 | void mousePressEvent(QMouseEvent* e) override; 60 | 61 | QString getLabel() const override; 62 | 63 | bool addTask(const TaskInfo& task) override; 64 | 65 | bool updateTask(const TaskInfo& task) override; 66 | 67 | bool removeTask(WId wId) override; 68 | 69 | bool hasTask(WId wId) override; 70 | 71 | bool beforeTask(const QString& command) override; 72 | 73 | bool shouldBeRemoved() override { return taskCount() == 0 && !pinned_; } 74 | 75 | int taskCount() const { return static_cast(tasks_.size()); } 76 | 77 | bool active() const { return getActiveTask() >= 0; } 78 | 79 | int getActiveTask() const { 80 | for (int i = 0; i < static_cast(tasks_.size()); ++i) { 81 | if (KWindowSystem::activeWindow() == tasks_[i].wId) { 82 | return i; 83 | } 84 | } 85 | return -1; 86 | } 87 | 88 | bool pinned() { return pinned_; } 89 | void pinUnpin(); 90 | 91 | void launch(); 92 | static void launch(const QString& command); 93 | static void lockScreen() { launch(kLockScreenCommand); } 94 | 95 | private: 96 | void createMenu(); 97 | 98 | void setDemandsAttention(bool value); 99 | void updateDemandsAttention(); 100 | 101 | MultiDockModel* model_; 102 | QString name_; 103 | QString command_; 104 | QString taskCommand_; 105 | bool pinned_; 106 | std::vector tasks_; 107 | 108 | // Context (right-click) menu. 109 | QMenu menu_; 110 | QAction* pinAction_; 111 | 112 | // Demands attention logic. 113 | bool demandsAttention_; 114 | QTimer animationTimer_; 115 | bool attentionStrong_; 116 | 117 | friend class DockPanel; 118 | }; 119 | 120 | } // namespace ksmoothdock 121 | 122 | #endif // KSMOOTHDOCK_PROGRAM_H_ 123 | -------------------------------------------------------------------------------- /src/view/separator.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2019 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "separator.h" 20 | 21 | #include "dock_panel.h" 22 | 23 | namespace ksmoothdock { 24 | 25 | constexpr float Separator::kWhRatio; 26 | 27 | Separator::Separator(DockPanel* parent, MultiDockModel* model, Qt::Orientation orientation, 28 | int minSize, int maxSize) 29 | : IconlessDockItem(parent, "" /* label */, orientation, minSize, maxSize, 30 | kWhRatio, /*reverseWhRatio=*/ true), 31 | model_(model) {} 32 | 33 | void Separator::draw(QPainter* painter) const { 34 | int x, y, w, h; 35 | if (orientation_ == Qt::Horizontal) { 36 | x = left_ + getWidth() / 2; 37 | y = (parent_->position() == PanelPosition::Top) 38 | ? top_ 39 | : getHeight() - getMinHeight() + top_; 40 | w = 1; 41 | h = getMinHeight(); 42 | } else { // Vertical. 43 | x = (parent_->position() == PanelPosition::Left) 44 | ? left_ 45 | : getWidth() - getMinWidth() + left_; 46 | y = top_ + getHeight() / 2; 47 | w = getMinWidth(); 48 | h = 1; 49 | } 50 | painter->fillRect(x, y, w, h, model_->borderColor()); 51 | } 52 | 53 | } // namespace ksmoothdock 54 | -------------------------------------------------------------------------------- /src/view/separator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2019 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_SEPARATOR_H_ 20 | #define KSMOOTHDOCK_SEPARATOR_H_ 21 | 22 | #include "iconless_dock_item.h" 23 | 24 | #include 25 | 26 | namespace ksmoothdock { 27 | 28 | // A digital Separator. 29 | class Separator : public QObject, public IconlessDockItem { 30 | Q_OBJECT 31 | 32 | public: 33 | Separator(DockPanel* parent, MultiDockModel* model, Qt::Orientation orientation, 34 | int minSize, int maxSize); 35 | virtual ~Separator() = default; 36 | 37 | void draw(QPainter* painter) const override; 38 | 39 | void mousePressEvent(QMouseEvent* e) override { /* no-op */ } 40 | 41 | bool beforeTask(const QString& command) override { return false; } 42 | 43 | private: 44 | static constexpr float kWhRatio = 0.1; 45 | 46 | MultiDockModel* model_; 47 | }; 48 | 49 | } // namespace ksmoothdock 50 | 51 | #endif // KSMOOTHDOCK_SEPARATOR_H_ 52 | -------------------------------------------------------------------------------- /src/view/task_manager_settings_dialog.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "task_manager_settings_dialog.h" 20 | #include "ui_task_manager_settings_dialog.h" 21 | 22 | #include 23 | 24 | namespace ksmoothdock { 25 | 26 | TaskManagerSettingsDialog::TaskManagerSettingsDialog(QWidget* parent, MultiDockModel* model) : 27 | QDialog(parent), 28 | ui(new Ui::TaskManagerSettingsDialog), 29 | model_(model), 30 | isSingleScreen_(true) { 31 | ui->setupUi(this); 32 | 33 | // Adjust the UI for single/multi-screen. 34 | isSingleScreen_ = (QGuiApplication::screens().size() == 1); 35 | ui->showCurrentScreenOnly->setVisible(!isSingleScreen_); 36 | if (isSingleScreen_) { 37 | ui->buttonBox->move(40, 200); 38 | resize(600, 260); 39 | } 40 | connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), 41 | this, SLOT(buttonClicked(QAbstractButton*))); 42 | 43 | loadData(); 44 | } 45 | 46 | TaskManagerSettingsDialog::~TaskManagerSettingsDialog() { 47 | delete ui; 48 | } 49 | 50 | void TaskManagerSettingsDialog::accept() { 51 | QDialog::accept(); 52 | saveData(); 53 | } 54 | 55 | void TaskManagerSettingsDialog::buttonClicked(QAbstractButton* button) { 56 | auto role = ui->buttonBox->buttonRole(button); 57 | if (role == QDialogButtonBox::ApplyRole) { 58 | saveData(); 59 | } 60 | } 61 | 62 | void TaskManagerSettingsDialog::loadData() { 63 | ui->showCurrentDesktopOnly->setChecked(model_->currentDesktopTasksOnly()); 64 | if (!isSingleScreen_) { 65 | ui->showCurrentScreenOnly->setChecked(model_->currentScreenTasksOnly()); 66 | } 67 | } 68 | 69 | void TaskManagerSettingsDialog::saveData() { 70 | model_->setCurrentDesktopTasksOnly(ui->showCurrentDesktopOnly->isChecked()); 71 | if (!isSingleScreen_) { 72 | model_->setCurrentScreenTasksOnly(ui->showCurrentScreenOnly->isChecked()); 73 | } 74 | model_->saveAppearanceConfig(); 75 | } 76 | 77 | } // namespace ksmoothdock 78 | -------------------------------------------------------------------------------- /src/view/task_manager_settings_dialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_TASK_MANAGER_SETTINGS_DIALOG_H_ 20 | #define KSMOOTHDOCK_TASK_MANAGER_SETTINGS_DIALOG_H_ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | namespace Ui { 28 | class TaskManagerSettingsDialog; 29 | } 30 | 31 | namespace ksmoothdock { 32 | 33 | class TaskManagerSettingsDialog : public QDialog { 34 | Q_OBJECT 35 | 36 | public: 37 | explicit TaskManagerSettingsDialog(QWidget* parent, MultiDockModel* model); 38 | ~TaskManagerSettingsDialog(); 39 | 40 | public slots: 41 | void accept() override; 42 | void buttonClicked(QAbstractButton* button); 43 | 44 | private: 45 | void loadData(); 46 | void saveData(); 47 | 48 | Ui::TaskManagerSettingsDialog *ui; 49 | 50 | MultiDockModel* model_; 51 | 52 | bool isSingleScreen_; 53 | }; 54 | 55 | } // namespace ksmoothdock 56 | 57 | #endif // KSMOOTHDOCK_TASK_MANAGER_SETTINGS_DIALOG_H_ 58 | -------------------------------------------------------------------------------- /src/view/task_manager_settings_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | TaskManagerSettingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 600 10 | 300 11 | 12 | 13 | 14 | Task Manager Settings 15 | 16 | 17 | 18 | 19 | 30 20 | 240 21 | 530 22 | 32 23 | 24 | 25 | 26 | Qt::Horizontal 27 | 28 | 29 | QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok 30 | 31 | 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 40 39 | 30 40 | 351 41 | 28 42 | 43 | 44 | 45 | Showing tasks from: 46 | 47 | 48 | 49 | 50 | false 51 | 52 | 53 | 54 | 80 55 | 70 56 | 401 57 | 32 58 | 59 | 60 | 61 | Current activity only 62 | 63 | 64 | true 65 | 66 | 67 | true 68 | 69 | 70 | 71 | 72 | 73 | 80 74 | 120 75 | 401 76 | 32 77 | 78 | 79 | 80 | Current desktop only 81 | 82 | 83 | true 84 | 85 | 86 | 87 | 88 | 89 | 80 90 | 170 91 | 421 92 | 32 93 | 94 | 95 | 96 | Current screen only 97 | 98 | 99 | true 100 | 101 | 102 | 103 | 104 | 105 | 106 | buttonBox 107 | accepted() 108 | TaskManagerSettingsDialog 109 | accept() 110 | 111 | 112 | 248 113 | 254 114 | 115 | 116 | 157 117 | 274 118 | 119 | 120 | 121 | 122 | buttonBox 123 | rejected() 124 | TaskManagerSettingsDialog 125 | reject() 126 | 127 | 128 | 316 129 | 260 130 | 131 | 132 | 286 133 | 274 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /src/view/tooltip.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "tooltip.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | namespace ksmoothdock { 31 | 32 | const int Tooltip::kPadding; 33 | 34 | Tooltip::Tooltip() : QWidget(), font_(QApplication::font()) { 35 | setAttribute(Qt::WA_TranslucentBackground); 36 | KWindowSystem::setType(winId(), NET::Dock); 37 | KWindowSystem::setOnAllDesktops(winId(), true); 38 | } 39 | 40 | void Tooltip::setFontColor(const QColor& color) { 41 | fontColor_ = color; 42 | } 43 | 44 | void Tooltip::setBackgroundColor(const QColor& color) { 45 | backgroundColor_ = color; 46 | } 47 | 48 | void Tooltip::setFontFace(const QString& fontFace) { 49 | font_.setFamily(fontFace); 50 | } 51 | 52 | void Tooltip::setFontItalic(bool val) { 53 | font_.setItalic(val); 54 | } 55 | 56 | void Tooltip::setFontBold(bool val) { 57 | font_.setBold(val); 58 | } 59 | 60 | void Tooltip::setFontSize(int size) { 61 | font_.setPointSize(size); 62 | } 63 | 64 | void Tooltip::setText(const QString& text) { 65 | text_ = text; 66 | updateLayout(); 67 | } 68 | 69 | void Tooltip::updateLayout() { 70 | QFontMetrics metrics(font_); 71 | int w = metrics.horizontalAdvance(text_) + 2 * kPadding; 72 | int h = metrics.height() + 2 * kPadding; 73 | 74 | resize(w,h); 75 | update(); 76 | } 77 | 78 | void Tooltip::paintEvent(QPaintEvent* e) { 79 | QPainter painter(this); 80 | painter.setRenderHint(QPainter::TextAntialiasing); 81 | QFontMetrics metrics(font_); 82 | const int kDeltaY = metrics.height() / 2; 83 | painter.setFont(font_); 84 | drawBorderedText(kPadding, kPadding + kDeltaY, text_, 2 /* borderWidth */, 85 | backgroundColor_, fontColor_, &painter); 86 | } 87 | 88 | } // namespace ksmoothdock 89 | -------------------------------------------------------------------------------- /src/view/tooltip.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2017 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_TOOLTIP_H_ 20 | #define KSMOOTHDOCK_TOOLTIP_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace ksmoothdock { 29 | 30 | // Tooltip with translucent background. 31 | class Tooltip : public QWidget { 32 | public: 33 | Tooltip(); 34 | 35 | void setText(const QString& text); 36 | void setFontFace(const QString& fontFace); 37 | void setFontItalic(bool val); 38 | void setFontBold(bool val); 39 | void setFontSize(int size); 40 | void setFontColor(const QColor& color); 41 | void setBackgroundColor(const QColor& color); 42 | 43 | void updateLayout(); 44 | 45 | protected: 46 | virtual void paintEvent(QPaintEvent* e) override; 47 | 48 | private: 49 | // Additional padding around the text e.g. to avoid clipping. 50 | static const int kPadding = 10; 51 | 52 | QString text_; 53 | QFont font_; 54 | QColor fontColor_; 55 | QColor backgroundColor_; 56 | }; 57 | 58 | } // namespace ksmoothdock 59 | 60 | #endif // KSMOOTHDOCK_TOOLTIP_H_ 61 | -------------------------------------------------------------------------------- /src/view/wallpaper_settings_dialog.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #include "wallpaper_settings_dialog.h" 20 | #include "ui_wallpaper_settings_dialog.h" 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | namespace ksmoothdock { 34 | 35 | WallpaperSettingsDialog::WallpaperSettingsDialog(QWidget* parent, 36 | MultiDockModel* model) 37 | : QDialog(parent), 38 | ui(new Ui::WallpaperSettingsDialog), 39 | model_(model), 40 | currentDir_(QDir::homePath()), 41 | multiScreen_(false) { 42 | ui->setupUi(this); 43 | 44 | populateDesktopList(); 45 | 46 | // Populate screen list. 47 | const int screenCount = QGuiApplication::screens().size(); 48 | for (int i = 1; i <= screenCount; ++i) { 49 | ui->screen->addItem(QString::number(i)); 50 | } 51 | ui->screen->setCurrentIndex(0); 52 | 53 | // Adjust the UI for single/multi-screen. 54 | multiScreen_ = (screenCount > 1); 55 | ui->screenLabel->setVisible(multiScreen_); 56 | ui->screen->setVisible(multiScreen_); 57 | 58 | adjustUiForScreen(); 59 | 60 | connect(ui->desktop, SIGNAL(currentIndexChanged(int)), 61 | this, SLOT(reload())); 62 | connect(ui->browse, SIGNAL(clicked()), this, SLOT(browseWallpaper())); 63 | connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), 64 | this, SLOT(buttonClicked(QAbstractButton*))); 65 | connect(KWindowSystem::self(), SIGNAL(numberOfDesktopsChanged(int)), 66 | this, SLOT(populateDesktopList())); 67 | 68 | if (multiScreen_) { 69 | connect(ui->screen, SIGNAL(currentIndexChanged(int)), 70 | this, SLOT(reload())); 71 | } 72 | } 73 | 74 | WallpaperSettingsDialog::~WallpaperSettingsDialog() { 75 | delete ui; 76 | } 77 | 78 | void WallpaperSettingsDialog::setFor(int desktop, int screen) { 79 | ui->desktop->setCurrentIndex(desktop - 1); 80 | if (multiScreen_) { 81 | ui->screen->setCurrentIndex(screen); 82 | adjustUiForScreen(); 83 | } 84 | loadData(); 85 | } 86 | 87 | void WallpaperSettingsDialog::populateDesktopList() { 88 | ui->desktop->clear(); 89 | for (int desktop = 1; desktop <= KWindowSystem::numberOfDesktops(); 90 | ++desktop) { 91 | ui->desktop->addItem(QString::number(desktop)); 92 | } 93 | } 94 | 95 | void WallpaperSettingsDialog::accept() { 96 | QDialog::accept(); 97 | saveData(); 98 | } 99 | 100 | void WallpaperSettingsDialog::buttonClicked(QAbstractButton *button) { 101 | auto role = ui->buttonBox->buttonRole(button); 102 | if (role == QDialogButtonBox::ApplyRole) { 103 | saveData(); 104 | } 105 | } 106 | 107 | void WallpaperSettingsDialog::browseWallpaper() { 108 | const QString& wallpaper = QFileDialog::getOpenFileName( 109 | nullptr, 110 | i18n("Select Wallpaper Image"), 111 | currentDir_, 112 | i18n("Image Files (*.png *.jpg *.bmp)")); 113 | if (wallpaper.isEmpty()) { 114 | return; 115 | } 116 | 117 | wallpaper_ = wallpaper; 118 | ui->preview->setPixmap(QPixmap(wallpaper_)); 119 | currentDir_ = QFileInfo(wallpaper_).dir().absolutePath(); 120 | } 121 | 122 | void WallpaperSettingsDialog::adjustUiForScreen() { 123 | const auto screenGeometry = QGuiApplication::screens()[screen()]->geometry(); 124 | const int w = ui->preview->width(); 125 | const int h = w * screenGeometry.height() / screenGeometry.width(); 126 | const int delta = h - ui->preview->height(); 127 | ui->preview->resize(w, h); 128 | ui->previewHolder->resize(ui->previewHolder->width(), 129 | ui->previewHolder->height() + delta); 130 | ui->buttonBox->move(ui->buttonBox->x(), ui->buttonBox->y() + delta); 131 | resize(width(), height() + delta); 132 | } 133 | 134 | void WallpaperSettingsDialog::reload() { 135 | if (multiScreen_) { 136 | adjustUiForScreen(); 137 | } 138 | loadData(); 139 | } 140 | 141 | int WallpaperSettingsDialog::screen() const { 142 | return ui->screen->currentIndex(); 143 | } 144 | 145 | int WallpaperSettingsDialog::desktop() const { 146 | return ui->desktop->currentIndex() + 1; 147 | } 148 | 149 | void WallpaperSettingsDialog::loadData() { 150 | wallpaper_ = model_->wallpaper(desktop(), screen()); 151 | ui->preview->setPixmap(QPixmap(wallpaper_)); 152 | } 153 | 154 | void WallpaperSettingsDialog::saveData() { 155 | if (!wallpaper_.isEmpty() && 156 | (wallpaper_ != model_->wallpaper(desktop(), screen()))) { 157 | model_->setWallpaper(desktop(), screen(), wallpaper_); 158 | model_->saveAppearanceConfig(); 159 | if (desktop() == KWindowSystem::currentDesktop()) { 160 | model_->notifyWallpaperChanged(screen()); 161 | } 162 | } 163 | } 164 | 165 | } // namespace ksmoothdock 166 | -------------------------------------------------------------------------------- /src/view/wallpaper_settings_dialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of KSmoothDock. 3 | * Copyright (C) 2018 Viet Dang (dangvd@gmail.com) 4 | * 5 | * KSmoothDock is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * KSmoothDock is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with KSmoothDock. If not, see . 17 | */ 18 | 19 | #ifndef KSMOOTHDOCK_WALLPAPER_SETTINGS_DIALOG_H_ 20 | #define KSMOOTHDOCK_WALLPAPER_SETTINGS_DIALOG_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | namespace Ui { 29 | class WallpaperSettingsDialog; 30 | } 31 | 32 | namespace ksmoothdock { 33 | 34 | class WallpaperSettingsDialog : public QDialog { 35 | Q_OBJECT 36 | 37 | public: 38 | WallpaperSettingsDialog(QWidget* parent, MultiDockModel* model); 39 | ~WallpaperSettingsDialog(); 40 | 41 | void setFor(int desktop, int screen); 42 | 43 | public slots: 44 | void populateDesktopList(); 45 | 46 | void accept() override; 47 | void buttonClicked(QAbstractButton* button); 48 | 49 | void browseWallpaper(); 50 | 51 | void adjustUiForScreen(); 52 | 53 | void reload(); 54 | 55 | private: 56 | // Gets screen (0-based). 57 | int screen() const; 58 | 59 | // Gets desktop (1-based). 60 | int desktop() const; 61 | 62 | void loadData(); 63 | void saveData(); 64 | 65 | Ui::WallpaperSettingsDialog *ui; 66 | 67 | MultiDockModel* model_; 68 | 69 | // Path to wallpaper file. 70 | QString wallpaper_; 71 | 72 | // Remember the current directory of the session when opening the file dialog 73 | // for browsing wallpapers. 74 | QString currentDir_; 75 | 76 | bool multiScreen_; 77 | }; 78 | 79 | } // namespace ksmoothdock 80 | 81 | #endif // KSMOOTHDOCK_WALLPAPER_SETTINGS_DIALOG_H_ 82 | -------------------------------------------------------------------------------- /src/view/wallpaper_settings_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | WallpaperSettingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 900 10 | 791 11 | 12 | 13 | 14 | Wallpaper Settings 15 | 16 | 17 | 18 | 19 | 40 20 | 730 21 | 821 22 | 32 23 | 24 | 25 | 26 | Qt::Horizontal 27 | 28 | 29 | QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok 30 | 31 | 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 40 39 | 90 40 | 221 41 | 36 42 | 43 | 44 | 45 | Browse Image 46 | 47 | 48 | 49 | 50 | 51 | 170 52 | 20 53 | 91 54 | 36 55 | 56 | 57 | 58 | 59 | 60 | 61 | 40 62 | 30 63 | 121 64 | 23 65 | 66 | 67 | 68 | Desktop 69 | 70 | 71 | 72 | 73 | 74 | 650 75 | 30 76 | 111 77 | 23 78 | 79 | 80 | 81 | Screen 82 | 83 | 84 | 85 | 86 | 87 | 770 88 | 20 89 | 91 90 | 36 91 | 92 | 93 | 94 | 95 | 96 | 97 | 40 98 | 180 99 | 821 100 | 521 101 | 102 | 103 | 104 | QFrame::Panel 105 | 106 | 107 | QFrame::Plain 108 | 109 | 110 | 111 | 112 | 10 113 | 10 114 | 800 115 | 500 116 | 117 | 118 | 119 | 120 | 121 | 122 | true 123 | 124 | 125 | 126 | 127 | 128 | 129 | 40 130 | 150 131 | 131 132 | 23 133 | 134 | 135 | 136 | Preview 137 | 138 | 139 | 140 | 141 | 142 | 143 | buttonBox 144 | accepted() 145 | WallpaperSettingsDialog 146 | accept() 147 | 148 | 149 | 248 150 | 254 151 | 152 | 153 | 157 154 | 274 155 | 156 | 157 | 158 | 159 | buttonBox 160 | rejected() 161 | WallpaperSettingsDialog 162 | reject() 163 | 164 | 165 | 316 166 | 260 167 | 168 | 169 | 286 170 | 274 171 | 172 | 173 | 174 | 175 | 176 | --------------------------------------------------------------------------------