diff --git a/install.sh b/install.sh index 12cf091d..4497d573 100755 --- a/install.sh +++ b/install.sh @@ -74,6 +74,18 @@ link "icons" ".local/share/icons" link "fonts" ".fonts" link "fontconfig" ".config/fontconfig" +# kde +link "kde/plasma" ".local/share/plasma" +link "kde/kdedefaults" ".config/kdedefaults" +link "lone-files/kglobalshortcutsrc" ".config/kglobalshortcutsrc" +link "lone-files/kiorc" ".config/kiorc" +link "lone-files/krunnerrc" ".config/krunnerrc" +link "lone-files/kservicemenurc" ".config/kservicemenurc" +link "lone-files/ksplashrc" ".config/ksplashrc" +link "lone-files/ktimezonedrc" ".config/ktimezonedrc" +link "lone-files/plasma-localerc" ".config/plasma-localrc" +link "lone-files/plasma-org.kde.plasma.desktop-appletsrc" ".config/plasma-org.kde.plasma.desktop-appletsrc" + # programs link "lone-files/konsolerc" ".config/konsolerc" link "konsole" ".local/share/konsole" diff --git a/kde/kdedefaults/kcminputrc b/kde/kdedefaults/kcminputrc new file mode 100644 index 00000000..728fea4d --- /dev/null +++ b/kde/kdedefaults/kcminputrc @@ -0,0 +1,2 @@ +[Mouse] +cursorTheme=PosyCursor diff --git a/kde/kdedefaults/kdeglobals b/kde/kdedefaults/kdeglobals new file mode 100644 index 00000000..c497e740 --- /dev/null +++ b/kde/kdedefaults/kdeglobals @@ -0,0 +1,8 @@ +[General] +ColorScheme=TokyoNight + +[Icons] +Theme=TokyoNight-SE + +[KDE] +widgetStyle=Breeze diff --git a/kde/kdedefaults/kscreenlockerrc b/kde/kdedefaults/kscreenlockerrc new file mode 100644 index 00000000..7e949cf8 --- /dev/null +++ b/kde/kdedefaults/kscreenlockerrc @@ -0,0 +1,2 @@ +[Greeter] +Theme=org.kde.breeze.desktop diff --git a/kde/kdedefaults/ksplashrc b/kde/kdedefaults/ksplashrc new file mode 100644 index 00000000..6f69bc82 --- /dev/null +++ b/kde/kdedefaults/ksplashrc @@ -0,0 +1,3 @@ +[KSplash] +Engine=KSplashQML +Theme=org.kde.breeze.desktop diff --git a/kde/kdedefaults/kwinrc b/kde/kdedefaults/kwinrc new file mode 100644 index 00000000..05e29d82 --- /dev/null +++ b/kde/kdedefaults/kwinrc @@ -0,0 +1,12 @@ +[TabBox] +DesktopLayout=org.kde.breeze.desktop +DesktopListLayout=org.kde.breeze.desktop +LayoutName=org.kde.breeze.desktop + +[Windows] +Placement=Centered + +[org.kde.kdecoration2] +NoPlugin=false +library=org.kde.kwin.aurorae +theme=__aurorae__svg__TokyoNight diff --git a/kde/kdedefaults/package b/kde/kdedefaults/package new file mode 100644 index 00000000..2b5862d9 --- /dev/null +++ b/kde/kdedefaults/package @@ -0,0 +1 @@ +com.github.Jayy-Dev.Plasma.Tokyo.Night \ No newline at end of file diff --git a/kde/kdedefaults/plasmarc b/kde/kdedefaults/plasmarc new file mode 100644 index 00000000..81c45d17 --- /dev/null +++ b/kde/kdedefaults/plasmarc @@ -0,0 +1,2 @@ +[Theme] +name=Tokyo-Night diff --git a/kde/plasma/avatars/Drip Konqi.png b/kde/plasma/avatars/Drip Konqi.png new file mode 100644 index 00000000..41b14596 Binary files /dev/null and b/kde/plasma/avatars/Drip Konqi.png differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/dialogs/background.svgz b/kde/plasma/desktoptheme/Colloid-dark/dialogs/background.svgz new file mode 100644 index 00000000..d91d089d Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/dialogs/background.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/akonadi.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/akonadi.svgz new file mode 100644 index 00000000..1385d594 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/akonadi.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/akregator.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/akregator.svgz new file mode 100644 index 00000000..626fa7d7 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/akregator.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/amarok.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/amarok.svgz new file mode 100644 index 00000000..13b6dc90 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/amarok.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/applications.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/applications.svgz new file mode 100644 index 00000000..43cf68a5 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/applications.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/apport.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/apport.svgz new file mode 100644 index 00000000..9646744c Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/apport.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/audio.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/audio.svgz new file mode 100644 index 00000000..701cb1b3 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/audio.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/battery.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/battery.svgz new file mode 100644 index 00000000..50f5f0fe Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/battery.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/bookmarks.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/bookmarks.svgz new file mode 100644 index 00000000..8af33e0e Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/bookmarks.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/cantata.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/cantata.svgz new file mode 100644 index 00000000..4c166820 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/cantata.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/compass.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/compass.svgz new file mode 100644 index 00000000..8bfcc51b Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/compass.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/computer.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/computer.svgz new file mode 100644 index 00000000..9e72d9dc Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/computer.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/configure.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/configure.svgz new file mode 100644 index 00000000..07ce4b6a Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/configure.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/device.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/device.svgz new file mode 100644 index 00000000..2c9ac4d9 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/device.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/disk.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/disk.svgz new file mode 100644 index 00000000..3852af33 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/disk.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/distribute.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/distribute.svgz new file mode 100644 index 00000000..aa59ff23 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/distribute.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/document.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/document.svgz new file mode 100644 index 00000000..479511c9 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/document.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/drive.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/drive.svgz new file mode 100644 index 00000000..6fe83fec Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/drive.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/edit.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/edit.svgz new file mode 100644 index 00000000..62eff322 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/edit.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/fcitx.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/fcitx.svgz new file mode 100644 index 00000000..797ffa4a Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/fcitx.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/go.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/go.svgz new file mode 100644 index 00000000..6fc504ab Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/go.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/ime.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/ime.svgz new file mode 100644 index 00000000..574e65fa Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/ime.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/input.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/input.svgz new file mode 100644 index 00000000..67fa83ad Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/input.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kalarm.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kalarm.svgz new file mode 100644 index 00000000..90de80a2 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kalarm.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kdeconnect.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kdeconnect.svgz new file mode 100644 index 00000000..46515b9b Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kdeconnect.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kdf.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kdf.svgz new file mode 100644 index 00000000..b7ee2ec8 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kdf.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/keyboard.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/keyboard.svgz new file mode 100644 index 00000000..eef8ee29 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/keyboard.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kget.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kget.svgz new file mode 100644 index 00000000..df1d877e Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kget.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kgpg.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kgpg.svgz new file mode 100644 index 00000000..304da052 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kgpg.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kleopatra.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kleopatra.svgz new file mode 100644 index 00000000..a9a58007 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kleopatra.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/klipper.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/klipper.svgz new file mode 100644 index 00000000..aa6983e7 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/klipper.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kmail.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kmail.svgz new file mode 100644 index 00000000..d7f2a010 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kmail.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/knotes.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/knotes.svgz new file mode 100644 index 00000000..428ede58 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/knotes.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/konv_message.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/konv_message.svgz new file mode 100644 index 00000000..205417f7 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/konv_message.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/konversation.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/konversation.svgz new file mode 100644 index 00000000..51bec163 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/konversation.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kopete.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kopete.svgz new file mode 100644 index 00000000..d538c60b Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kopete.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/korgac.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/korgac.svgz new file mode 100644 index 00000000..60fa4f1d Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/korgac.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kpackagekit.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kpackagekit.svgz new file mode 100644 index 00000000..d9811608 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kpackagekit.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kruler.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kruler.svgz new file mode 100644 index 00000000..2f84b8a7 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kruler.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kteatime.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kteatime.svgz new file mode 100644 index 00000000..5e8e2405 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kteatime.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/ktorrent.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/ktorrent.svgz new file mode 100644 index 00000000..663bd493 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/ktorrent.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/kup.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/kup.svgz new file mode 100644 index 00000000..457c866b Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/kup.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/list.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/list.svgz new file mode 100644 index 00000000..aafd2438 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/list.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/mail.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/mail.svgz new file mode 100644 index 00000000..0f0af9a9 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/mail.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/manjaro.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/manjaro.svgz new file mode 100644 index 00000000..a14affff Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/manjaro.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/media.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/media.svgz new file mode 100644 index 00000000..5553cc2f Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/media.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/mobile.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/mobile.svgz new file mode 100644 index 00000000..7bf003a4 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/mobile.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/nepomuk.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/nepomuk.svgz new file mode 100644 index 00000000..d0ddce36 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/nepomuk.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/network.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/network.svgz new file mode 100644 index 00000000..f5ee6dc9 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/network.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/notification.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/notification.svgz new file mode 100644 index 00000000..22e60e61 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/notification.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/osd.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/osd.svgz new file mode 100644 index 00000000..c2f245a8 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/osd.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/pamac.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/pamac.svgz new file mode 100644 index 00000000..8d01db50 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/pamac.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/phone.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/phone.svgz new file mode 100644 index 00000000..f4b2f4a6 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/phone.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/plasmavault.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/plasmavault.svgz new file mode 100644 index 00000000..078301bd Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/plasmavault.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/plasmavault_error.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/plasmavault_error.svgz new file mode 100644 index 00000000..5f964a8e Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/plasmavault_error.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/preferences.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/preferences.svgz new file mode 100644 index 00000000..3ad04713 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/preferences.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/printer.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/printer.svgz new file mode 100644 index 00000000..21f44df2 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/printer.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/quassel.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/quassel.svgz new file mode 100644 index 00000000..4932fc91 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/quassel.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/quota.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/quota.svgz new file mode 100644 index 00000000..5a4328eb Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/quota.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/redshift.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/redshift.svgz new file mode 100644 index 00000000..3e229260 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/redshift.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/search.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/search.svgz new file mode 100644 index 00000000..93faf3f5 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/search.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/slc.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/slc.svgz new file mode 100644 index 00000000..ff6cae58 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/slc.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/software.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/software.svgz new file mode 100644 index 00000000..34d8b900 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/software.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/start.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/start.svgz new file mode 100644 index 00000000..85c1323c Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/start.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/system.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/system.svgz new file mode 100644 index 00000000..49134dbf Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/system.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/touchpad.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/touchpad.svgz new file mode 100644 index 00000000..2a9c4f26 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/touchpad.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/update.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/update.svgz new file mode 100644 index 00000000..f2be57da Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/update.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/user.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/user.svgz new file mode 100644 index 00000000..01e3ae16 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/user.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/video-card.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/video-card.svgz new file mode 100644 index 00000000..969e50c1 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/video-card.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/video.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/video.svgz new file mode 100644 index 00000000..2c0673f8 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/video.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/view.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/view.svgz new file mode 100644 index 00000000..a0e96da8 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/view.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/vlc.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/vlc.svgz new file mode 100644 index 00000000..cdc2363e Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/vlc.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/wallet.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/wallet.svgz new file mode 100644 index 00000000..06200777 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/wallet.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/window.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/window.svgz new file mode 100644 index 00000000..81e16d68 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/window.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/icons/zoom.svgz b/kde/plasma/desktoptheme/Colloid-dark/icons/zoom.svgz new file mode 100644 index 00000000..b07aef6b Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/icons/zoom.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/metadata.desktop b/kde/plasma/desktoptheme/Colloid-dark/metadata.desktop new file mode 100644 index 00000000..686088cb --- /dev/null +++ b/kde/plasma/desktoptheme/Colloid-dark/metadata.desktop @@ -0,0 +1,28 @@ +[Desktop Entry] +Name=Colloid-dark +Comment=Colloid-dark theme for plasma by vince + +X-KDE-PluginInfo-Author=Vince Liuice +X-KDE-PluginInfo-Email=vinceliuice@hotmail.com +X-KDE-PluginInfo-Name=Colloid-dark +X-KDE-PluginInfo-Version=5.84.0 +X-KDE-PluginInfo-Website=https://plasma.kde.org +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-API=5.0 + +[Wallpaper] +defaultWallpaperTheme=Colloid-dark +defaultFileSuffix=.png +defaultWidth=3840 +defaultHeight=2160 + +[ContrastEffect] +enabled=false +contrast=0.2 +intensity=1.4 +saturation=10 + +[AdaptiveTransparency] +enabled=true diff --git a/kde/plasma/desktoptheme/Colloid-dark/solid/dialogs/background.svgz b/kde/plasma/desktoptheme/Colloid-dark/solid/dialogs/background.svgz new file mode 100644 index 00000000..c730c967 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/solid/dialogs/background.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/solid/widgets/background.svgz b/kde/plasma/desktoptheme/Colloid-dark/solid/widgets/background.svgz new file mode 100644 index 00000000..002795a0 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/solid/widgets/background.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/solid/widgets/panel-background.svgz b/kde/plasma/desktoptheme/Colloid-dark/solid/widgets/panel-background.svgz new file mode 100644 index 00000000..9b7619c7 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/solid/widgets/panel-background.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/solid/widgets/tooltip.svgz b/kde/plasma/desktoptheme/Colloid-dark/solid/widgets/tooltip.svgz new file mode 100644 index 00000000..3668dd11 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/solid/widgets/tooltip.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/translucent/dialogs/background.svgz b/kde/plasma/desktoptheme/Colloid-dark/translucent/dialogs/background.svgz new file mode 100644 index 00000000..d91d089d Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/translucent/dialogs/background.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/translucent/widgets/background.svgz b/kde/plasma/desktoptheme/Colloid-dark/translucent/widgets/background.svgz new file mode 100644 index 00000000..a3ce8a16 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/translucent/widgets/background.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/translucent/widgets/panel-background.svgz b/kde/plasma/desktoptheme/Colloid-dark/translucent/widgets/panel-background.svgz new file mode 100644 index 00000000..96a53bf7 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/translucent/widgets/panel-background.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/translucent/widgets/tooltip.svgz b/kde/plasma/desktoptheme/Colloid-dark/translucent/widgets/tooltip.svgz new file mode 100644 index 00000000..284e1560 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/translucent/widgets/tooltip.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/wallpapers/Colloid-dark/contents/images/3840x2160.png b/kde/plasma/desktoptheme/Colloid-dark/wallpapers/Colloid-dark/contents/images/3840x2160.png new file mode 100644 index 00000000..42e3eed1 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/wallpapers/Colloid-dark/contents/images/3840x2160.png differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/wallpapers/Colloid-dark/metadata.desktop b/kde/plasma/desktoptheme/Colloid-dark/wallpapers/Colloid-dark/metadata.desktop new file mode 100644 index 00000000..d1581d6b --- /dev/null +++ b/kde/plasma/desktoptheme/Colloid-dark/wallpapers/Colloid-dark/metadata.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Name=Colloid-dark +X-KDE-PluginInfo-Name=Colloid-dark +X-KDE-PluginInfo-Author=Vince Liuice +X-KDE-PluginInfo-Email=vinceliuice@hotmail.com +X-KDE-PluginInfo-License=CC BY-NC-SA 3.0 diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/action-overlays.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/action-overlays.svgz new file mode 100644 index 00000000..414f4196 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/action-overlays.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/arrows.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/arrows.svgz new file mode 100644 index 00000000..b8b59347 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/arrows.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/background.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/background.svgz new file mode 100644 index 00000000..a3ce8a16 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/background.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/bar_meter_horizontal.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/bar_meter_horizontal.svgz new file mode 100644 index 00000000..21e036f7 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/bar_meter_horizontal.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/bar_meter_vertical.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/bar_meter_vertical.svgz new file mode 100644 index 00000000..b9f12640 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/bar_meter_vertical.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/busywidget.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/busywidget.svgz new file mode 100644 index 00000000..8976a847 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/busywidget.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/button.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/button.svgz new file mode 100644 index 00000000..d83a60f2 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/button.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/calendar.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/calendar.svgz new file mode 100644 index 00000000..1b1ff5be Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/calendar.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/checkmarks.svg b/kde/plasma/desktoptheme/Colloid-dark/widgets/checkmarks.svg new file mode 100644 index 00000000..4e68a81f --- /dev/null +++ b/kde/plasma/desktoptheme/Colloid-dark/widgets/checkmarks.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/clock.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/clock.svgz new file mode 100644 index 00000000..d00330b7 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/clock.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/configuration-icons.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/configuration-icons.svgz new file mode 100644 index 00000000..6ba21ce1 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/configuration-icons.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/containment-controls.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/containment-controls.svgz new file mode 100644 index 00000000..516d811e Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/containment-controls.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/dragger.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/dragger.svgz new file mode 100644 index 00000000..81c4855a Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/dragger.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/frame.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/frame.svgz new file mode 100644 index 00000000..c90b6e30 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/frame.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/glowbar.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/glowbar.svgz new file mode 100644 index 00000000..de42a337 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/glowbar.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/line.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/line.svgz new file mode 100644 index 00000000..687a3cda Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/line.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/lineedit.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/lineedit.svgz new file mode 100644 index 00000000..03704181 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/lineedit.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/listitem.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/listitem.svgz new file mode 100644 index 00000000..487feb42 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/listitem.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/margins-highlight.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/margins-highlight.svgz new file mode 100644 index 00000000..67d8cc36 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/margins-highlight.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/media-delegate.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/media-delegate.svgz new file mode 100644 index 00000000..75398916 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/media-delegate.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/menubaritem.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/menubaritem.svgz new file mode 100644 index 00000000..ee956dfb Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/menubaritem.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/notes.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/notes.svgz new file mode 100644 index 00000000..68c777ec Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/notes.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/pager.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/pager.svgz new file mode 100644 index 00000000..bea8f8e3 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/pager.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/panel-background.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/panel-background.svgz new file mode 100644 index 00000000..96a53bf7 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/panel-background.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/picker.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/picker.svgz new file mode 100644 index 00000000..13c5809c Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/picker.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/plasmoidheading.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/plasmoidheading.svgz new file mode 100644 index 00000000..d1de225b Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/plasmoidheading.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/plot-background.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/plot-background.svgz new file mode 100644 index 00000000..5eb6b97e Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/plot-background.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/scrollbar.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/scrollbar.svgz new file mode 100644 index 00000000..e4f71168 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/scrollbar.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/scrollwidget.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/scrollwidget.svgz new file mode 100644 index 00000000..064c5c00 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/scrollwidget.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/slider.svg b/kde/plasma/desktoptheme/Colloid-dark/widgets/slider.svg new file mode 100644 index 00000000..7330ae27 --- /dev/null +++ b/kde/plasma/desktoptheme/Colloid-dark/widgets/slider.svg @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/tabbar.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/tabbar.svgz new file mode 100644 index 00000000..61b7a5bf Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/tabbar.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/tasks.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/tasks.svgz new file mode 100644 index 00000000..39555eb3 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/tasks.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/timer.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/timer.svgz new file mode 100644 index 00000000..4364927d Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/timer.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/toolbar.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/toolbar.svgz new file mode 100644 index 00000000..c077270e Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/toolbar.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/tooltip.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/tooltip.svgz new file mode 100644 index 00000000..284e1560 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/tooltip.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/translucentbackground.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/translucentbackground.svgz new file mode 100644 index 00000000..4694c216 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/translucentbackground.svgz differ diff --git a/kde/plasma/desktoptheme/Colloid-dark/widgets/viewitem.svgz b/kde/plasma/desktoptheme/Colloid-dark/widgets/viewitem.svgz new file mode 100644 index 00000000..30086b88 Binary files /dev/null and b/kde/plasma/desktoptheme/Colloid-dark/widgets/viewitem.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/colors b/kde/plasma/desktoptheme/Dracula-Solid/colors new file mode 100644 index 00000000..7f4a9e7a --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/colors @@ -0,0 +1,24 @@ +[Colors:Button] +BackgroundNormal=255,255,255 +DecorationFocus=#6E5991 +DecorationHover=#6E5991 +ForegroundNormal=195,199,209 + +[Colors:Complementary] +BackgroundNormal=32,32,32 +DecorationFocus=#6E5991 +DecorationHover=#6E5991 +ForegroundNormal=195,199,209 + +[Colors:View] +BackgroundNormal=#282a36 +DecorationFocus=#6E5991 +DecorationHover=#6E5991 +ForegroundNormal=195,199,209 + +[Colors:Window] +BackgroundNormal=#1e1f29 +DecorationHover=#6E5991 +ForegroundLink=3,77,179 +ForegroundNormal=195,199,209 +ForegroundVisited=153,93,198 diff --git a/kde/plasma/desktoptheme/Dracula-Solid/dialogs/background.svgz b/kde/plasma/desktoptheme/Dracula-Solid/dialogs/background.svgz new file mode 100644 index 00000000..138a8e03 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/dialogs/background.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/icons/applications.svg b/kde/plasma/desktoptheme/Dracula-Solid/icons/applications.svg new file mode 100644 index 00000000..d72538e9 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/icons/applications.svg @@ -0,0 +1,90 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/icons/bookmarks.svg b/kde/plasma/desktoptheme/Dracula-Solid/icons/bookmarks.svg new file mode 100644 index 00000000..bb9b91f6 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/icons/bookmarks.svg @@ -0,0 +1,110 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/icons/computer.svg b/kde/plasma/desktoptheme/Dracula-Solid/icons/computer.svg new file mode 100644 index 00000000..df9bef43 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/icons/computer.svg @@ -0,0 +1,438 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/icons/system.svg b/kde/plasma/desktoptheme/Dracula-Solid/icons/system.svg new file mode 100644 index 00000000..5acfdf2c --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/icons/system.svg @@ -0,0 +1,817 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/icons/view.svg b/kde/plasma/desktoptheme/Dracula-Solid/icons/view.svg new file mode 100644 index 00000000..bc2d747a --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/icons/view.svg @@ -0,0 +1,123 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/metadata.desktop b/kde/plasma/desktoptheme/Dracula-Solid/metadata.desktop new file mode 100644 index 00000000..86628089 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/metadata.desktop @@ -0,0 +1,16 @@ +[Desktop Entry] +Name=Dracula-Solid +Comment[es]=Un tema oscuro creado usando la asombrosa paleta de colores Dracula. +Comment=A dark theme created using the awesome Dracula color palette. +X-KDE-PluginInfo-Author=EliverLara +X-KDE-PluginInfo-Email=eliverlara@gmail.com +X-KDE-PluginInfo-Name=Dracula-Solid +X-KDE-PluginInfo-Version=1.0.0 +X-KDE-PluginInfo-Website=https://github.com/EliverLara/Dracula/tree/master/kde +X-KDE-PluginInfo-Category=Plasma Theme +X-KDE-PluginInfo-License=GPLv3 +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-API=5.0 + +[AdaptiveTransparency] +enabled=true diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/action-overlays.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/action-overlays.svgz new file mode 100644 index 00000000..f164b614 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/action-overlays.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/actionbutton.svg b/kde/plasma/desktoptheme/Dracula-Solid/widgets/actionbutton.svg new file mode 100644 index 00000000..a52eea13 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/widgets/actionbutton.svg @@ -0,0 +1,537 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/arrows.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/arrows.svgz new file mode 100644 index 00000000..f88366d6 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/arrows.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/background.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/background.svgz new file mode 100644 index 00000000..86199329 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/background.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/bar_meter_horizontal.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/bar_meter_horizontal.svgz new file mode 100644 index 00000000..387e5b8b Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/bar_meter_horizontal.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/bar_meter_vertical.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/bar_meter_vertical.svgz new file mode 100644 index 00000000..358d9cca Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/bar_meter_vertical.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/busywidget.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/busywidget.svgz new file mode 100644 index 00000000..d420f9f8 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/busywidget.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/button.svg b/kde/plasma/desktoptheme/Dracula-Solid/widgets/button.svg new file mode 100644 index 00000000..9409e21b --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/widgets/button.svg @@ -0,0 +1,1965 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/checkmarks.svg b/kde/plasma/desktoptheme/Dracula-Solid/widgets/checkmarks.svg new file mode 100644 index 00000000..3275c578 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/widgets/checkmarks.svg @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/clock.svg b/kde/plasma/desktoptheme/Dracula-Solid/widgets/clock.svg new file mode 100644 index 00000000..3b6dcbd9 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/widgets/clock.svg @@ -0,0 +1,323 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/containment-controls.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/containment-controls.svgz new file mode 100644 index 00000000..a1d2dc6e Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/containment-controls.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/frame.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/frame.svgz new file mode 100644 index 00000000..ffbc031e Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/frame.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/glowbar.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/glowbar.svgz new file mode 100644 index 00000000..8a6958db Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/glowbar.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/line.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/line.svgz new file mode 100644 index 00000000..bb39ca8a Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/line.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/lineedit.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/lineedit.svgz new file mode 100644 index 00000000..12cf8cda Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/lineedit.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/listitem.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/listitem.svgz new file mode 100644 index 00000000..abb2e15f Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/listitem.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/pager.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/pager.svgz new file mode 100644 index 00000000..46f1b630 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/pager.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/panel-background.svg b/kde/plasma/desktoptheme/Dracula-Solid/widgets/panel-background.svg new file mode 100644 index 00000000..43e1ee13 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/widgets/panel-background.svg @@ -0,0 +1,389 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/plot-background.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/plot-background.svgz new file mode 100644 index 00000000..4ab396a0 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/plot-background.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/scrollbar.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/scrollbar.svgz new file mode 100644 index 00000000..e8d458a6 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/scrollbar.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/scrollwidget.svg b/kde/plasma/desktoptheme/Dracula-Solid/widgets/scrollwidget.svg new file mode 100644 index 00000000..80879aed --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula-Solid/widgets/scrollwidget.svg @@ -0,0 +1,432 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/slider.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/slider.svgz new file mode 100644 index 00000000..1eb90915 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/slider.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/tabbar.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/tabbar.svgz new file mode 100644 index 00000000..32acc227 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/tabbar.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/tasks.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/tasks.svgz new file mode 100644 index 00000000..51a99a04 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/tasks.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/timer.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/timer.svgz new file mode 100644 index 00000000..9fc40247 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/timer.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/toolbar.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/toolbar.svgz new file mode 100644 index 00000000..ae57bfe9 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/toolbar.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/tooltip.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/tooltip.svgz new file mode 100644 index 00000000..a00a7755 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/tooltip.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/translucentbackground.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/translucentbackground.svgz new file mode 100644 index 00000000..fdb10c21 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/translucentbackground.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula-Solid/widgets/viewitem.svgz b/kde/plasma/desktoptheme/Dracula-Solid/widgets/viewitem.svgz new file mode 100644 index 00000000..b1848908 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula-Solid/widgets/viewitem.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/colors b/kde/plasma/desktoptheme/Dracula/colors new file mode 100644 index 00000000..7f4a9e7a --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/colors @@ -0,0 +1,24 @@ +[Colors:Button] +BackgroundNormal=255,255,255 +DecorationFocus=#6E5991 +DecorationHover=#6E5991 +ForegroundNormal=195,199,209 + +[Colors:Complementary] +BackgroundNormal=32,32,32 +DecorationFocus=#6E5991 +DecorationHover=#6E5991 +ForegroundNormal=195,199,209 + +[Colors:View] +BackgroundNormal=#282a36 +DecorationFocus=#6E5991 +DecorationHover=#6E5991 +ForegroundNormal=195,199,209 + +[Colors:Window] +BackgroundNormal=#1e1f29 +DecorationHover=#6E5991 +ForegroundLink=3,77,179 +ForegroundNormal=195,199,209 +ForegroundVisited=153,93,198 diff --git a/kde/plasma/desktoptheme/Dracula/dialogs/background.svgz b/kde/plasma/desktoptheme/Dracula/dialogs/background.svgz new file mode 100644 index 00000000..95873ce6 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/dialogs/background.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/icons/applications.svg b/kde/plasma/desktoptheme/Dracula/icons/applications.svg new file mode 100644 index 00000000..d72538e9 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/icons/applications.svg @@ -0,0 +1,90 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/icons/bookmarks.svg b/kde/plasma/desktoptheme/Dracula/icons/bookmarks.svg new file mode 100644 index 00000000..bb9b91f6 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/icons/bookmarks.svg @@ -0,0 +1,110 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/icons/computer.svg b/kde/plasma/desktoptheme/Dracula/icons/computer.svg new file mode 100644 index 00000000..df9bef43 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/icons/computer.svg @@ -0,0 +1,438 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/icons/system.svg b/kde/plasma/desktoptheme/Dracula/icons/system.svg new file mode 100644 index 00000000..5acfdf2c --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/icons/system.svg @@ -0,0 +1,817 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/icons/view.svg b/kde/plasma/desktoptheme/Dracula/icons/view.svg new file mode 100644 index 00000000..bc2d747a --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/icons/view.svg @@ -0,0 +1,123 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/metadata.desktop b/kde/plasma/desktoptheme/Dracula/metadata.desktop new file mode 100644 index 00000000..d2cd3a27 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/metadata.desktop @@ -0,0 +1,16 @@ +[Desktop Entry] +Name=Dracula +Comment[es]=Un tema oscuro creado usando la asombrosa paleta de colores Dracula. +Comment=A dark theme created using the awesome Dracula color palette. +X-KDE-PluginInfo-Author=EliverLara +X-KDE-PluginInfo-Email=eliverlara@gmail.com +X-KDE-PluginInfo-Name=Dracula +X-KDE-PluginInfo-Version=1.0.0 +X-KDE-PluginInfo-Website=https://github.com/EliverLara/Ant-Dracula/tree/master/kde +X-KDE-PluginInfo-Category=Plasma Theme +X-KDE-PluginInfo-License=GPLv3 +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-API=5.0 + +[AdaptiveTransparency] +enabled=true diff --git a/kde/plasma/desktoptheme/Dracula/widgets/action-overlays.svgz b/kde/plasma/desktoptheme/Dracula/widgets/action-overlays.svgz new file mode 100644 index 00000000..f164b614 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/action-overlays.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/actionbutton.svg b/kde/plasma/desktoptheme/Dracula/widgets/actionbutton.svg new file mode 100644 index 00000000..a52eea13 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/widgets/actionbutton.svg @@ -0,0 +1,537 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/widgets/arrows.svgz b/kde/plasma/desktoptheme/Dracula/widgets/arrows.svgz new file mode 100644 index 00000000..f88366d6 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/arrows.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/background.svgz b/kde/plasma/desktoptheme/Dracula/widgets/background.svgz new file mode 100644 index 00000000..86199329 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/background.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/bar_meter_horizontal.svgz b/kde/plasma/desktoptheme/Dracula/widgets/bar_meter_horizontal.svgz new file mode 100644 index 00000000..387e5b8b Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/bar_meter_horizontal.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/bar_meter_vertical.svgz b/kde/plasma/desktoptheme/Dracula/widgets/bar_meter_vertical.svgz new file mode 100644 index 00000000..358d9cca Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/bar_meter_vertical.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/busywidget.svgz b/kde/plasma/desktoptheme/Dracula/widgets/busywidget.svgz new file mode 100644 index 00000000..d420f9f8 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/busywidget.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/button.svg b/kde/plasma/desktoptheme/Dracula/widgets/button.svg new file mode 100644 index 00000000..9409e21b --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/widgets/button.svg @@ -0,0 +1,1965 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/widgets/checkmarks.svg b/kde/plasma/desktoptheme/Dracula/widgets/checkmarks.svg new file mode 100644 index 00000000..3275c578 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/widgets/checkmarks.svg @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/widgets/clock.svg b/kde/plasma/desktoptheme/Dracula/widgets/clock.svg new file mode 100644 index 00000000..3b6dcbd9 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/widgets/clock.svg @@ -0,0 +1,323 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/widgets/containment-controls.svgz b/kde/plasma/desktoptheme/Dracula/widgets/containment-controls.svgz new file mode 100644 index 00000000..a1d2dc6e Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/containment-controls.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/frame.svgz b/kde/plasma/desktoptheme/Dracula/widgets/frame.svgz new file mode 100644 index 00000000..ffbc031e Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/frame.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/glowbar.svgz b/kde/plasma/desktoptheme/Dracula/widgets/glowbar.svgz new file mode 100644 index 00000000..8a6958db Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/glowbar.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/line.svgz b/kde/plasma/desktoptheme/Dracula/widgets/line.svgz new file mode 100644 index 00000000..bb39ca8a Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/line.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/lineedit.svgz b/kde/plasma/desktoptheme/Dracula/widgets/lineedit.svgz new file mode 100644 index 00000000..12cf8cda Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/lineedit.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/listitem.svgz b/kde/plasma/desktoptheme/Dracula/widgets/listitem.svgz new file mode 100644 index 00000000..abb2e15f Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/listitem.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/pager.svgz b/kde/plasma/desktoptheme/Dracula/widgets/pager.svgz new file mode 100644 index 00000000..46f1b630 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/pager.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/panel-background.svg b/kde/plasma/desktoptheme/Dracula/widgets/panel-background.svg new file mode 100644 index 00000000..5c2e1381 --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/widgets/panel-background.svg @@ -0,0 +1,389 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/widgets/plot-background.svgz b/kde/plasma/desktoptheme/Dracula/widgets/plot-background.svgz new file mode 100644 index 00000000..4ab396a0 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/plot-background.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/scrollbar.svgz b/kde/plasma/desktoptheme/Dracula/widgets/scrollbar.svgz new file mode 100644 index 00000000..e8d458a6 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/scrollbar.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/scrollwidget.svg b/kde/plasma/desktoptheme/Dracula/widgets/scrollwidget.svg new file mode 100644 index 00000000..80879aed --- /dev/null +++ b/kde/plasma/desktoptheme/Dracula/widgets/scrollwidget.svg @@ -0,0 +1,432 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kde/plasma/desktoptheme/Dracula/widgets/slider.svgz b/kde/plasma/desktoptheme/Dracula/widgets/slider.svgz new file mode 100644 index 00000000..1eb90915 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/slider.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/tabbar.svgz b/kde/plasma/desktoptheme/Dracula/widgets/tabbar.svgz new file mode 100644 index 00000000..32acc227 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/tabbar.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/tasks.svgz b/kde/plasma/desktoptheme/Dracula/widgets/tasks.svgz new file mode 100644 index 00000000..51a99a04 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/tasks.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/timer.svgz b/kde/plasma/desktoptheme/Dracula/widgets/timer.svgz new file mode 100644 index 00000000..9fc40247 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/timer.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/toolbar.svgz b/kde/plasma/desktoptheme/Dracula/widgets/toolbar.svgz new file mode 100644 index 00000000..ae57bfe9 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/toolbar.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/tooltip.svgz b/kde/plasma/desktoptheme/Dracula/widgets/tooltip.svgz new file mode 100644 index 00000000..09a97842 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/tooltip.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/translucentbackground.svgz b/kde/plasma/desktoptheme/Dracula/widgets/translucentbackground.svgz new file mode 100644 index 00000000..fdb10c21 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/translucentbackground.svgz differ diff --git a/kde/plasma/desktoptheme/Dracula/widgets/viewitem.svgz b/kde/plasma/desktoptheme/Dracula/widgets/viewitem.svgz new file mode 100644 index 00000000..b1848908 Binary files /dev/null and b/kde/plasma/desktoptheme/Dracula/widgets/viewitem.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/dialogs/background.svgz b/kde/plasma/desktoptheme/metadata/dialogs/background.svgz new file mode 100644 index 00000000..81da5e83 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/dialogs/background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/akonadi.svgz b/kde/plasma/desktoptheme/metadata/icons/akonadi.svgz new file mode 100644 index 00000000..26e17e0e Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/akonadi.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/akregator.svgz b/kde/plasma/desktoptheme/metadata/icons/akregator.svgz new file mode 100644 index 00000000..2cc37e02 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/akregator.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/amarok.svgz b/kde/plasma/desktoptheme/metadata/icons/amarok.svgz new file mode 100644 index 00000000..3ec39aa9 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/amarok.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/applications.svgz b/kde/plasma/desktoptheme/metadata/icons/applications.svgz new file mode 100644 index 00000000..6fd0675a Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/applications.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/apport.svgz b/kde/plasma/desktoptheme/metadata/icons/apport.svgz new file mode 100644 index 00000000..24753d65 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/apport.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/audio.svgz b/kde/plasma/desktoptheme/metadata/icons/audio.svgz new file mode 100644 index 00000000..6ddfb060 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/audio.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/battery.svgz b/kde/plasma/desktoptheme/metadata/icons/battery.svgz new file mode 100644 index 00000000..a222c4b8 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/battery.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/bookmarks.svgz b/kde/plasma/desktoptheme/metadata/icons/bookmarks.svgz new file mode 100644 index 00000000..ad95bd2a Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/bookmarks.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/cantata.svgz b/kde/plasma/desktoptheme/metadata/icons/cantata.svgz new file mode 100644 index 00000000..4a57f2af Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/cantata.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/computer.svgz b/kde/plasma/desktoptheme/metadata/icons/computer.svgz new file mode 100644 index 00000000..281b9b47 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/computer.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/configure.svgz b/kde/plasma/desktoptheme/metadata/icons/configure.svgz new file mode 100644 index 00000000..c74f3e08 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/configure.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/device.svgz b/kde/plasma/desktoptheme/metadata/icons/device.svgz new file mode 100644 index 00000000..1993d022 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/device.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/disk.svgz b/kde/plasma/desktoptheme/metadata/icons/disk.svgz new file mode 100644 index 00000000..2f018faf Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/disk.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/distribute.svgz b/kde/plasma/desktoptheme/metadata/icons/distribute.svgz new file mode 100644 index 00000000..689eb8b5 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/distribute.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/document.svgz b/kde/plasma/desktoptheme/metadata/icons/document.svgz new file mode 100644 index 00000000..da3ef9fc Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/document.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/drive.svgz b/kde/plasma/desktoptheme/metadata/icons/drive.svgz new file mode 100644 index 00000000..448391ec Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/drive.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/edit.svgz b/kde/plasma/desktoptheme/metadata/icons/edit.svgz new file mode 100644 index 00000000..361e13f5 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/edit.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/fcitx.svgz b/kde/plasma/desktoptheme/metadata/icons/fcitx.svgz new file mode 100644 index 00000000..8e2f07a8 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/fcitx.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/go.svgz b/kde/plasma/desktoptheme/metadata/icons/go.svgz new file mode 100644 index 00000000..f473fc4c Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/go.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/ime.svgz b/kde/plasma/desktoptheme/metadata/icons/ime.svgz new file mode 100644 index 00000000..578c35cd Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/ime.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/input.svgz b/kde/plasma/desktoptheme/metadata/icons/input.svgz new file mode 100644 index 00000000..3a4c53e5 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/input.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kalarm.svgz b/kde/plasma/desktoptheme/metadata/icons/kalarm.svgz new file mode 100644 index 00000000..bc1d5a0e Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kalarm.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kdeconnect.svgz b/kde/plasma/desktoptheme/metadata/icons/kdeconnect.svgz new file mode 100644 index 00000000..ddfa1967 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kdeconnect.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/keyboard.svgz b/kde/plasma/desktoptheme/metadata/icons/keyboard.svgz new file mode 100644 index 00000000..c3ed2ffa Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/keyboard.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kget.svgz b/kde/plasma/desktoptheme/metadata/icons/kget.svgz new file mode 100644 index 00000000..c7371830 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kget.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kgpg.svgz b/kde/plasma/desktoptheme/metadata/icons/kgpg.svgz new file mode 100644 index 00000000..fdc65f86 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kgpg.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kleopatra.svgz b/kde/plasma/desktoptheme/metadata/icons/kleopatra.svgz new file mode 100644 index 00000000..39835a37 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kleopatra.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/klipper.svgz b/kde/plasma/desktoptheme/metadata/icons/klipper.svgz new file mode 100644 index 00000000..c331ae58 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/klipper.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kmail.svgz b/kde/plasma/desktoptheme/metadata/icons/kmail.svgz new file mode 100644 index 00000000..1ed84925 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kmail.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/konv_message.svgz b/kde/plasma/desktoptheme/metadata/icons/konv_message.svgz new file mode 100644 index 00000000..47dd526b Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/konv_message.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/konversation.svgz b/kde/plasma/desktoptheme/metadata/icons/konversation.svgz new file mode 100644 index 00000000..70406c56 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/konversation.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kopete.svgz b/kde/plasma/desktoptheme/metadata/icons/kopete.svgz new file mode 100644 index 00000000..6d17fa87 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kopete.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/korgac.svgz b/kde/plasma/desktoptheme/metadata/icons/korgac.svgz new file mode 100644 index 00000000..ca61a31c Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/korgac.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kpackagekit.svgz b/kde/plasma/desktoptheme/metadata/icons/kpackagekit.svgz new file mode 100644 index 00000000..22e894f9 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kpackagekit.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kruler.svgz b/kde/plasma/desktoptheme/metadata/icons/kruler.svgz new file mode 100644 index 00000000..d5d69d9e Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kruler.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kteatime.svgz b/kde/plasma/desktoptheme/metadata/icons/kteatime.svgz new file mode 100644 index 00000000..b515c8b9 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kteatime.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/ktorrent.svgz b/kde/plasma/desktoptheme/metadata/icons/ktorrent.svgz new file mode 100644 index 00000000..0cef8efd Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/ktorrent.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/kup.svgz b/kde/plasma/desktoptheme/metadata/icons/kup.svgz new file mode 100644 index 00000000..81a9efe6 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/kup.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/list.svgz b/kde/plasma/desktoptheme/metadata/icons/list.svgz new file mode 100644 index 00000000..182df736 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/list.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/mail.svgz b/kde/plasma/desktoptheme/metadata/icons/mail.svgz new file mode 100644 index 00000000..0d886433 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/mail.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/media.svgz b/kde/plasma/desktoptheme/metadata/icons/media.svgz new file mode 100644 index 00000000..d2500755 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/media.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/mobile.svgz b/kde/plasma/desktoptheme/metadata/icons/mobile.svgz new file mode 100644 index 00000000..e44ad0f8 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/mobile.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/network.svgz b/kde/plasma/desktoptheme/metadata/icons/network.svgz new file mode 100644 index 00000000..de5f3148 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/network.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/notification.svgz b/kde/plasma/desktoptheme/metadata/icons/notification.svgz new file mode 100644 index 00000000..85575de2 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/notification.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/osd.svgz b/kde/plasma/desktoptheme/metadata/icons/osd.svgz new file mode 100644 index 00000000..cd9e5691 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/osd.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/phone.svgz b/kde/plasma/desktoptheme/metadata/icons/phone.svgz new file mode 100644 index 00000000..4d1e65b4 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/phone.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/plasmavault.svgz b/kde/plasma/desktoptheme/metadata/icons/plasmavault.svgz new file mode 100644 index 00000000..61f5a324 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/plasmavault.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/plasmavault_error.svgz b/kde/plasma/desktoptheme/metadata/icons/plasmavault_error.svgz new file mode 100644 index 00000000..43b9d7ad Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/plasmavault_error.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/preferences.svgz b/kde/plasma/desktoptheme/metadata/icons/preferences.svgz new file mode 100644 index 00000000..2ee1f7da Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/preferences.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/printer.svgz b/kde/plasma/desktoptheme/metadata/icons/printer.svgz new file mode 100644 index 00000000..7c786be0 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/printer.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/quassel.svgz b/kde/plasma/desktoptheme/metadata/icons/quassel.svgz new file mode 100644 index 00000000..3d3b6784 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/quassel.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/search.svgz b/kde/plasma/desktoptheme/metadata/icons/search.svgz new file mode 100644 index 00000000..76a24444 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/search.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/slc.svgz b/kde/plasma/desktoptheme/metadata/icons/slc.svgz new file mode 100644 index 00000000..0a8cb186 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/slc.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/software.svgz b/kde/plasma/desktoptheme/metadata/icons/software.svgz new file mode 100644 index 00000000..3af4b674 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/software.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/start.svgz b/kde/plasma/desktoptheme/metadata/icons/start.svgz new file mode 100644 index 00000000..c2865ac4 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/start.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/system.svgz b/kde/plasma/desktoptheme/metadata/icons/system.svgz new file mode 100644 index 00000000..847fadff Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/system.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/touchpad.svg b/kde/plasma/desktoptheme/metadata/icons/touchpad.svg new file mode 100644 index 00000000..8648ea88 --- /dev/null +++ b/kde/plasma/desktoptheme/metadata/icons/touchpad.svg @@ -0,0 +1,30 @@ + + + + + + + + + + image/svg+xml + + + + + + + + touchpad_enabled + + + + + + touchpad_disabled + + + + + + diff --git a/kde/plasma/desktoptheme/metadata/icons/touchpad.svgz b/kde/plasma/desktoptheme/metadata/icons/touchpad.svgz new file mode 100644 index 00000000..2116b828 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/touchpad.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/user.svgz b/kde/plasma/desktoptheme/metadata/icons/user.svgz new file mode 100644 index 00000000..01dc29ef Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/user.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/video-card.svgz b/kde/plasma/desktoptheme/metadata/icons/video-card.svgz new file mode 100644 index 00000000..1931b380 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/video-card.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/video.svgz b/kde/plasma/desktoptheme/metadata/icons/video.svgz new file mode 100644 index 00000000..941e55e8 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/video.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/view.svgz b/kde/plasma/desktoptheme/metadata/icons/view.svgz new file mode 100644 index 00000000..c9f11475 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/view.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/vlc.svgz b/kde/plasma/desktoptheme/metadata/icons/vlc.svgz new file mode 100644 index 00000000..a2f6a6ca Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/vlc.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/wallet.svgz b/kde/plasma/desktoptheme/metadata/icons/wallet.svgz new file mode 100644 index 00000000..4a34c675 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/wallet.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/window.svgz b/kde/plasma/desktoptheme/metadata/icons/window.svgz new file mode 100644 index 00000000..2a183ca9 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/window.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/yakuake.svgz b/kde/plasma/desktoptheme/metadata/icons/yakuake.svgz new file mode 100644 index 00000000..d432446d Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/yakuake.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/icons/zoom.svgz b/kde/plasma/desktoptheme/metadata/icons/zoom.svgz new file mode 100644 index 00000000..9c6346da Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/icons/zoom.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/metadata.desktop b/kde/plasma/desktoptheme/metadata/metadata.desktop new file mode 100644 index 00000000..e0b1dfb1 --- /dev/null +++ b/kde/plasma/desktoptheme/metadata/metadata.desktop @@ -0,0 +1,26 @@ +[AdaptiveTransparency] +enabled=true + +[ContrastEffect] +contrast=0.2 +enabled=false +intensity=0.4 +saturation=1.7 + +[Desktop Entry] +X-KDE-PluginInfo-Version=1 + +[DesktopEntry] +Comment=Fan Favorite Tokyo Night Theme for Plasma Desktop +Name=Tokyo-Night +X-KDE-PluginInfo-Author=JayyDev +X-KDE-PluginInfo-Email=none25711@gmail.com +X-KDE-PluginInfo-License=GPL_V3 +X-KDE-PluginInfo-Name=Tokyo Night +X-KDE-PluginInfo-Version=1 +X-KDE-PluginInfo-Website=https://github.com/Jayy-Dev/Plasma-Tokyo-Night +X-Plasma-API=5.0 + +[Wallpaper] +defaultFileSuffix=.jpg +defaultWallpaperTheme=Tokyo-Night diff --git a/kde/plasma/desktoptheme/metadata/opaque/dialogs/background.svgz b/kde/plasma/desktoptheme/metadata/opaque/dialogs/background.svgz new file mode 100644 index 00000000..142286ea Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/opaque/dialogs/background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/opaque/widgets/panel-background.svgz b/kde/plasma/desktoptheme/metadata/opaque/widgets/panel-background.svgz new file mode 100644 index 00000000..f00a05eb Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/opaque/widgets/panel-background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/opaque/widgets/tooltip.svgz b/kde/plasma/desktoptheme/metadata/opaque/widgets/tooltip.svgz new file mode 100644 index 00000000..5e01ba58 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/opaque/widgets/tooltip.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/solid/dialogs/background.svgz b/kde/plasma/desktoptheme/metadata/solid/dialogs/background.svgz new file mode 100644 index 00000000..b787c2c0 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/solid/dialogs/background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/solid/widgets/background.svgz b/kde/plasma/desktoptheme/metadata/solid/widgets/background.svgz new file mode 100644 index 00000000..2b6b4f83 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/solid/widgets/background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/solid/widgets/panel-background.svgz b/kde/plasma/desktoptheme/metadata/solid/widgets/panel-background.svgz new file mode 100644 index 00000000..0f669370 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/solid/widgets/panel-background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/solid/widgets/tooltip.svgz b/kde/plasma/desktoptheme/metadata/solid/widgets/tooltip.svgz new file mode 100644 index 00000000..4713a1c3 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/solid/widgets/tooltip.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/translucent/dialogs/background.svgz b/kde/plasma/desktoptheme/metadata/translucent/dialogs/background.svgz new file mode 100644 index 00000000..cd725f1e Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/translucent/dialogs/background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/translucent/widgets/background.svgz b/kde/plasma/desktoptheme/metadata/translucent/widgets/background.svgz new file mode 100644 index 00000000..635ede7e Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/translucent/widgets/background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/translucent/widgets/panel-background.svgz b/kde/plasma/desktoptheme/metadata/translucent/widgets/panel-background.svgz new file mode 100644 index 00000000..035b914a Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/translucent/widgets/panel-background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/translucent/widgets/tooltip.svgz b/kde/plasma/desktoptheme/metadata/translucent/widgets/tooltip.svgz new file mode 100644 index 00000000..4ec55be2 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/translucent/widgets/tooltip.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/weather/wind-arrows.svgz b/kde/plasma/desktoptheme/metadata/weather/wind-arrows.svgz new file mode 100644 index 00000000..666ec85d Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/weather/wind-arrows.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/action-overlays.svgz b/kde/plasma/desktoptheme/metadata/widgets/action-overlays.svgz new file mode 100644 index 00000000..bc22be5a Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/action-overlays.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/actionbutton.svgz b/kde/plasma/desktoptheme/metadata/widgets/actionbutton.svgz new file mode 100644 index 00000000..bda1c0b8 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/actionbutton.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/analog_meter.svgz b/kde/plasma/desktoptheme/metadata/widgets/analog_meter.svgz new file mode 100644 index 00000000..1576ca32 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/analog_meter.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/arrows.svgz b/kde/plasma/desktoptheme/metadata/widgets/arrows.svgz new file mode 100644 index 00000000..b1b28703 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/arrows.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/background.svgz b/kde/plasma/desktoptheme/metadata/widgets/background.svgz new file mode 100644 index 00000000..407fd653 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/bar_meter_horizontal.svgz b/kde/plasma/desktoptheme/metadata/widgets/bar_meter_horizontal.svgz new file mode 100644 index 00000000..afeb6aed Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/bar_meter_horizontal.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/bar_meter_vertical.svgz b/kde/plasma/desktoptheme/metadata/widgets/bar_meter_vertical.svgz new file mode 100644 index 00000000..afeb6aed Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/bar_meter_vertical.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/branding.svgz b/kde/plasma/desktoptheme/metadata/widgets/branding.svgz new file mode 100644 index 00000000..c06df31d Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/branding.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/busywidget.svgz b/kde/plasma/desktoptheme/metadata/widgets/busywidget.svgz new file mode 100644 index 00000000..f6034831 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/busywidget.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/button.svgz b/kde/plasma/desktoptheme/metadata/widgets/button.svgz new file mode 100644 index 00000000..6218159f Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/button.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/calendar.svgz b/kde/plasma/desktoptheme/metadata/widgets/calendar.svgz new file mode 100644 index 00000000..288d790d Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/calendar.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/checkmarks.svgz b/kde/plasma/desktoptheme/metadata/widgets/checkmarks.svgz new file mode 100644 index 00000000..2b9a521e Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/checkmarks.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/clock.svgz b/kde/plasma/desktoptheme/metadata/widgets/clock.svgz new file mode 100644 index 00000000..9900b958 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/clock.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/configuration-icons.svgz b/kde/plasma/desktoptheme/metadata/widgets/configuration-icons.svgz new file mode 100644 index 00000000..284dffff Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/configuration-icons.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/containment-controls.svgz b/kde/plasma/desktoptheme/metadata/widgets/containment-controls.svgz new file mode 100644 index 00000000..49811305 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/containment-controls.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/dragger.svgz b/kde/plasma/desktoptheme/metadata/widgets/dragger.svgz new file mode 100644 index 00000000..19d0ed63 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/dragger.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/frame.svgz b/kde/plasma/desktoptheme/metadata/widgets/frame.svgz new file mode 100644 index 00000000..e26b611d Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/frame.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/glowbar.svgz b/kde/plasma/desktoptheme/metadata/widgets/glowbar.svgz new file mode 100644 index 00000000..39d41f38 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/glowbar.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/line.svgz b/kde/plasma/desktoptheme/metadata/widgets/line.svgz new file mode 100644 index 00000000..687a3cda Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/line.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/lineedit.svgz b/kde/plasma/desktoptheme/metadata/widgets/lineedit.svgz new file mode 100644 index 00000000..09be930a Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/lineedit.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/listitem.svgz b/kde/plasma/desktoptheme/metadata/widgets/listitem.svgz new file mode 100644 index 00000000..ccebace6 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/listitem.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/margins-highlight.svgz b/kde/plasma/desktoptheme/metadata/widgets/margins-highlight.svgz new file mode 100644 index 00000000..34503d0f Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/margins-highlight.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/media-delegate.svgz b/kde/plasma/desktoptheme/metadata/widgets/media-delegate.svgz new file mode 100644 index 00000000..616f8974 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/media-delegate.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/menubaritem.svgz b/kde/plasma/desktoptheme/metadata/widgets/menubaritem.svgz new file mode 100644 index 00000000..4d27f9ad Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/menubaritem.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/monitor.svgz b/kde/plasma/desktoptheme/metadata/widgets/monitor.svgz new file mode 100644 index 00000000..21498e45 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/monitor.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/notes.svgz b/kde/plasma/desktoptheme/metadata/widgets/notes.svgz new file mode 100644 index 00000000..854f8170 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/notes.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/pager.svgz b/kde/plasma/desktoptheme/metadata/widgets/pager.svgz new file mode 100644 index 00000000..b616c4d3 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/pager.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/panel-background.svgz b/kde/plasma/desktoptheme/metadata/widgets/panel-background.svgz new file mode 100644 index 00000000..dd3268b2 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/panel-background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/picker.svgz b/kde/plasma/desktoptheme/metadata/widgets/picker.svgz new file mode 100644 index 00000000..871e012c Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/picker.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/plasmoidheading.svgz b/kde/plasma/desktoptheme/metadata/widgets/plasmoidheading.svgz new file mode 100644 index 00000000..fd0fcfff Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/plasmoidheading.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/plot-background.svgz b/kde/plasma/desktoptheme/metadata/widgets/plot-background.svgz new file mode 100644 index 00000000..51956284 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/plot-background.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/radiobutton.svgz b/kde/plasma/desktoptheme/metadata/widgets/radiobutton.svgz new file mode 100644 index 00000000..026cfab6 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/radiobutton.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/scrollbar.svgz b/kde/plasma/desktoptheme/metadata/widgets/scrollbar.svgz new file mode 100644 index 00000000..c60c5136 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/scrollbar.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/scrollwidget.svgz b/kde/plasma/desktoptheme/metadata/widgets/scrollwidget.svgz new file mode 100644 index 00000000..2e94aea3 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/scrollwidget.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/slider.svgz b/kde/plasma/desktoptheme/metadata/widgets/slider.svgz new file mode 100644 index 00000000..f8635bc5 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/slider.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/tabbar.svgz b/kde/plasma/desktoptheme/metadata/widgets/tabbar.svgz new file mode 100644 index 00000000..7dbdd2b1 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/tabbar.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/tasks.svgz b/kde/plasma/desktoptheme/metadata/widgets/tasks.svgz new file mode 100644 index 00000000..64fae9a7 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/tasks.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/timer.svgz b/kde/plasma/desktoptheme/metadata/widgets/timer.svgz new file mode 100644 index 00000000..4364927d Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/timer.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/toolbar.svgz b/kde/plasma/desktoptheme/metadata/widgets/toolbar.svgz new file mode 100644 index 00000000..eb8471ce Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/toolbar.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/tooltip.svgz b/kde/plasma/desktoptheme/metadata/widgets/tooltip.svgz new file mode 100644 index 00000000..0a4ac7e6 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/tooltip.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/translucentbackground.svgz b/kde/plasma/desktoptheme/metadata/widgets/translucentbackground.svgz new file mode 100644 index 00000000..d1ddfc43 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/translucentbackground.svgz differ diff --git a/kde/plasma/desktoptheme/metadata/widgets/viewitem.svgz b/kde/plasma/desktoptheme/metadata/widgets/viewitem.svgz new file mode 100644 index 00000000..68d6b510 Binary files /dev/null and b/kde/plasma/desktoptheme/metadata/widgets/viewitem.svgz differ diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/ActionButton.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/components/ActionButton.qml new file mode 100644 index 00000000..b11b4bbe --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/components/ActionButton.qml @@ -0,0 +1,130 @@ +/* + * Copyright 2016 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.8 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item { + id: root + property alias text: label.text + property alias iconSource: icon.source + property alias containsMouse: mouseArea.containsMouse + property alias font: label.font + property alias labelRendering: label.renderType + property alias circleOpacity: iconCircle.opacity + property alias circleVisiblity: iconCircle.visible + property int fontSize: config.fontSize + readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software + signal clicked + + activeFocusOnTab: true + + property int iconSize: units.gridUnit * 3 + + implicitWidth: Math.max(iconSize + units.largeSpacing * 2, label.contentWidth) + implicitHeight: iconSize + units.smallSpacing + label.implicitHeight + + opacity: activeFocus || containsMouse ? 1 : 0.85 + Behavior on opacity { + PropertyAnimation { // OpacityAnimator makes it turn black at random intervals + duration: units.longDuration + easing.type: Easing.InOutQuad + } + } + + Rectangle { + id: iconCircle + anchors.centerIn: icon + width: iconSize + units.smallSpacing + height: width + radius: width / 2 + color: "#09090C" + border.color: "#9B79CC" + border.width: 1 + opacity: activeFocus || containsMouse ? (softwareRendering ? 0.8 : 0.15) : (softwareRendering ? 0.6 : 0) + Behavior on opacity { + PropertyAnimation { // OpacityAnimator makes it turn black at random intervals + duration: units.longDuration + easing.type: Easing.InOutQuad + } + } + } + + Rectangle { + anchors.centerIn: iconCircle + width: iconCircle.width + height: width + radius: width / 2 + scale: mouseArea.containsPress ? 1 : 0 + color: PlasmaCore.ColorScope.textColor + opacity: 0.15 + Behavior on scale { + PropertyAnimation { + duration: units.shortDuration + easing.type: Easing.InOutQuart + } + } + } + + PlasmaCore.IconItem { + id: icon + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + } + width: iconSize + height: iconSize + + colorGroup: PlasmaCore.ColorScope.colorGroup + active: mouseArea.containsMouse || root.activeFocus + } + + PlasmaComponents.Label { + id: label + font.pointSize: Math.max(fontSize + 1,theme.defaultFont.pointSize + 1) + anchors { + top: icon.bottom + topMargin: (softwareRendering ? 1.5 : 1) * units.smallSpacing + left: parent.left + right: parent.right + } + style: softwareRendering ? Text.Outline : Text.Normal + styleColor: softwareRendering ? PlasmaCore.ColorScope.backgroundColor : "transparent" //no outline, doesn't matter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignTop + wrapMode: Text.WordWrap + font.underline: root.activeFocus + } + + MouseArea { + id: mouseArea + hoverEnabled: true + onClicked: root.clicked() + anchors.fill: parent + } + + Keys.onEnterPressed: clicked() + Keys.onReturnPressed: clicked() + Keys.onSpacePressed: clicked() + + Accessible.onPressAction: clicked() + Accessible.role: Accessible.Button + Accessible.name: label.text +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/Battery.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/components/Battery.qml new file mode 100644 index 00000000..2351c4de --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/components/Battery.qml @@ -0,0 +1,53 @@ +/* + * Copyright 2016 Kai Uwe Broulik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.2 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.workspace.components 2.0 as PW + +Row { + spacing: units.smallSpacing + visible: pmSource.data["Battery"]["Has Cumulative"] + + PlasmaCore.DataSource { + id: pmSource + engine: "powermanagement" + connectedSources: ["Battery", "AC Adapter"] + } + + PW.BatteryIcon { + id: battery + hasBattery: pmSource.data["Battery"]["Has Battery"] || false + percent: pmSource.data["Battery"]["Percent"] || 0 + pluggedIn: pmSource.data["AC Adapter"] ? pmSource.data["AC Adapter"]["Plugged in"] : false + + height: batteryLabel.height + width: height + } + + PlasmaComponents.Label { + id: batteryLabel + font.pointSize: config.fontSize + height: undefined + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel","%1%", battery.percent) + Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel","Battery at %1%", battery.percent) + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/Clock.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/components/Clock.qml new file mode 100644 index 00000000..14bea3b2 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/components/Clock.qml @@ -0,0 +1,50 @@ +/* + * Copyright 2016 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.8 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.5 +import org.kde.plasma.core 2.0 + +ColumnLayout { + readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software + + Label { + text: Qt.formatTime(timeSource.data["Local"]["DateTime"]) + color: ColorScope.textColor + style: softwareRendering ? Text.Outline : Text.Normal + styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" //no outline, doesn't matter + font.pointSize: 34 + Layout.alignment: Qt.AlignHCenter + } + Label { + text: Qt.formatDate(timeSource.data["Local"]["DateTime"], Qt.DefaultLocaleLongDate) + color: ColorScope.textColor + style: softwareRendering ? Text.Outline : Text.Normal + styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" //no outline, doesn't matter + font.pointSize: 17 + Layout.alignment: Qt.AlignHCenter + } + DataSource { + id: timeSource + engine: "time" + connectedSources: ["Local"] + interval: 1000 + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/KeyboardLayoutButton.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/components/KeyboardLayoutButton.qml new file mode 100644 index 00000000..2af23258 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/components/KeyboardLayoutButton.qml @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2014 by Daniel Vrátil * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.1 as QQC + +import org.kde.plasma.components 2.0 as PlasmaComponents + +import org.kde.plasma.workspace.keyboardlayout 1.0 + +PlasmaComponents.ToolButton { + + property int fontSize: config.fontSize + + id: kbLayoutButton + + iconName: "input-keyboard" + implicitWidth: minimumWidth + text: layout.layoutName() + font.pointSize: Math.max(fontSize,theme.defaultFont.pointSize) + + Accessible.name: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to change keyboard layout", "Switch layout") + + visible: layout.shouldBeVisible() + + onClicked: layout.nextLayout() + + KeyboardLayout { + id: layout + function nextLayout() { + layout.layout = (layout.layout + 1) % layout.layoutsList.length; + } + + function shouldBeVisible() { + return layout.layoutsList.length > 1; + } + + function layoutName() { + return (layout.isInitialized() && layout.layoutsList[layout.layout].displayName) || ''; + } + + function isInitialized() { + return layout.layoutsList.length > 0; + } + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/SessionManagementScreen.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/components/SessionManagementScreen.qml new file mode 100644 index 00000000..5f882604 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/components/SessionManagementScreen.qml @@ -0,0 +1,121 @@ +/* + * Copyright 2016 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.2 + +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.1 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item { + id: root + + /* + * Any message to be displayed to the user, visible above the text fields + */ + property alias notificationMessage: notificationsLabel.text + + /* + * A list of Items (typically ActionButtons) to be shown in a Row beneath the prompts + */ + property alias actionItems: actionItemsLayout.children + + /* + * A model with a list of users to show in the view + * The following roles should exist: + * - name + * - iconSource + * + * The following are also handled: + * - vtNumber + * - displayNumber + * - session + * - isTty + */ + property alias userListModel: userListView.model + + /* + * Self explanatory + */ + property alias userListCurrentIndex: userListView.currentIndex + property var userListCurrentModelData: userListView.currentItem === null ? [] : userListView.currentItem.m + property bool showUserList: true + + property alias userList: userListView + + property int fontSize: config.fontSize + + default property alias _children: innerLayout.children + + UserList { + id: userListView + visible: showUserList && y > 0 + anchors { + bottom: parent.verticalCenter + left: parent.left + right: parent.right + } + } + + //goal is to show the prompts, in ~16 grid units high, then the action buttons + //but collapse the space between the prompts and actions if there's no room + //ui is constrained to 16 grid units wide, or the screen + ColumnLayout { + id: prompts + anchors.top: parent.verticalCenter + anchors.topMargin: units.gridUnit * 0.5 + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + PlasmaComponents.Label { + id: notificationsLabel + font.pointSize: Math.max(fontSize + 1,theme.defaultFont.pointSize + 1) + Layout.maximumWidth: units.gridUnit * 16 + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + font.italic: true + } + ColumnLayout { + Layout.minimumHeight: implicitHeight + Layout.maximumHeight: units.gridUnit * 10 + Layout.maximumWidth: units.gridUnit * 16 + Layout.alignment: Qt.AlignHCenter + ColumnLayout { + id: innerLayout + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + } + Item { + Layout.fillHeight: true + } + } + Row { //deliberately not rowlayout as I'm not trying to resize child items + id: actionItemsLayout + spacing: units.largeSpacing / 2 + Layout.alignment: Qt.AlignHCenter + } + Item { + Layout.fillHeight: true + } + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/UserDelegate.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/components/UserDelegate.qml new file mode 100644 index 00000000..e30e4a35 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/components/UserDelegate.qml @@ -0,0 +1,192 @@ +/* + * Copyright 2014 David Edmundson + * Copyright 2014 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.8 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item { + id: wrapper + + // If we're using software rendering, draw outlines instead of shadows + // See https://bugs.kde.org/show_bug.cgi?id=398317 + readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software + + property bool isCurrent: true + + readonly property var m: model + property string name + property string userName + property string avatarPath + property string iconSource + property bool constrainText: true + property alias nameFontSize: usernameDelegate.font.pointSize + property int fontSize: config.fontSize + signal clicked() + + property real faceSize: units.gridUnit * 7 + + opacity: isCurrent ? 1.0 : 0.5 + + Behavior on opacity { + OpacityAnimator { + duration: units.longDuration + } + } + + // Draw a translucent background circle under the user picture + Rectangle { + anchors.centerIn: imageSource + width: imageSource.width + 2 // Subtract to prevent fringing + height: width + radius: width / 2 + gradient: Gradient { + GradientStop { position: 0.0; color: "#A67CF3" } + GradientStop { position: 1.0; color: "#9B79CC" } + } + } + + + Item { + id: imageSource + anchors { + bottom: usernameDelegate.top + bottomMargin: units.largeSpacing + horizontalCenter: parent.horizontalCenter + } + Behavior on width { + PropertyAnimation { + from: faceSize + duration: units.longDuration; + } + } + width: isCurrent ? faceSize : faceSize - units.largeSpacing + height: width + + //Image takes priority, taking a full path to a file, if that doesn't exist we show an icon + Image { + id: face + source: wrapper.avatarPath + sourceSize: Qt.size(faceSize, faceSize) + fillMode: Image.PreserveAspectCrop + anchors.fill: parent + } + + PlasmaCore.IconItem { + id: faceIcon + source: iconSource + visible: (face.status == Image.Error || face.status == Image.Null) + anchors.fill: parent + anchors.margins: units.gridUnit * 0.5 // because mockup says so... + colorGroup: PlasmaCore.ColorScope.colorGroup + } + } + + ShaderEffect { + anchors { + bottom: usernameDelegate.top + bottomMargin: units.largeSpacing + horizontalCenter: parent.horizontalCenter + } + + width: imageSource.width + height: imageSource.height + + supportsAtlasTextures: true + + property var source: ShaderEffectSource { + sourceItem: imageSource + // software rendering is just a fallback so we can accept not having a rounded avatar here + hideSource: wrapper.GraphicsInfo.api !== GraphicsInfo.Software + live: true // otherwise the user in focus will show a blurred avatar + } + + property var colorBorder: "#00000000" + + //draw a circle with an antialiased border + //innerRadius = size of the inner circle with contents + //outerRadius = size of the border + //blend = area to blend between two colours + //all sizes are normalised so 0.5 == half the width of the texture + + //if copying into another project don't forget to connect themeChanged to update() + //but in SDDM that's a bit pointless + fragmentShader: " + varying highp vec2 qt_TexCoord0; + uniform highp float qt_Opacity; + uniform lowp sampler2D source; + + uniform lowp vec4 colorBorder; + highp float blend = 0.01; + highp float innerRadius = 0.47; + highp float outerRadius = 0.49; + lowp vec4 colorEmpty = vec4(0.0, 0.0, 0.0, 0.0); + + void main() { + lowp vec4 colorSource = texture2D(source, qt_TexCoord0.st); + + highp vec2 m = qt_TexCoord0 - vec2(0.5, 0.5); + highp float dist = sqrt(m.x * m.x + m.y * m.y); + + if (dist < innerRadius) + gl_FragColor = colorSource; + else if (dist < innerRadius + blend) + gl_FragColor = mix(colorSource, colorBorder, ((dist - innerRadius) / blend)); + else if (dist < outerRadius) + gl_FragColor = colorBorder; + else if (dist < outerRadius + blend) + gl_FragColor = mix(colorBorder, colorEmpty, ((dist - outerRadius) / blend)); + else + gl_FragColor = colorEmpty ; + + gl_FragColor = gl_FragColor * qt_Opacity; + } + " + } + + PlasmaComponents.Label { + id: usernameDelegate + font.pointSize: Math.max(fontSize + 2,theme.defaultFont.pointSize + 2) + anchors { + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + height: implicitHeight // work around stupid bug in Plasma Components that sets the height + width: constrainText ? parent.width : implicitWidth + text: wrapper.name + style: softwareRendering ? Text.Outline : Text.Normal + styleColor: softwareRendering ? PlasmaCore.ColorScope.backgroundColor : "transparent" //no outline, doesn't matter + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + //make an indication that this has active focus, this only happens when reached with keyboard navigation + font.underline: wrapper.activeFocus + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + + onClicked: wrapper.clicked(); + } + + Accessible.name: name + Accessible.role: Accessible.Button + function accessiblePressAction() { wrapper.clicked() } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/UserList.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/components/UserList.qml new file mode 100644 index 00000000..a2d85088 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/components/UserList.qml @@ -0,0 +1,93 @@ +/* + * Copyright 2014 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.2 + +ListView { + id: view + readonly property string selectedUser: currentItem ? currentItem.userName : "" + readonly property int userItemWidth: units.gridUnit * 8 + readonly property int userItemHeight: units.gridUnit * 8 + + implicitHeight: userItemHeight + + activeFocusOnTab : true + + /* + * Signals that a user was explicitly selected + */ + signal userSelected; + + orientation: ListView.Horizontal + highlightRangeMode: ListView.StrictlyEnforceRange + + //centre align selected item (which implicitly centre aligns the rest + preferredHighlightBegin: width/2 - userItemWidth/2 + preferredHighlightEnd: preferredHighlightBegin + + delegate: UserDelegate { + avatarPath: model.icon || "" + iconSource: model.iconName || "user-identity" + + name: { + var displayName = model.realName || model.name + + if (model.vtNumber === undefined || model.vtNumber < 0) { + return displayName + } + + if (!model.session) { + return i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Nobody logged in on that session", "Unused") + } + + + var location = "" + if (model.isTty) { + location = i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "User logged in on console number", "TTY %1", model.vtNumber) + } else if (model.displayNumber) { + location = i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "User logged in on console (X display number)", "on TTY %1 (Display %2)", model.vtNumber, model.displayNumber) + } + + if (location) { + return i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Username (location)", "%1 (%2)", displayName, location) + } + + return displayName + } + + userName: model.name + + width: userItemWidth + height: userItemHeight + + //if we only have one delegate, we don't need to clip the text as it won't be overlapping with anything + constrainText: ListView.view.count > 1 + + isCurrent: ListView.isCurrentItem + + onClicked: { + ListView.view.currentIndex = index; + ListView.view.userSelected(); + } + } + + Keys.onEscapePressed: view.userSelected() + Keys.onEnterPressed: view.userSelected() + Keys.onReturnPressed: view.userSelected() +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/VirtualKeyboard.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/components/VirtualKeyboard.qml new file mode 100644 index 00000000..7848b753 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/components/VirtualKeyboard.qml @@ -0,0 +1,28 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2017 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +import QtQuick 2.5 +import QtQuick.VirtualKeyboard 2.1 + +InputPanel { + id: inputPanel + property bool activated: false + active: activated && Qt.inputMethod.visible + visible: active + width: parent.width +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/WallpaperFader.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/components/WallpaperFader.qml new file mode 100644 index 00000000..c8476cd6 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/components/WallpaperFader.qml @@ -0,0 +1,178 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2014 Aleix Pol Gonzalez + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.1 +import QtGraphicalEffects 1.0 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +import org.kde.plasma.private.sessions 2.0 +import "../components" + +Item { + id: wallpaperFader + property Item clock + property Item mainStack + property Item footer + property alias source: wallpaperBlur.source + state: lockScreenRoot.uiVisible ? "on" : "off" + property real factor: 0 + readonly property bool lightBackground: Math.max(PlasmaCore.ColorScope.backgroundColor.r, PlasmaCore.ColorScope.backgroundColor.g, PlasmaCore.ColorScope.backgroundColor.b) > 0.5 + + property bool alwaysShowClock: typeof config === "undefined" || config.alwaysShowClock === true + + Behavior on factor { + NumberAnimation { + target: wallpaperFader + property: "factor" + duration: 1000 + easing.type: Easing.InOutQuad + } + } + FastBlur { + id: wallpaperBlur + anchors.fill: parent + radius: 50 * wallpaperFader.factor + } + ShaderEffect { + id: wallpaperShader + anchors.fill: parent + supportsAtlasTextures: true + property var source: ShaderEffectSource { + sourceItem: wallpaperBlur + live: true + hideSource: true + textureMirroring: ShaderEffectSource.NoMirroring + } + + readonly property real contrast: 0.65 * wallpaperFader.factor + (1 - wallpaperFader.factor) + readonly property real saturation: 1.6 * wallpaperFader.factor + (1 - wallpaperFader.factor) + readonly property real intensity: (wallpaperFader.lightBackground ? 1.7 : 0.6) * wallpaperFader.factor + (1 - wallpaperFader.factor) + + readonly property real transl: (1.0 - contrast) / 2.0; + readonly property real rval: (1.0 - saturation) * 0.2126; + readonly property real gval: (1.0 - saturation) * 0.7152; + readonly property real bval: (1.0 - saturation) * 0.0722; + + property var colorMatrix: Qt.matrix4x4( + contrast, 0, 0, 0.0, + 0, contrast, 0, 0.0, + 0, 0, contrast, 0.0, + transl, transl, transl, 1.0).times(Qt.matrix4x4( + rval + saturation, rval, rval, 0.0, + gval, gval + saturation, gval, 0.0, + bval, bval, bval + saturation, 0.0, + 0, 0, 0, 1.0)).times(Qt.matrix4x4( + intensity, 0, 0, 0, + 0, intensity, 0, 0, + 0, 0, intensity, 0, + 0, 0, 0, 1 + )); + + + fragmentShader: " + uniform mediump mat4 colorMatrix; + uniform mediump sampler2D source; + varying mediump vec2 qt_TexCoord0; + uniform lowp float qt_Opacity; + + void main(void) + { + mediump vec4 tex = texture2D(source, qt_TexCoord0); + gl_FragColor = tex * colorMatrix * qt_Opacity; + }" + } + + states: [ + State { + name: "on" + PropertyChanges { + target: mainStack + opacity: 1 + } + PropertyChanges { + target: footer + opacity: 1 + } + PropertyChanges { + target: wallpaperFader + factor: 1 + } + PropertyChanges { + target: clock.shadow + opacity: 0 + } + PropertyChanges { + target: clock + opacity: 1 + anchors.horizontalCenter: formBg.horizontalCenter + // y: parent.height - height - 10 + } + }, + State { + name: "off" + PropertyChanges { + target: mainStack + opacity: 0 + } + PropertyChanges { + target: footer + opacity: 0 + } + PropertyChanges { + target: wallpaperFader + factor: 0 + } + PropertyChanges { + target: clock.shadow + opacity: wallpaperFader.alwaysShowClock ? 1 : 0 + } + PropertyChanges { + target: clock + opacity: wallpaperFader.alwaysShowClock ? 1 : 0 + } + } + ] + transitions: [ + Transition { + from: "off" + to: "on" + //Note: can't use animators as they don't play well with parallelanimations + NumberAnimation { + targets: [mainStack, footer, clock] + property: "opacity" + duration: units.longDuration + easing.type: Easing.InOutQuad + } + }, + Transition { + from: "on" + to: "off" + NumberAnimation { + targets: [mainStack, footer, clock] + property: "opacity" + duration: 500 + easing.type: Easing.InOutQuad + } + } + ] +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/README.txt b/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/README.txt new file mode 100644 index 00000000..1885a360 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/README.txt @@ -0,0 +1 @@ +After editing SVG files be sure to run currentColorFillFix.sh from plasma-framework \ No newline at end of file diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/logout_primary.svgz b/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/logout_primary.svgz new file mode 100644 index 00000000..6a9423fa Binary files /dev/null and b/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/logout_primary.svgz differ diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/restart_primary.svgz b/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/restart_primary.svgz new file mode 100644 index 00000000..e2312bd8 Binary files /dev/null and b/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/restart_primary.svgz differ diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/shutdown_primary.svgz b/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/shutdown_primary.svgz new file mode 100644 index 00000000..1c60152f Binary files /dev/null and b/kde/plasma/look-and-feel/Dracula-purple/contents/components/artwork/shutdown_primary.svgz differ diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/defaults b/kde/plasma/look-and-feel/Dracula-purple/contents/defaults new file mode 100644 index 00000000..6888aac1 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/defaults @@ -0,0 +1,20 @@ +[kdeglobals][KDE] +widgetStyle=kvantum + +[kdeglobals][General] +ColorScheme=Dracula-purple + +[kdeglobals][Icons] +Theme=candy-icons + +[kcminputrc][Mouse] +cursorTheme=Dracula-cursors + +[plasmarc][Theme] +name=Dracula + +[kwinrc][org.kde.kdecoration2] +library=org.kde.kwin.aurorae +theme=__aurorae__svg__Dracula + + diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/LockOsd.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/LockOsd.qml new file mode 100644 index 00000000..b28363b2 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/LockOsd.qml @@ -0,0 +1,83 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2014 Aleix Pol Gonzalez + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import "../osd" + +PlasmaCore.FrameSvgItem { + id: osd + + // OSD Timeout in msecs - how long it will stay on the screen + property int timeout: 1800 + // This is either a text or a number, if showingProgress is set to true, + // the number will be used as a value for the progress bar + property var osdValue + // Icon name to display + property string icon + // Set to true if the value is meant for progress bar, + // false for displaying the value as normal text + property bool showingProgress: false + + objectName: "onScreenDisplay" + visible: false + width: osdItem.width + margins.left + margins.right + height: osdItem.height + margins.top + margins.bottom + imagePath: "widgets/background" + + function show() { + osd.visible = true; + hideAnimation.restart(); + } + + // avoid leaking ColorScope of lock screen theme into the OSD "popup" + PlasmaCore.ColorScope { + width: osdItem.width + height: osdItem.height + anchors.centerIn: parent + colorGroup: PlasmaCore.Theme.NormalColorGroup + + OsdItem { + id: osdItem + rootItem: osd + } + } + + SequentialAnimation { + id: hideAnimation + // prevent press and hold from flickering + PauseAnimation { duration: 100 } + NumberAnimation { + target: osd + property: "opacity" + from: 1 + to: 0 + duration: osd.timeout + easing.type: Easing.InQuad + } + ScriptAction { + script: { + osd.visible = false; + osd.opacity = 1; + osd.icon = ""; + osd.osdValue = 0; + } + } + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/LockScreen.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/LockScreen.qml new file mode 100644 index 00000000..c0bc939e --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/LockScreen.qml @@ -0,0 +1,65 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2014 Aleix Pol Gonzalez + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.5 +import QtQuick.Controls 1.1 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.private.sessions 2.0 +import "../components" + +Item { + id: root + property bool viewVisible: false + property bool debug: false + property string notification + property int interfaceVersion: org_kde_plasma_screenlocker_greeter_interfaceVersion ? org_kde_plasma_screenlocker_greeter_interfaceVersion : 0 + signal clearPassword() + + LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft + LayoutMirroring.childrenInherit: true + + Loader { + id: mainLoader + anchors.fill: parent + opacity: 0 + onItemChanged: opacity = 1 + + focus: true + + Behavior on opacity { + OpacityAnimator { + duration: units.longDuration + easing.type: Easing.InCubic + } + } + } + Connections { + id:loaderConnection + target: org_kde_plasma_screenlocker_greeter_view + onFrameSwapped: { + mainLoader.source = "LockScreenUi.qml"; + loaderConnection.target = null; + } + } + Component.onCompleted: { + if (root.interfaceVersion < 2) { + mainLoader.source = "LockScreenUi.qml"; + } + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/LockScreenUi.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/LockScreenUi.qml new file mode 100644 index 00000000..927de343 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/LockScreenUi.qml @@ -0,0 +1,543 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2014 Aleix Pol Gonzalez + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.8 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.1 +import QtGraphicalEffects 1.0 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtras + + +import org.kde.plasma.private.sessions 2.0 +import "../components" + +PlasmaCore.ColorScope { + + id: lockScreenUi + // If we're using software rendering, draw outlines instead of shadows + // See https://bugs.kde.org/show_bug.cgi?id=398317 + readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software + readonly property bool lightBackground: Math.max(PlasmaCore.ColorScope.backgroundColor.r, PlasmaCore.ColorScope.backgroundColor.g, PlasmaCore.ColorScope.backgroundColor.b) > 0.5 + + colorGroup: PlasmaCore.Theme.ComplementaryColorGroup + + Connections { + target: authenticator + onFailed: { + root.notification = i18nd("plasma_lookandfeel_org.kde.lookandfeel","Unlocking failed"); + } + onGraceLockedChanged: { + if (!authenticator.graceLocked) { + root.notification = ""; + root.clearPassword(); + } + } + onMessage: { + root.notification = msg; + } + onError: { + root.notification = err; + } + } + + SessionManagement { + id: sessionManagement + } + + Connections { + target: sessionManagement + onAboutToSuspend: { + mainBlock.mainPasswordBox.text = ""; + } + } + + SessionsModel { + id: sessionsModel + showNewSessionEntry: false + } + + PlasmaCore.DataSource { + id: keystateSource + engine: "keystate" + connectedSources: "Caps Lock" + } + + Loader { + id: changeSessionComponent + active: false + source: "ChangeSession.qml" + visible: false + } + + MouseArea { + id: lockScreenRoot + + property bool uiVisible: false + property bool blockUI: mainStack.depth > 1 || mainBlock.mainPasswordBox.text.length > 0 || inputPanel.keyboardActive + + x: parent.x + y: parent.y + width: parent.width + height: parent.height + hoverEnabled: true + drag.filterChildren: true + onPressed: uiVisible = true; + onPositionChanged: uiVisible = true; + onUiVisibleChanged: { + if (blockUI) { + fadeoutTimer.running = false; + } else if (uiVisible) { + fadeoutTimer.restart(); + } + } + onBlockUIChanged: { + if (blockUI) { + fadeoutTimer.running = false; + uiVisible = true; + } else { + fadeoutTimer.restart(); + } + } + Keys.onEscapePressed: { + uiVisible = !uiVisible; + if (inputPanel.keyboardActive) { + inputPanel.showHide(); + } + if (!uiVisible) { + mainBlock.mainPasswordBox.text = ""; + } + } + Keys.onPressed: { + uiVisible = true; + event.accepted = false; + } + Timer { + id: fadeoutTimer + interval: 10000 + onTriggered: { + if (!lockScreenRoot.blockUI) { + lockScreenRoot.uiVisible = false; + } + } + } + + Component.onCompleted: PropertyAnimation { id: launchAnimation; target: lockScreenRoot; property: "opacity"; from: 0; to: 1; duration: 1000 } + + states: [ + State { + name: "onOtherSession" + // for slide out animation + PropertyChanges { target: lockScreenRoot; y: lockScreenRoot.height } + // we also change the opacity just to be sure it's not visible even on unexpected screen dimension changes with possible race conditions + PropertyChanges { target: lockScreenRoot; opacity: 0 } + } + ] + + transitions: + Transition { + // we only animate switchting to another session, because kscreenlocker doesn't get notified when + // coming from another session back and so we wouldn't know when to trigger the animation exactly + from: "" + to: "onOtherSession" + + PropertyAnimation { id: stateChangeAnimation; properties: "y"; duration: 300; easing.type: Easing.InQuad} + PropertyAnimation { properties: "opacity"; duration: 300} + + onRunningChanged: { + // after the animation has finished switch session: since we only animate the transition TO state "onOtherSession" + // and not the other way around, we don't have to check the state we transitioned into + if (/* lockScreenRoot.state == "onOtherSession" && */ !running) { + mainStack.currentItem.switchSession() + } + } + } + + WallpaperFader { + anchors.fill: parent + state: lockScreenRoot.uiVisible ? "on" : "off" + source: wallpaper + mainStack: mainStack + footer: footer + clock: clock + z: -3 + } + + DropShadow { + id: clockShadow + anchors.fill: clock + source: clock + visible: !softwareRendering + horizontalOffset: 1 + verticalOffset: 1 + radius: 6 + samples: 14 + spread: 0.3 + color: lockScreenUi.lightBackground ? PlasmaCore.ColorScope.backgroundColor : "black" // black matches Breeze window decoration and desktopcontainment + Behavior on opacity { + OpacityAnimator { + duration: 1000 + easing.type: Easing.InOutQuad + } + } + } + + Clock { + id: clock + property Item shadow: clockShadow + anchors.horizontalCenter: parent.horizontalCenter + y: (mainBlock.userList.y + mainStack.y)/2 - height/2 + visible: y > 0 + Layout.alignment: Qt.AlignBaseline + } + + ListModel { + id: users + + Component.onCompleted: { + users.append({name: kscreenlocker_userName, + realName: kscreenlocker_userName, + icon: kscreenlocker_userImage, + + }) + } + } + + StackView { + id: mainStack + anchors.centerIn: parent + + height: lockScreenRoot.height + units.gridUnit * 3 + width: parent.width / 3 + focus: true //StackView is an implicit focus scope, so we need to give this focus so the item inside will have it + + initialItem: MainBlock { + id: mainBlock + lockScreenUiVisible: lockScreenRoot.uiVisible + + showUserList: userList.y + mainStack.y > 0 + + Stack.onStatusChanged: { + // prepare for presenting again to the user + if (Stack.status == Stack.Activating) { + mainPasswordBox.remove(0, mainPasswordBox.length) + mainPasswordBox.focus = true + } + } + userListModel: users + notificationMessage: { + var text = "" + if (keystateSource.data["Caps Lock"]["Locked"]) { + text += i18nd("plasma_lookandfeel_org.kde.lookandfeel","Caps Lock is on") + if (root.notification) { + text += " • " + } + } + text += root.notification + return text + } + + onLoginRequest: { + root.notification = "" + authenticator.tryUnlock(password) + } + + actionItems: [ + ActionButton { + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Switch User") + iconSource: "system-switch-user" + onClicked: { + // If there are no existing sessions to switch to, create a new one instead + if (((sessionsModel.showNewSessionEntry && sessionsModel.count === 1) || + (!sessionsModel.showNewSessionEntry && sessionsModel.count === 0)) && + sessionsModel.canSwitchUser) { + mainStack.pop({immediate:true}) + sessionsModel.startNewSession(true /* lock the screen too */) + lockScreenRoot.state = '' + } else { + mainStack.push(switchSessionPage) + } + } + visible: sessionsModel.canStartNewSession && sessionsModel.canSwitchUser + //Button gets cut off on smaller displays without this. + anchors{ + verticalCenter: parent.top + } + } + ] + + Loader { + Layout.fillWidth: true + Layout.preferredHeight: item ? item.implicitHeight : 0 + active: config.showMediaControls + source: "MediaControls.qml" + } + } + + Component.onCompleted: { + if (defaultToSwitchUser) { //context property + // If we are in the only session, then going to the session switcher is + // a pointless extra step; instead create a new session immediately + if (((sessionsModel.showNewSessionEntry && sessionsModel.count === 1) || + (!sessionsModel.showNewSessionEntry && sessionsModel.count === 0)) && + sessionsModel.canStartNewSession) { + sessionsModel.startNewSession(true /* lock the screen too */) + } else { + mainStack.push({ + item: switchSessionPage, + immediate: true}); + } + } + } + } + + Loader { + id: inputPanel + state: "hidden" + readonly property bool keyboardActive: item ? item.active : false + anchors { + left: parent.left + right: parent.right + } + function showHide() { + state = state == "hidden" ? "visible" : "hidden"; + } + Component.onCompleted: inputPanel.source = "../components/VirtualKeyboard.qml" + + onKeyboardActiveChanged: { + if (keyboardActive) { + state = "visible"; + } else { + state = "hidden"; + } + } + + states: [ + State { + name: "visible" + PropertyChanges { + target: mainStack + y: Math.min(0, lockScreenRoot.height - inputPanel.height - mainBlock.visibleBoundary) + } + PropertyChanges { + target: inputPanel + y: lockScreenRoot.height - inputPanel.height + opacity: 1 + } + }, + State { + name: "hidden" + PropertyChanges { + target: mainStack + y: 0 + } + PropertyChanges { + target: inputPanel + y: lockScreenRoot.height - lockScreenRoot.height/4 + opacity: 0 + } + } + ] + transitions: [ + Transition { + from: "hidden" + to: "visible" + SequentialAnimation { + ScriptAction { + script: { + inputPanel.item.activated = true; + Qt.inputMethod.show(); + } + } + ParallelAnimation { + NumberAnimation { + target: mainStack + property: "y" + duration: units.longDuration + easing.type: Easing.InOutQuad + } + NumberAnimation { + target: inputPanel + property: "y" + duration: units.longDuration + easing.type: Easing.OutQuad + } + OpacityAnimator { + target: inputPanel + duration: units.longDuration + easing.type: Easing.OutQuad + } + } + } + }, + Transition { + from: "visible" + to: "hidden" + SequentialAnimation { + ParallelAnimation { + NumberAnimation { + target: mainStack + property: "y" + duration: units.longDuration + easing.type: Easing.InOutQuad + } + NumberAnimation { + target: inputPanel + property: "y" + duration: units.longDuration + easing.type: Easing.InQuad + } + OpacityAnimator { + target: inputPanel + duration: units.longDuration + easing.type: Easing.InQuad + } + } + ScriptAction { + script: { + Qt.inputMethod.hide(); + } + } + } + } + ] + } + + Component { + id: switchSessionPage + SessionManagementScreen { + property var switchSession: finalSwitchSession + + Stack.onStatusChanged: { + if (Stack.status == Stack.Activating) { + focus = true + } + } + + userListModel: sessionsModel + + // initiating animation of lockscreen for session switch + function initSwitchSession() { + lockScreenRoot.state = 'onOtherSession' + } + + // initiating session switch and preparing lockscreen for possible return of user + function finalSwitchSession() { + mainStack.pop({immediate:true}) + sessionsModel.switchUser(userListCurrentModelData.vtNumber) + lockScreenRoot.state = '' + } + + Keys.onLeftPressed: userList.decrementCurrentIndex() + Keys.onRightPressed: userList.incrementCurrentIndex() + Keys.onEnterPressed: initSwitchSession() + Keys.onReturnPressed: initSwitchSession() + Keys.onEscapePressed: mainStack.pop() + + ColumnLayout { + Layout.fillWidth: true + spacing: units.largeSpacing + + PlasmaComponents.Button { + Layout.fillWidth: true + font.pointSize: theme.defaultFont.pointSize + 1 + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Switch to This Session") + onClicked: initSwitchSession() + visible: sessionsModel.count > 0 + } + + PlasmaComponents.Button { + Layout.fillWidth: true + font.pointSize: theme.defaultFont.pointSize + 1 + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Start New Session") + onClicked: { + mainStack.pop({immediate:true}) + sessionsModel.startNewSession(true /* lock the screen too */) + lockScreenRoot.state = '' + } + } + } + + + actionItems: [ + ActionButton { + iconSource: "go-previous" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel","Back") + onClicked: mainStack.pop() + //Button gets cut off on smaller displays without this. + anchors{ + verticalCenter: parent.top + } + } + ] + } + } + + + Loader { + active: root.viewVisible + source: "LockOsd.qml" + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + bottomMargin: units.largeSpacing + } + } + + RowLayout { + id: footer + z: -2 + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + margins: units.smallSpacing + } + + + + PlasmaComponents.ToolButton { + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to show/hide virtual keyboard", "Virtual Keyboard") + iconName: inputPanel.keyboardActive ? "input-keyboard-virtual-on" : "input-keyboard-virtual-off" + onClicked: inputPanel.showHide() + + visible: inputPanel.status == Loader.Ready + } + + KeyboardLayoutButton { + } + + Item { + Layout.fillWidth: true + } + + Battery {} + } + } + + Component.onCompleted: { + // version support checks + if (root.interfaceVersion < 1) { + // ksmserver of 5.4, with greeter of 5.5 + root.viewVisible = true; + } + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/MainBlock.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/MainBlock.qml new file mode 100644 index 00000000..bd2d68b8 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/MainBlock.qml @@ -0,0 +1,141 @@ +/* + * Copyright 2016 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.8 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Styles 1.4 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +import "../components" + +SessionManagementScreen { + + property Item mainPasswordBox: passwordBox + property bool lockScreenUiVisible: false + + //the y position that should be ensured visible when the on screen keyboard is visible + property int visibleBoundary: mapFromItem(loginButton, 0, 0).y + onHeightChanged: visibleBoundary = mapFromItem(loginButton, 0, 0).y + loginButton.height + units.smallSpacing + /* + * Login has been requested with the following username and password + * If username field is visible, it will be taken from that, otherwise from the "name" property of the currentIndex + */ + signal loginRequest(string password) + + function startLogin() { + var password = passwordBox.text + + //this is partly because it looks nicer + //but more importantly it works round a Qt bug that can trigger if the app is closed with a TextField focused + //See https://bugreports.qt.io/browse/QTBUG-55460 + loginButton.forceActiveFocus(); + loginRequest(password); + } + + RowLayout { + Layout.fillWidth: true + + TextField { + id: passwordBox + font.pointSize: theme.defaultFont.pointSize + 1 + Layout.fillWidth: true + placeholderText: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Password") + focus: true + echoMode: TextInput.Password + inputMethodHints: Qt.ImhHiddenText | Qt.ImhSensitiveData | Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText + enabled: !authenticator.graceLocked + + placeholderTextColor: "#C3C7D1" + palette.text: "#C3C7D1" + + background: Rectangle { + color: "#272834" + opacity: 0.9 + border.width: 1 + border.color: "#9283BB" + radius: parent.width / 2 + height: 30 + anchors.fill: parent + anchors.centerIn: parent + } + + + onAccepted: { + if (lockScreenUiVisible) { + startLogin(); + } + } + + //if empty and left or right is pressed change selection in user switch + //this cannot be in keys.onLeftPressed as then it doesn't reach the password box + Keys.onPressed: { + if (event.key == Qt.Key_Left && !text) { + userList.decrementCurrentIndex(); + event.accepted = true + } + if (event.key == Qt.Key_Right && !text) { + userList.incrementCurrentIndex(); + event.accepted = true + } + } + + Connections { + target: root + onClearPassword: { + passwordBox.forceActiveFocus() + passwordBox.selectAll() + } + } + } + + Button { + id: loginButton + Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Unlock") + implicitHeight: passwordBox.height - units.smallSpacing * 0.5 // otherwise it comes out taller than the password field + text: ">" + Layout.leftMargin: 30 + + contentItem: Text { + text: loginButton.text + font: loginButton.font + opacity: enabled ? 1.0 : 0.3 + color: "#ffffff" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + background: Rectangle { + id: buttonBackground + width: 30 + height: 40 + radius: width / 2 + rotation: -90 + anchors.centerIn: parent + color: "#9B79CC" + + } + + onClicked: startLogin() + } + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/MediaControls.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/MediaControls.qml new file mode 100644 index 00000000..d981153f --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/MediaControls.qml @@ -0,0 +1,162 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2016 Kai Uwe Broulik + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.5 +import QtQuick.Layouts 1.1 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtras + +Item { + visible: mpris2Source.hasPlayer + implicitHeight: controlsRow.height + controlsRow.y + + RowLayout { + id: controlsRow + anchors.bottom: parent.bottom + y: units.smallSpacing // some distance to the password field + width: parent.width + height: units.gridUnit * 3 + spacing: 0 + + enabled: mpris2Source.canControl + + PlasmaCore.DataSource { + id: mpris2Source + + readonly property string source: "@multiplex" + readonly property var playerData: data[source] + + readonly property bool hasPlayer: sources.length > 1 && !!playerData + readonly property string identity: hasPlayer ? playerData.Identity : "" + readonly property bool playing: hasPlayer && playerData.PlaybackStatus === "Playing" + readonly property bool canControl: hasPlayer && playerData.CanControl + readonly property bool canGoBack: hasPlayer && playerData.CanGoPrevious + readonly property bool canGoNext: hasPlayer && playerData.CanGoNext + + readonly property var currentMetadata: hasPlayer ? playerData.Metadata : ({}) + + readonly property string track: { + var xesamTitle = currentMetadata["xesam:title"] + if (xesamTitle) { + return xesamTitle + } + // if no track title is given, print out the file name + var xesamUrl = currentMetadata["xesam:url"] ? currentMetadata["xesam:url"].toString() : "" + if (!xesamUrl) { + return "" + } + var lastSlashPos = xesamUrl.lastIndexOf('/') + if (lastSlashPos < 0) { + return "" + } + var lastUrlPart = xesamUrl.substring(lastSlashPos + 1) + return decodeURIComponent(lastUrlPart) + } + readonly property string artist: currentMetadata["xesam:artist"] || "" + readonly property string albumArt: currentMetadata["mpris:artUrl"] || "" + + engine: "mpris2" + connectedSources: [source] + + function startOperation(op) { + var service = serviceForSource(source) + var operation = service.operationDescription(op) + return service.startOperationCall(operation) + } + + function goPrevious() { + startOperation("Previous"); + } + function goNext() { + startOperation("Next"); + } + function playPause(source) { + startOperation("PlayPause"); + } + } + + Image { + id: albumArt + Layout.preferredWidth: height + Layout.fillHeight: true + asynchronous: true + fillMode: Image.PreserveAspectFit + source: mpris2Source.albumArt + sourceSize.height: height + visible: status === Image.Loading || status === Image.Ready + } + + Item { // spacer + width: units.smallSpacing + height: 1 + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + + PlasmaComponents.Label { + Layout.fillWidth: true + wrapMode: Text.NoWrap + elide: Text.ElideRight + text: mpris2Source.track || i18nd("plasma_lookandfeel_org.kde.lookandfeel", "No media playing") + textFormat: Text.PlainText + font.pointSize: theme.defaultFont.pointSize + 1 + maximumLineCount: 1 + } + + PlasmaExtras.DescriptiveLabel { + Layout.fillWidth: true + wrapMode: Text.NoWrap + elide: Text.ElideRight + // if no artist is given, show player name instead + text: mpris2Source.artist || mpris2Source.identity || "" + textFormat: Text.PlainText + font.pointSize: theme.smallestFont.pointSize + 1 + maximumLineCount: 1 + } + } + + PlasmaComponents.ToolButton { + enabled: mpris2Source.canGoBack + iconName: LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward" + onClicked: mpris2Source.goPrevious() + visible: mpris2Source.canGoBack || mpris2Source.canGoNext + Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Previous track") + } + + PlasmaComponents.ToolButton { + Layout.fillHeight: true + Layout.preferredWidth: height // make this button bigger + iconName: mpris2Source.playing ? "media-playback-pause" : "media-playback-start" + onClicked: mpris2Source.playPause() + Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Play or Pause media") + } + + PlasmaComponents.ToolButton { + enabled: mpris2Source.canGoNext + iconName: LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward" + onClicked: mpris2Source.goNext() + visible: mpris2Source.canGoBack || mpris2Source.canGoNext + Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Next track") + } + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/config.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/config.qml new file mode 100644 index 00000000..921a0385 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/config.qml @@ -0,0 +1,44 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.5 as QQC2 +import QtQuick.Layouts 1.1 + +ColumnLayout { + property alias cfg_alwaysShowClock: alwaysClock.checked + property alias cfg_showMediaControls: showMediaControls.checked + + spacing: 0 + + RowLayout { + spacing: units.largeSpacing / 2 + + QQC2.Label { + Layout.minimumWidth: formAlignment - units.largeSpacing //to match wallpaper config... + horizontalAlignment: Text.AlignRight + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Clock:") + } + QQC2.CheckBox { + id: alwaysClock + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "verb, to show something", "Always show") + } + Item { + Layout.fillWidth: true + } + } + + RowLayout { + spacing: units.largeSpacing / 2 + + QQC2.Label { + Layout.minimumWidth: formAlignment - units.largeSpacing //to match wallpaper config... + horizontalAlignment: Text.AlignRight + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Media controls:") + } + QQC2.CheckBox { + id: showMediaControls + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "verb, to show something", "Show") + } + Item { + Layout.fillWidth: true + } + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/config.xml b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/config.xml new file mode 100644 index 00000000..436a67ea --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/lockscreen/config.xml @@ -0,0 +1,19 @@ + + + + + + + + true + + + + true + + + + diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/logout/Logout.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/logout/Logout.qml new file mode 100644 index 00000000..57e21fcb --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/logout/Logout.qml @@ -0,0 +1,262 @@ +/*************************************************************************** + * Copyright (C) 2014 by Aleix Pol Gonzalez * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 1.1 as Controls + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.kcoreaddons 1.0 as KCoreAddons + +import "../components" +import "timer.js" as AutoTriggerTimer + +import org.kde.plasma.private.sessions 2.0 + +PlasmaCore.ColorScope { + id: root + colorGroup: PlasmaCore.Theme.ComplementaryColorGroup + height: screenGeometry.height + width: screenGeometry.width + + signal logoutRequested() + signal haltRequested() + signal suspendRequested(int spdMethod) + signal rebootRequested() + signal rebootRequested2(int opt) + signal cancelRequested() + signal lockScreenRequested() + + property alias backgroundColor: backgroundRect.color + + function sleepRequested() { + root.suspendRequested(2); + } + + function hibernateRequested() { + root.suspendRequested(4); + } + + property real timeout: 30 + property real remainingTime: root.timeout + property var currentAction: { + switch (sdtype) { + case ShutdownType.ShutdownTypeReboot: + return root.rebootRequested; + case ShutdownType.ShutdownTypeHalt: + return root.haltRequested; + default: + return root.logoutRequested; + } + } + + KCoreAddons.KUser { + id: kuser + } + + // For showing a "other users are logged in" hint + SessionsModel { + id: sessionsModel + includeUnusedSessions: false + } + + Controls.Action { + onTriggered: root.cancelRequested() + shortcut: "Escape" + } + + onRemainingTimeChanged: { + if (remainingTime <= 0) { + root.currentAction(); + } + } + + Timer { + id: countDownTimer + running: true + repeat: true + interval: 1000 + onTriggered: remainingTime-- + Component.onCompleted: { + AutoTriggerTimer.addCancelAutoTriggerCallback(function() { + countDownTimer.running = false; + }); + } + } + + function isLightColor(color) { + return Math.max(color.r, color.g, color.b) > 0.5 + } + + Rectangle { + id: backgroundRect + anchors.fill: parent + //use "black" because this is intended to look like a general darkening of the scene. a dark gray as normal background would just look too "washed out" + color: "#1e1f29" + opacity: 0.6 + } + MouseArea { + anchors.fill: parent + onClicked: root.cancelRequested() + } + UserDelegate { + width: units.gridUnit * 7 + height: width + nameFontSize: theme.defaultFont.pointSize + 2 + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.verticalCenter + } + constrainText: false + avatarPath: kuser.faceIconUrl + iconSource: "user-identity" + isCurrent: true + name: kuser.fullName + } + ColumnLayout { + anchors { + top: parent.verticalCenter + topMargin: units.gridUnit * 2 + horizontalCenter: parent.horizontalCenter + } + spacing: units.largeSpacing + + height: Math.max(implicitHeight, units.gridUnit * 10) + width: Math.max(implicitWidth, units.gridUnit * 16) + + PlasmaComponents.Label { + font.pointSize: theme.defaultFont.pointSize + 1 + Layout.maximumWidth: units.gridUnit * 16 + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + font.italic: true + text: i18ndp("plasma_lookandfeel_org.kde.lookandfeel", + "One other user is currently logged in. If the computer is shut down or restarted, that user may lose work.", + "%1 other users are currently logged in. If the computer is shut down or restarted, those users may lose work.", + sessionsModel.count) + visible: sessionsModel.count > 1 + } + + PlasmaComponents.Label { + font.pointSize: theme.defaultFont.pointSize + 1 + Layout.maximumWidth: units.gridUnit * 16 + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + font.italic: true + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "When restarted, the computer will enter the firmware setup screen.") + visible: rebootToFirmwareSetup + } + + RowLayout { + spacing: units.largeSpacing * 2 + Layout.alignment: Qt.AlignHCenter + LogoutButton { + id: suspendButton + iconSource: "system-suspend" + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Suspend to RAM", "Sleep") + action: root.sleepRequested + KeyNavigation.left: logoutButton + KeyNavigation.right: hibernateButton + visible: spdMethods.SuspendState + } + LogoutButton { + id: hibernateButton + iconSource: "system-suspend-hibernate" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Hibernate") + action: root.hibernateRequested + KeyNavigation.left: suspendButton + KeyNavigation.right: rebootButton + visible: spdMethods.HibernateState + } + LogoutButton { + id: rebootButton + iconSource: "system-reboot" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Restart") + action: root.rebootRequested + KeyNavigation.left: hibernateButton + KeyNavigation.right: shutdownButton + focus: sdtype === ShutdownType.ShutdownTypeReboot + visible: maysd + } + LogoutButton { + id: shutdownButton + iconSource: "system-shutdown" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Shut Down") + action: root.haltRequested + KeyNavigation.left: rebootButton + KeyNavigation.right: logoutButton + focus: sdtype === ShutdownType.ShutdownTypeHalt + visible: maysd + } + LogoutButton { + id: logoutButton + iconSource: "system-log-out" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Log Out") + action: root.logoutRequested + KeyNavigation.left: shutdownButton + KeyNavigation.right: suspendButton + focus: sdtype === ShutdownType.ShutdownTypeNone + visible: canLogout + } + } + + PlasmaComponents.Label { + font.pointSize: theme.defaultFont.pointSize + 1 + Layout.alignment: Qt.AlignHCenter + //opacity, as visible would re-layout + opacity: countDownTimer.running ? 1 : 0 + Behavior on opacity { + OpacityAnimator { + duration: units.longDuration + easing.type: Easing.InOutQuad + } + } + text: { + switch (sdtype) { + case ShutdownType.ShutdownTypeReboot: + return i18ndp("plasma_lookandfeel_org.kde.lookandfeel", "Restarting in 1 second", "Restarting in %1 seconds", root.remainingTime); + case ShutdownType.ShutdownTypeHalt: + return i18ndp("plasma_lookandfeel_org.kde.lookandfeel", "Shutting down in 1 second", "Shutting down in %1 seconds", root.remainingTime); + default: + return i18ndp("plasma_lookandfeel_org.kde.lookandfeel", "Logging out in 1 second", "Logging out in %1 seconds", root.remainingTime); + } + } + } + + RowLayout { + Layout.alignment: Qt.AlignHCenter + PlasmaComponents.Button { + font.pointSize: theme.defaultFont.pointSize + 1 + enabled: root.currentAction !== null + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "OK") + onClicked: root.currentAction() + } + PlasmaComponents.Button { + font.pointSize: theme.defaultFont.pointSize + 1 + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Cancel") + onClicked: root.cancelRequested() + } + } + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/logout/LogoutButton.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/logout/LogoutButton.qml new file mode 100644 index 00000000..af1b79d4 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/logout/LogoutButton.qml @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2016 Marco Martin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.2 + +import org.kde.plasma.core 2.0 as PlasmaCore + +import "../components" +import "timer.js" as AutoTriggerTimer + +ActionButton { + property var action + onClicked: action() + Layout.alignment: Qt.AlignTop + iconSize: units.iconSizes.huge + circleVisiblity: activeFocus || containsMouse + circleOpacity: 0.55 // Selected option's circle is instantly visible + opacity: activeFocus || containsMouse ? 1 : 0.7 + labelRendering: Text.QtRendering // Remove once we've solved Qt bug: https://bugreports.qt.io/browse/QTBUG-70138 (KDE bug: https://bugs.kde.org/show_bug.cgi?id=401644) + font.underline: false + font.pointSize: theme.defaultFont.pointSize + 1 + Behavior on opacity { + OpacityAnimator { + duration: units.longDuration + easing.type: Easing.InOutQuad + } + } + Keys.onPressed: AutoTriggerTimer.cancelAutoTrigger(); +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/logout/timer.js b/kde/plasma/look-and-feel/Dracula-purple/contents/logout/timer.js new file mode 100644 index 00000000..eeb9a4b1 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/logout/timer.js @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2018 David Edmundson * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +.pragma library + +//written as a library to share knowledge of when a key was pressed +//between the multiple views, so pressing a key on one cancels all timers + +var callbacks = []; + +function addCancelAutoTriggerCallback(callback) { + callbacks.push(callback); +} + +function cancelAutoTrigger() { + callbacks.forEach(function(c) { + if (!c) { + return; + } + c(); + }); +} + diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/osd/Osd.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/osd/Osd.qml new file mode 100644 index 00000000..52b80e25 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/osd/Osd.qml @@ -0,0 +1,38 @@ +/* + * Copyright 2014 Martin Klapetek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.0 +import QtQuick.Window 2.2 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.extras 2.0 as PlasmaExtra + +PlasmaCore.Dialog { + id: root + location: PlasmaCore.Types.Floating + type: PlasmaCore.Dialog.OnScreenDisplay + outputOnly: true + + property alias timeout: osd.timeout + property alias osdValue: osd.osdValue + property alias osdMaxValue: osd.osdMaxValue + property alias icon: osd.icon + property alias showingProgress: osd.showingProgress + + mainItem: OsdItem { + id: osd + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/osd/OsdItem.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/osd/OsdItem.qml new file mode 100644 index 00000000..35c54fa9 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/osd/OsdItem.qml @@ -0,0 +1,118 @@ +/* + * Copyright 2014 Martin Klapetek + * Copyright 2019 Kai Uwe Broulik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.14 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 3.0 as PlasmaComponents3 +import org.kde.plasma.extras 2.0 as PlasmaExtra +import QtQuick.Window 2.2 + +RowLayout { + // OSD Timeout in msecs - how long it will stay on the screen + property int timeout: 1800 + // This is either a text or a number, if showingProgress is set to true, + // the number will be used as a value for the progress bar + property var osdValue + // Maximum percent value + property int osdMaxValue: 100 + // Icon name to display + property string icon + // Set to true if the value is meant for progress bar, + // false for displaying the value as normal text + property bool showingProgress: false + + spacing: PlasmaCore.Units.smallSpacing + + width: Math.max(Math.min(Screen.desktopAvailableWidth / 2, implicitWidth), PlasmaCore.Units.gridUnit * 15) + height: PlasmaCore.Units.iconSizes.medium + + PlasmaCore.IconItem { + Layout.leftMargin: PlasmaCore.Units.smallSpacing + Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium + Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium + Layout.alignment: Qt.AlignVCenter + source: icon + visible: valid + } + + PlasmaComponents3.ProgressBar { + id: progressBar + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + // So it never exceeds the minimum popup size + Layout.preferredWidth: 1 + Layout.rightMargin: PlasmaCore.Units.smallSpacing + visible: showingProgress + from: 0 + to: osdMaxValue + value: Number(osdValue) + } + + // Get the width of a three-digit number so we can size the label + // to the maximum width to avoid the progress bad resizing itself + TextMetrics { + id: widestLabelSize + text: i18n("100%") + font: percentageLabel.font + } + + // Numerical display of progress bar value + PlasmaExtra.Heading { + id: percentageLabel + Layout.fillHeight: true + Layout.preferredWidth: widestLabelSize.width + Layout.rightMargin: PlasmaCore.Units.smallSpacing + Layout.alignment: Qt.AlignVCenter + level: 3 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: i18nc("Percentage value", "%1%", progressBar.value) + visible: showingProgress + // Display a subtle visual indication that the volume might be + // dangerously high + // ------------------------------------------------ + // Keep this in sync with the copies in plasma-pa:ListItemBase.qml + // and plasma-pa:VolumeSlider.qml + color: { + if (progressBar.value <= 100) { + return PlasmaCore.Theme.textColor + } else if (progressBar.value > 100 && progressBar.value <= 125) { + return PlasmaCore.Theme.neutralTextColor + } else { + return PlasmaCore.Theme.negativeTextColor + } + } + } + + PlasmaExtra.Heading { + id: label + Layout.fillWidth: true + Layout.fillHeight: true + Layout.rightMargin: PlasmaCore.Units.smallSpacing + Layout.alignment: Qt.AlignVCenter + level: 3 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + textFormat: Text.PlainText + wrapMode: Text.NoWrap + elide: Text.ElideRight + text: !showingProgress && osdValue ? osdValue : "" + visible: !showingProgress + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/previews/fullscreenpreview.png b/kde/plasma/look-and-feel/Dracula-purple/contents/previews/fullscreenpreview.png new file mode 100644 index 00000000..f606b89b Binary files /dev/null and b/kde/plasma/look-and-feel/Dracula-purple/contents/previews/fullscreenpreview.png differ diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/previews/preview.png b/kde/plasma/look-and-feel/Dracula-purple/contents/previews/preview.png new file mode 100644 index 00000000..1c9ad113 Binary files /dev/null and b/kde/plasma/look-and-feel/Dracula-purple/contents/previews/preview.png differ diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/previews/splash.png b/kde/plasma/look-and-feel/Dracula-purple/contents/previews/splash.png new file mode 100644 index 00000000..7925def1 Binary files /dev/null and b/kde/plasma/look-and-feel/Dracula-purple/contents/previews/splash.png differ diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/splash/Splash.qml b/kde/plasma/look-and-feel/Dracula-purple/contents/splash/Splash.qml new file mode 100644 index 00000000..6fc7e6a7 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/splash/Splash.qml @@ -0,0 +1,109 @@ +import QtQuick 2.5 + +Image { + id: root + source: "images/background.png" + + property int stage + + onStageChanged: { + if (stage == 1) { + introAnimation.running = true + } + } + + Item { + id: content + anchors.fill: parent + opacity: 0 + TextMetrics { + id: units + text: "M" + property int gridUnit: boundingRect.height + property int largeSpacing: units.gridUnit + property int smallSpacing: Math.max(2, gridUnit/4) + } + + Image { + id: logo + property real size: units.gridUnit * 12 + anchors.centerIn: parent + source: "images/logo.png" + sourceSize.width: 150 + sourceSize.height: 150 + + ParallelAnimation { + running: true + + ScaleAnimator { + target: logo + from: 0 + to: 1 + duration: 700 + } + SequentialAnimation { + loops: Animation.Infinite + + ScaleAnimator { + target: logo + from: 0.97 + to: 1 + duration: 1000 + } + ScaleAnimator { + target: logo + from: 1 + to: 0.97 + duration: 1000 + } + } + } + } + + Image { + id: busyIndicator + //in the middle of the remaining space + y: parent.height / 2 - height/2 + anchors.horizontalCenter: parent.horizontalCenter + source: "images/busy02.svg" + sourceSize.height: logo.height + 60 + sourceSize.width: logo.width + 60 + RotationAnimator on rotation { + id: rotationAnimator + from: 0 + to: 360 + duration: 1200 + loops: Animation.Infinite + } + } + + Image { + id: busyIndicator2 + //in the middle of the remaining space + y: parent.height / 2 - height /2 + anchors.horizontalCenter: parent.horizontalCenter + source: "images/busy02.svg" + sourceSize.height: logo.height + 100 + sourceSize.width: logo.width + 100 + RotationAnimator on rotation { + id: rotationAnimator2 + from: 360 + to: 0 + duration: 1200 + loops: Animation.Infinite + } + } + + + } + + OpacityAnimator { + id: introAnimation + running: false + target: content + from: 0 + to: 1 + duration: 1000 + easing.type: Easing.InOutQuad + } +} diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/splash/images/background.png b/kde/plasma/look-and-feel/Dracula-purple/contents/splash/images/background.png new file mode 100644 index 00000000..9e1a1a8d Binary files /dev/null and b/kde/plasma/look-and-feel/Dracula-purple/contents/splash/images/background.png differ diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/splash/images/busy02.svg b/kde/plasma/look-and-feel/Dracula-purple/contents/splash/images/busy02.svg new file mode 100644 index 00000000..1de8b618 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/contents/splash/images/busy02.svg @@ -0,0 +1,46 @@ + + + + + + + + + diff --git a/kde/plasma/look-and-feel/Dracula-purple/contents/splash/images/logo.png b/kde/plasma/look-and-feel/Dracula-purple/contents/splash/images/logo.png new file mode 100644 index 00000000..ccb15227 Binary files /dev/null and b/kde/plasma/look-and-feel/Dracula-purple/contents/splash/images/logo.png differ diff --git a/kde/plasma/look-and-feel/Dracula-purple/metadata.desktop b/kde/plasma/look-and-feel/Dracula-purple/metadata.desktop new file mode 100644 index 00000000..0a683613 --- /dev/null +++ b/kde/plasma/look-and-feel/Dracula-purple/metadata.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Name=Dracula-purple +X-KDE-PluginInfo-Author=EliverLara +X-KDE-PluginInfo-Category=Plasma Look And Feel +X-KDE-PluginInfo-Email=eliverlara@gmail.com +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-PluginInfo-License=GPL 3+ +X-KDE-PluginInfo-Name=Dracula-purple +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=https://github.com/EliverLara/Ant-Dracula/tree/master/kde +X-KDE-ServiceTypes=Plasma/LookAndFeel + +X-KPackage-Dependencies=kns://colorschemes.knsrc/api.kde-look.org/1370679,kns://plasma-themes.knsrc/api.kde-look.org/1370687,kns://plasma-themes.knsrc/api.kde-look.org/1420691,kns://aurorae.knsrc/api.kde-look.org/1370682,kns://sddmtheme.knsrc/api.kde-look.org/1374247,kns://wallpaper.knsrc/api.kde-look.org/1378234,kns://xcursor.knsrc/api.kde-look.org/1669262,kns://plasmoids.knsrc/api.kde-look.org/2048016 \ No newline at end of file diff --git a/kde/plasma/look-and-feel/PomeDesktop2/contents/defaults b/kde/plasma/look-and-feel/PomeDesktop2/contents/defaults new file mode 100644 index 00000000..5dfd0f3b --- /dev/null +++ b/kde/plasma/look-and-feel/PomeDesktop2/contents/defaults @@ -0,0 +1,27 @@ +[kcminputrc][Mouse] +cursorTheme=breeze_cursors + +[kdeglobals][General] +ColorScheme=BreezeDark + +[kdeglobals][Icons] +Theme=Papirus-Dark + +[kdeglobals][KDE] +widgetStyle=Breeze + +[kwinrc][DesktopSwitcher] +LayoutName=org.kde.breeze.desktop + +[kwinrc][WindowSwitcher] +LayoutName=org.kde.breeze.desktop + +[kwinrc][org.kde.kdecoration2] +library=org.kde.breeze +theme=Breeze + +[plasmarc][Theme] +name=Colloid-dark + +[Wallpaper] +Image=PomeDefaultWallpaper diff --git a/kde/plasma/look-and-feel/PomeDesktop2/contents/layouts/org.kde.plasma.desktop-layout.js b/kde/plasma/look-and-feel/PomeDesktop2/contents/layouts/org.kde.plasma.desktop-layout.js new file mode 100644 index 00000000..8ee57608 --- /dev/null +++ b/kde/plasma/look-and-feel/PomeDesktop2/contents/layouts/org.kde.plasma.desktop-layout.js @@ -0,0 +1,167 @@ +var plasma = getApiVersion(1); + +ColorAccetFile = ConfigFile("kdeglobals") +ColorAccetFile.group = "General" +ColorAccetFile.writeEntry("accentColorFromWallpaper", "true") + +var layout = { + "desktops": [ + { + "applets": [ + ], + "config": { + "/": { + "ItemGeometries-1920x1080": "", + "ItemGeometriesHorizontal": "", + "formfactor": "0", + "immutability": "1", + "lastScreen": "0", + "wallpaperplugin": "com.github.casout.wallpaperEngineKde" + }, + "/ConfigDialog": { + "DialogHeight": "540", + "DialogWidth": "720" + }, + "/General": { + "ToolBoxButtonState": "topcenter", + "ToolBoxButtonX": "315", + "ToolBoxButtonY": "27", + "filterMimeTypes": "\\0", + "positions": "{\"1920x1080\":[]}", + "sortMode": "-1" + } + }, + "wallpaperPlugin": "org.kde.image" + } + ], + "panels": [ + { + "alignment": "left", + "applets": [ + { + "config": { + "/": { + "PreloadWeight": "100" + }, + "/ConfigDialog": { + "DialogHeight": "540", + "DialogWidth": "720" + }, + "/General": { + "displayPosition": "Center", + "favoritesPortedToKAstats": "true", + "floating": "true", + "launcherPosition": "2" + } + }, + "plugin": "org.kde.plasma.dittomenu" + }, + { + "config": { + }, + "plugin": "org.kde.plasma.panelspacer" + }, + { + "config": { + "/": { + "PreloadWeight": "75", + "popupHeight": "450", + "popupWidth": "396" + }, + "/Appearance": { + "customDateFormat": "", + "showDate": "false" + }, + "/ConfigDialog": { + "DialogHeight": "540", + "DialogWidth": "720" + } + }, + "plugin": "org.kde.plasma.digitalclock" + }, + { + "config": { + }, + "plugin": "org.kde.plasma.panelspacer" + }, + { + "config": { + "/": { + "PreloadWeight": "65" + } + }, + "plugin": "org.kde.plasma.systemtray" + }, + { + "config": { + }, + "plugin": "org.kde.plasma.lock_logout" + } + ], + "config": { + "/": { + "formfactor": "2", + "immutability": "1", + "lastScreen": "0", + "wallpaperplugin": "org.kde.image" + }, + "/ConfigDialog": { + "DialogHeight": "84", + "DialogWidth": "1920" + } + }, + "height": 1.5, + "hiding": "normal", + "location": "top", + "maximumLength": 106.66666666666667, + "minimumLength": 106.66666666666667, + "offset": 0 + }, + { + "alignment": "center", + "applets": [ + { + "config": { + "/": { + "launchers": "" + }, + "/General": { + "iconSpacing": "0", + "indicateAudioStreams": "false", + "launchers": "", + "maxStripes": "1" + } + }, + "plugin": "org.kde.plasma.icontasks" + }, + { + "config": { + }, + "plugin": "org.kde.plasma.trash" + } + ], + "config": { + "/": { + "formfactor": "3", + "immutability": "1", + "lastScreen": "0", + "wallpaperplugin": "org.kde.image" + }, + "/ConfigDialog": { + "DialogHeight": "1080", + "DialogWidth": "248" + } + }, + "height": 3.3333333333333335, + "hiding": "autohide", + "location": "right", + "maximumLength": 60, + "minimumLength": 60, + "offset": 0 + } + ], + "serializationFormatVersion": "1" +} +; + +plasma.loadSerializedLayout(layout); diff --git a/kde/plasma/look-and-feel/PomeDesktop2/contents/previews/fullscreenpreview.jpg b/kde/plasma/look-and-feel/PomeDesktop2/contents/previews/fullscreenpreview.jpg new file mode 100644 index 00000000..4d46c14e Binary files /dev/null and b/kde/plasma/look-and-feel/PomeDesktop2/contents/previews/fullscreenpreview.jpg differ diff --git a/kde/plasma/look-and-feel/PomeDesktop2/contents/previews/preview.png b/kde/plasma/look-and-feel/PomeDesktop2/contents/previews/preview.png new file mode 100644 index 00000000..d24b59d1 Binary files /dev/null and b/kde/plasma/look-and-feel/PomeDesktop2/contents/previews/preview.png differ diff --git a/kde/plasma/look-and-feel/PomeDesktop2/metadata.desktop b/kde/plasma/look-and-feel/PomeDesktop2/metadata.desktop new file mode 100644 index 00000000..455fa6f5 --- /dev/null +++ b/kde/plasma/look-and-feel/PomeDesktop2/metadata.desktop @@ -0,0 +1,15 @@ +[Desktop Entry] +Name=Pome Desktop 2 +X-KDE-PluginInfo-Author=UuBroot +X-KDE-PluginInfo-Category=Plasma Look And Feel +X-KDE-PluginInfo-Email=lolylyt@gmail.com +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-PluginInfo-License=GPL 3+ +X-KDE-PluginInfo-Name=PomeDesktop2 +X-KDE-PluginInfo-Version=2 +X-KDE-PluginInfo-Website=https://github.com/uubroot +X-KDE-ServiceTypes=Plasma/LookAndFeel +X-KDE-fallbackPackage=org.kde.breeze.desktop + +X-KPackage-Dependencies=kns://plasma-themes.knsrc/api.kde-look.org/1738703,kns://plasmoids.knsrc/api.kde-look.org/1312669,kns://icons.knsrc/api.kde-look.org/1166289/,kns://wallpaper.knsrc/api.kde-look.org/2056002/ + diff --git a/kde/plasma/look-and-feel/RedDash/contents/previews/splash.png b/kde/plasma/look-and-feel/RedDash/contents/previews/splash.png new file mode 100644 index 00000000..eb8a89a6 Binary files /dev/null and b/kde/plasma/look-and-feel/RedDash/contents/previews/splash.png differ diff --git a/kde/plasma/look-and-feel/RedDash/contents/splash/BebasNeue-Regular.ttf b/kde/plasma/look-and-feel/RedDash/contents/splash/BebasNeue-Regular.ttf new file mode 100644 index 00000000..c328c6e0 Binary files /dev/null and b/kde/plasma/look-and-feel/RedDash/contents/splash/BebasNeue-Regular.ttf differ diff --git a/kde/plasma/look-and-feel/RedDash/contents/splash/Digit.qml b/kde/plasma/look-and-feel/RedDash/contents/splash/Digit.qml new file mode 100644 index 00000000..fb3bce33 --- /dev/null +++ b/kde/plasma/look-and-feel/RedDash/contents/splash/Digit.qml @@ -0,0 +1,24 @@ +import QtQuick 2.15 + +Rectangle +{ + id: root + property int number + property alias font: text.font.family + radius: height * 0.05 + + color: "#9b0000" + + Text + { + id: text + text: (root.number < 10 ? "0" : "") + root.number + anchors.fill: parent + color: "#d8d8d8" + font.pixelSize: Math.min(height * 0.4, width * 0.4) + font.family: fixedFont.name + renderType: Text.QtRendering + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } +} diff --git a/kde/plasma/look-and-feel/RedDash/contents/splash/FlipEffect.qml b/kde/plasma/look-and-feel/RedDash/contents/splash/FlipEffect.qml new file mode 100644 index 00000000..fdf45d8d --- /dev/null +++ b/kde/plasma/look-and-feel/RedDash/contents/splash/FlipEffect.qml @@ -0,0 +1,160 @@ +import QtQuick 2.15 + +/** + * Provides a flip-panel effect on a given item + * It is assumed we have the same geometry of that item and anchored on top + */ + +// in any sane world we would hide the flipEffect when we're not animating +// however QtQuick tries to be clever and flushes with Effectsource when there's no monitor +// and I relied on that.. +// doesn't seem too costly, so meh +// it does look hilarious if you resize though... + +Item +{ + id: root + property Item sourceItem + property int duration: 1000 + property bool supress: true + + function flip() + { + // lazy hack to avoid the first flip that happens on initial bind + if (supress) + { + supress = false; + return; + } + + flipAnim.start() + } + + ShaderEffectSource + { + id: oldTop + sourceItem: root.sourceItem + sourceRect: Qt.rect(0, 0, root.sourceItem.width, root.sourceItem.height/2) + live: false + } + + ShaderEffectSource + { + id: oldBottom + sourceItem: root.sourceItem + sourceRect: Qt.rect(0, root.sourceItem.height/2, root.sourceItem.width, root.sourceItem.height/2) + live: false + } + + ShaderEffectSource + { + id: newBottom + sourceItem: root.sourceItem + sourceRect: Qt.rect(0, root.sourceItem.height/2, root.sourceItem.width, root.sourceItem.height/2) + live: false + textureMirroring: ShaderEffectSource.NoMirroring + } + + ShaderEffect + { + id: effect + anchors.top: root.top + anchors.bottom: root.verticalCenter + anchors.left: root.left + anchors.right: root.right + property variant source: oldTop + z: 10 + transform: Rotation + { + id: upperRotation + origin.x: effect.width/2 + origin.y: effect.height + axis.x: 1 + axis.y: 0 + axis.z: 0 + angle: 90 + } + } + + ShaderEffect + { + id: effect2 + anchors.top: root.top + anchors.bottom: root.verticalCenter + anchors.left: root.left + anchors.right: root.right + property variant source: newBottom + z: 10 + transform: Rotation + { + id: lowerRotation + origin.x: effect.width/2 + origin.y: effect.height + axis.x: 1 + axis.y: 0 + axis.z: 0 + angle: 90 + } + } + + ShaderEffect + { + property variant source: oldBottom + anchors.top: root.verticalCenter + anchors.bottom: root.bottom + anchors.left: root.left + anchors.right: root.right + z:1 + } + + SequentialAnimation + { + id: flipAnim + + NumberAnimation + { + target: upperRotation + property: "angle" + from: 0 + to: -90 + duration: root.duration / 2 + } + + ScriptAction + { + script: + { + newBottom.scheduleUpdate() + } + } + + NumberAnimation + { + target: lowerRotation + property: "angle" + from: -90 + to: -180 + duration: root.duration / 2 + } + + ScriptAction + { + script: + { + oldTop.scheduleUpdate(); + oldBottom.scheduleUpdate(); + } + } + } + + // horizontal line to make it look like a flippy thing + Rectangle + { + color: "#9b0000" + height: 2 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + z: 20 + } +} diff --git a/kde/plasma/look-and-feel/RedDash/contents/splash/Splash.qml b/kde/plasma/look-and-feel/RedDash/contents/splash/Splash.qml new file mode 100644 index 00000000..536b3afe --- /dev/null +++ b/kde/plasma/look-and-feel/RedDash/contents/splash/Splash.qml @@ -0,0 +1,162 @@ +import QtQuick 2.15 +import org.kde.plasma.core 2.0 as PlasmaCore + +Image { + id: root + source: "images/RedDash.png" + fillMode: Image.PreserveAspectCrop + + property int stage + + onStageChanged: + { + if (stage == 1) + { + introAnimation.running = true + } + } + + width: 1920 + height: 1200 + + FontLoader { + id: fixedFont + source: "BebasNeue-Regular.ttf" + } + + PlasmaCore.DataSource + { + id: dataSource + engine: "time" + connectedSources: "Local" + interval: 60000 + intervalAlignment: PlasmaCore.Types.AlignToMinute + onDataChanged: + { + updateTime() + } + } + + function updateTime() { + root.hour = dataSource.data["Local"]["DateTime"].getHours() + root.min = dataSource.data["Local"]["DateTime"].getMinutes() + } + + property int hour + property int min + + // helper for testing animation + //Timer + //{ + //running: true + //interval: 4000 + //repeat: true + //onTriggered: root.hour++ + //} + + Digit + { + id: hours + y: root.height + height: root.height * 0.2 + width: Math.min(parent.width * 0.45, height) + anchors.right: parent.horizontalCenter + anchors.rightMargin: parent.width * 0.01 + font: fixedFont.name + //anchors.verticalCenter: root.verticalCenter + number: root.hour + onNumberChanged: flipEffectHours.flip() + } + + FlipEffect + { + id: flipEffectHours + sourceItem: hours + anchors.fill: hours + } + + Digit + { + id: min + y: root.height + height: root.height * 0.2 + width: Math.min(parent.width * 0.45, height) + anchors.left: parent.horizontalCenter + anchors.leftMargin: parent.width * 0.01 + font: fixedFont.name + //anchors.verticalCenter: root.verticalCenter + number: root.min + onNumberChanged: flipEffectMin.flip() + } + + FlipEffect { + id: flipEffectMin + sourceItem: min + anchors.fill: min + } + + Rectangle + { + radius: 12 + color: "#640000" + height: 12 + width: height*40 + anchors + { + bottom: parent.bottom + bottomMargin:200 + horizontalCenter: parent.horizontalCenter + } + + Rectangle + { + radius: 12 + color: "#c80000" + width: (parent.width / 6) * (stage - 0.00) + anchors + { + left: parent.left + top: parent.top + bottom: parent.bottom + } + + Behavior on width + { + PropertyAnimation + { + duration: 2500 + easing.type: Easing.InOutQuad + } + } + } + } + + SequentialAnimation + { + id: introAnimation + running: false + + ParallelAnimation + { + PropertyAnimation + { + property: "y" + target: hours + to: (root.height / 2) - (hours.height / 2) + duration: 0 + easing.type: Easing.InOutBack + easing.overshoot: 1.0 + } + + PropertyAnimation + { + property: "y" + target: min + to: (root.height / 2) - (min.height / 2) + duration: 0 + easing.type: Easing.InOutBack + easing.overshoot: 1.0 + } + } + } +} diff --git a/kde/plasma/look-and-feel/RedDash/contents/splash/images/RedDash.png b/kde/plasma/look-and-feel/RedDash/contents/splash/images/RedDash.png new file mode 100644 index 00000000..eb8a89a6 Binary files /dev/null and b/kde/plasma/look-and-feel/RedDash/contents/splash/images/RedDash.png differ diff --git a/kde/plasma/look-and-feel/RedDash/metadata.desktop b/kde/plasma/look-and-feel/RedDash/metadata.desktop new file mode 100644 index 00000000..a0662de9 --- /dev/null +++ b/kde/plasma/look-and-feel/RedDash/metadata.desktop @@ -0,0 +1,22 @@ +[Desktop Entry] +Comment=Add a Dash of Red to your Startup + +Encoding=UTF-8 +Keywords=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate; +Name=Red Dash + +Type=Service + +X-KDE-ServiceTypes=Plasma/LookAndFeel +X-KDE-ParentApp= +X-KDE-PluginInfo-Author=RedrcknRbn +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Email= +X-KDE-PluginInfo-License=CC BY-SA 4.0 +X-KDE-PluginInfo-Name=RedDash +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website= +X-KDE-fallbackPackage=org.kde.breeze.desktop +X-Plasma-MainScript=defaults +X-Plasma-APIVersion=2 +X-KPackage-Dependencies= diff --git a/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/contents/defaults b/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/contents/defaults new file mode 100644 index 00000000..2500e612 --- /dev/null +++ b/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/contents/defaults @@ -0,0 +1,24 @@ +[kcminputrc][Mouse] +cursorTheme=Win10OS-cursors + +[kdeglobals][General] +ColorScheme=TokyoNight + +[kdeglobals][Icons] +Theme=TokyoNight-SE + +[kdeglobals][KDE] +widgetStyle=Klassy + +[kwinrc][DesktopSwitcher] +LayoutName=org.kde.breeze.desktop + +[kwinrc][WindowSwitcher] +LayoutName=org.kde.breeze.desktop + +[kwinrc][org.kde.kdecoration2] +library=org.kde.kwin.aurorae +theme=__aurorae__svg__TokyoNight + +[plasmarc][Theme] +name=Tokyo-Night diff --git a/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/contents/layouts/org.kde.plasma.desktop-layout.js b/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/contents/layouts/org.kde.plasma.desktop-layout.js new file mode 100644 index 00000000..4793c06e --- /dev/null +++ b/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/contents/layouts/org.kde.plasma.desktop-layout.js @@ -0,0 +1,110 @@ +var plasma = getApiVersion(1); + +var layout = { + "desktops": [ + { + "applets": [ + ], + "config": { + "/": { + "ItemGeometries-1280x720": "", + "ItemGeometries-1366x768": "", + "ItemGeometriesHorizontal": "", + "formfactor": "0", + "immutability": "1", + "lastScreen": "0", + "wallpaperplugin": "org.kde.image" + }, + "/ConfigDialog": { + "DialogHeight": "540", + "DialogWidth": "720" + }, + "/General": { + "ToolBoxButtonState": "topcenter", + "ToolBoxButtonX": "167" + }, + "/Wallpaper/org.kde.image/General": { + "Image": "/home/jay/.local/share/wallpapers/Tokyo-Night.jpg", + "SlidePaths": "/home/jay/.local/share/wallpapers/,/usr/share/wallpapers/" + } + }, + "wallpaperPlugin": "org.kde.image" + } + ], + "panels": [ + { + "alignment": "left", + "applets": [ + { + "config": { + "/": { + "PreloadWeight": "100", + "popupHeight": "514", + "popupWidth": "651" + }, + "/General": { + "favoritesPortedToKAstats": "true" + }, + "/Shortcuts": { + "global": "Alt+F1" + } + }, + "plugin": "org.kde.plasma.kickoff" + }, + { + "config": { + "/General": { + "launchers": "applications:systemsettings.desktop,preferred://filemanager,preferred://browser,applications:org.kde.konsole.desktop" + } + }, + "plugin": "org.kde.plasma.icontasks" + }, + { + "config": { + }, + "plugin": "org.kde.plasma.marginsseparator" + }, + { + "config": { + "/": { + "PreloadWeight": "65" + } + }, + "plugin": "org.kde.plasma.systemtray" + }, + { + "config": { + }, + "plugin": "org.kde.plasma.digitalclock" + }, + { + "config": { + }, + "plugin": "org.kde.plasma.showdesktop" + } + ], + "config": { + "/": { + "formfactor": "2", + "immutability": "1", + "lastScreen": "0", + "wallpaperplugin": "org.kde.image" + }, + "/ConfigDialog": { + "DialogHeight": "84", + "DialogWidth": "1366" + } + }, + "height": 1.8888888888888888, + "hiding": "normal", + "location": "bottom", + "maximumLength": 75.88888888888889, + "minimumLength": 75.88888888888889, + "offset": 0 + } + ], + "serializationFormatVersion": "1" +} +; + +plasma.loadSerializedLayout(layout); diff --git a/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/contents/previews/preview.png b/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/contents/previews/preview.png new file mode 100644 index 00000000..b4988478 Binary files /dev/null and b/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/contents/previews/preview.png differ diff --git a/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/metadata.desktop b/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/metadata.desktop new file mode 100644 index 00000000..931b0ce3 --- /dev/null +++ b/kde/plasma/look-and-feel/com.github.Jayy-Dev.Plasma.Tokyo.Night/metadata.desktop @@ -0,0 +1,21 @@ +[Desktop Entry] +Name=Tokyo Night +Comment=Tokyo Night Global Theme +Encoding=UTF-8 +Keywords=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate; + +Type=Service + +X-KDE-ServiceTypes=Plasma/LookAndFeel +X-KDE-ParentApp= +X-KDE-PluginInfo-Author=JayyDev +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Email=none25711@gmail.com +X-KDE-PluginInfo-License=GPL_V3 +X-KDE-PluginInfo-Name=com.github.Jayy-Dev.Plasma.Tokyo.Night +X-KDE-PluginInfo-Version=1.0.0 +X-KDE-PluginInfo-Website=https://github.com/Jayy-Dev/Plasma-Tokyo-Night +X-KDE-fallbackPackage=org.kde.breeze.desktop +X-Plasma-MainScript=defaults +X-KPackage-Dependencies=kns://colorschemes.knsrc/api.kde-look.org/2053460,kns://plasma-themes.knsrc/api.kde-look.org/2053458,kns://aurorae.knsrc/api.kde-look.org/2053454,kns://icons.knsrc/api.kde-look.org/2053446,kns://xcursor.knsrc/api.kde-look.org/1383064 +X-Plasma-MainScript=defaults diff --git a/kde/plasma/plasmoids/AndromedaLauncher/LICENSE b/kde/plasma/plasmoids/AndromedaLauncher/LICENSE new file mode 100644 index 00000000..d159169d --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/code/tools.js b/kde/plasma/plasmoids/AndromedaLauncher/contents/code/tools.js new file mode 100644 index 00000000..1aa2a65e --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/code/tools.js @@ -0,0 +1,202 @@ +/*************************************************************************** + * Copyright (C) 2013 by Aurélien Gâteau * + * Copyright (C) 2013-2015 by Eike Hein * + * Copyright (C) 2017 by Ivan Cukic * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +.pragma library + +function fillActionMenu(i18n, actionMenu, actionList, favoriteModel, favoriteId) { + // Accessing actionList can be a costly operation, so we don't + // access it until we need the menu. + + var actions = createFavoriteActions(i18n, favoriteModel, favoriteId); + + if (actions) { + if (actionList && actionList.length > 0) { + var separator = { "type": "separator" }; + actionList.push(separator); + // actionList = actions.concat(actionList); // this crashes Qt O.o + actionList.push.apply(actionList, actions); + } else { + actionList = actions; + } + } + + actionMenu.actionList = actionList; +} + +function createFavoriteActions(i18n, favoriteModel, favoriteId) { + if (favoriteModel === null || !favoriteModel.enabled || favoriteId == null) { + return null; + } + + + if (favoriteModel.activities === undefined || + favoriteModel.activities.runningActivities.length <= 1) { + var action = {}; + + if (favoriteModel.isFavorite(favoriteId)) { + action.text = i18n("Remove from Favorites"); + action.icon = "bookmark-remove"; + action.actionId = "_kicker_favorite_remove"; + } else if (favoriteModel.maxFavorites == -1 || favoriteModel.count < favoriteModel.maxFavorites) { + action.text = i18n("Add to Favorites"); + action.icon = "bookmark-new"; + action.actionId = "_kicker_favorite_add"; + } else { + return null; + } + + action.actionArgument = { favoriteModel: favoriteModel, favoriteId: favoriteId }; + + return [action]; + + } else { + var actions = []; + + var linkedActivities = favoriteModel.linkedActivitiesFor(favoriteId); + + var activities = favoriteModel.activities.runningActivities; + + // Adding the item to link/unlink to all activities + + var linkedToAllActivities = + !(linkedActivities.indexOf(":global") === -1); + + actions.push({ + text : i18n("On All Activities"), + checkable : true, + + actionId : linkedToAllActivities ? + "_kicker_favorite_remove_from_activity" : + "_kicker_favorite_set_to_activity", + checked : linkedToAllActivities, + + actionArgument : { + favoriteModel: favoriteModel, + favoriteId: favoriteId, + favoriteActivity: "" + } + }); + + + // Adding items for each activity separately + + var addActivityItem = function(activityId, activityName) { + var linkedToThisActivity = + !(linkedActivities.indexOf(activityId) === -1); + + actions.push({ + text : activityName, + checkable : true, + checked : linkedToThisActivity && !linkedToAllActivities, + + actionId : + // If we are on all activities, and the user clicks just one + // specific activity, unlink from everything else + linkedToAllActivities ? "_kicker_favorite_set_to_activity" : + + // If we are linked to the current activity, just unlink from + // that single one + linkedToThisActivity ? "_kicker_favorite_remove_from_activity" : + + // Otherwise, link to this activity, but do not unlink from + // other ones + "_kicker_favorite_add_to_activity", + + actionArgument : { + favoriteModel : favoriteModel, + favoriteId : favoriteId, + favoriteActivity : activityId + } + }); + }; + + // Adding the item to link/unlink to the current activity + + addActivityItem(favoriteModel.activities.currentActivity, i18n("On the Current Activity")); + + actions.push({ + type: "separator", + actionId: "_kicker_favorite_separator" + }); + + // Adding the items for each activity + + activities.forEach(function(activityId) { + addActivityItem(activityId, favoriteModel.activityNameForId(activityId)); + }); + + return [{ + text : i18n("Show in Favorites"), + icon : "favorite", + subActions : actions + }]; + } +} + +function triggerAction(model, index, actionId, actionArgument) { + function startsWith(txt, needle) { + return txt.substr(0, needle.length) === needle; + } + + if (startsWith(actionId, "_kicker_favorite_")) { + handleFavoriteAction(actionId, actionArgument); + return; + } + + var closeRequested = model.trigger(index, actionId, actionArgument); + + if (closeRequested) { + return true; + } + + return false; +} + +function handleFavoriteAction(actionId, actionArgument) { + var favoriteId = actionArgument.favoriteId; + var favoriteModel = actionArgument.favoriteModel; + + console.log(actionId); + + if (favoriteModel === null || favoriteId == null) { + return null; + } + + if (actionId == "_kicker_favorite_remove") { + console.log("Removing from all activities"); + favoriteModel.removeFavorite(favoriteId); + } else if (actionId == "_kicker_favorite_add") { + console.log("Adding to global activity"); + favoriteModel.addFavorite(favoriteId); + } else if (actionId == "_kicker_favorite_remove_from_activity") { + console.log("Removing from a specific activity"); + favoriteModel.removeFavoriteFrom(favoriteId, actionArgument.favoriteActivity); + + } else if (actionId == "_kicker_favorite_add_to_activity") { + console.log("Adding to another activity"); + favoriteModel.addFavoriteTo(favoriteId, actionArgument.favoriteActivity); + + } else if (actionId == "_kicker_favorite_set_to_activity") { + console.log("Removing the item from the favourites, and re-adding it just to be on a specific activity"); + favoriteModel.setFavoriteOn(favoriteId, actionArgument.favoriteActivity); + + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/config/config.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/config/config.qml new file mode 100644 index 00000000..09ac30ad --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/config/config.qml @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2014 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.0 + +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n("General") + icon: "preferences-desktop-plasma" + source: "ConfigGeneral.qml" + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/config/main.xml b/kde/plasma/plasmoids/AndromedaLauncher/contents/config/main.xml new file mode 100644 index 00000000..d1dbd4c5 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/config/main.xml @@ -0,0 +1,78 @@ + + + + + + + + start-here-kde + + + + false + + + + + + + + true + + + + #2164C9 + + + + true + + + + 0 + + + + 0 + + + + + + + + 0 + + + + 0 + + + + 0 + + + + false + + + + false + + + + 0 + + + + true + + + + shell,bookmarks,baloosearch,locations + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/locale/de/LC_MESSAGES/plasma_applet_com.github.SnoutBug.mmckLauncher.mo b/kde/plasma/plasmoids/AndromedaLauncher/contents/locale/de/LC_MESSAGES/plasma_applet_com.github.SnoutBug.mmckLauncher.mo new file mode 100644 index 00000000..2c20a7ef Binary files /dev/null and b/kde/plasma/plasmoids/AndromedaLauncher/contents/locale/de/LC_MESSAGES/plasma_applet_com.github.SnoutBug.mmckLauncher.mo differ diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/locale/id/LC_MESSAGES/plasma_applet_com.github.SnoutBug.mmckLauncher.mo b/kde/plasma/plasmoids/AndromedaLauncher/contents/locale/id/LC_MESSAGES/plasma_applet_com.github.SnoutBug.mmckLauncher.mo new file mode 100644 index 00000000..4d38c675 Binary files /dev/null and b/kde/plasma/plasmoids/AndromedaLauncher/contents/locale/id/LC_MESSAGES/plasma_applet_com.github.SnoutBug.mmckLauncher.mo differ diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/locale/nl/LC_MESSAGES/plasma_applet_com.github.SnoutBug.mmckLauncher.mo b/kde/plasma/plasmoids/AndromedaLauncher/contents/locale/nl/LC_MESSAGES/plasma_applet_com.github.SnoutBug.mmckLauncher.mo new file mode 100644 index 00000000..a3a60645 Binary files /dev/null and b/kde/plasma/plasmoids/AndromedaLauncher/contents/locale/nl/LC_MESSAGES/plasma_applet_com.github.SnoutBug.mmckLauncher.mo differ diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/ActionMenu.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/ActionMenu.qml new file mode 100644 index 00000000..885a60dc --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/ActionMenu.qml @@ -0,0 +1,137 @@ +/*************************************************************************** + * Copyright (C) 2013 by Aurélien Gâteau * + * Copyright (C) 2014-2015 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.0 +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item { + id: root + + property QtObject menu + property Item visualParent + property variant actionList + property bool opened: menu ? (menu.status != PlasmaComponents.DialogStatus.Closed) : false + + signal actionClicked(string actionId, variant actionArgument) + signal closed + + onActionListChanged: refreshMenu(); + + onOpenedChanged: { + if (!opened) { + closed(); + } + } + + function open(x, y) { + if (!actionList) { + return; + } + + if (x && y) { + menu.open(x, y); + } else { + menu.open(); + } + } + + function refreshMenu() { + if (menu) { + menu.destroy(); + } + + if (!actionList) { + return; + } + + menu = contextMenuComponent.createObject(root); + + fillMenu(menu, actionList); + } + + function fillMenu(menu, items) { + items.forEach(function (actionItem) { + if (actionItem.subActions) { + // This is a menu + var submenuItem = contextSubmenuItemComponent.createObject( + menu, { "actionItem": actionItem }); + + fillMenu(submenuItem.submenu, actionItem.subActions); + + } else { + var item = contextMenuItemComponent.createObject( + menu, + { + "actionItem": actionItem, + } + ); + } + }); + + } + + Component { + id: contextMenuComponent + + PlasmaComponents.ContextMenu { + visualParent: root.visualParent + } + } + + Component { + id: contextSubmenuItemComponent + + PlasmaComponents.MenuItem { + id: submenuItem + + property variant actionItem + + text: actionItem.text ? actionItem.text : "" + icon: actionItem.icon ? actionItem.icon : null + + property variant submenu: submenu_ + + PlasmaComponents.ContextMenu { + id: submenu_ + visualParent: submenuItem.action + } + } + } + + Component { + id: contextMenuItemComponent + + PlasmaComponents.MenuItem { + property variant actionItem + + text: actionItem.text ? actionItem.text : "" + enabled: actionItem.type != "title" && ("enabled" in actionItem ? actionItem.enabled : true) + separator: actionItem.type == "separator" + section: actionItem.type == "title" + icon: actionItem.icon ? actionItem.icon : null + checkable: actionItem.checkable ? actionItem.checkable : false + checked: actionItem.checked ? actionItem.checked : false + + onClicked: { + actionClicked(actionItem.actionId, actionItem.actionArgument); + } + } + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/AppList.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/AppList.qml new file mode 100644 index 00000000..282cdcf2 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/AppList.qml @@ -0,0 +1,373 @@ +/***************************************************************************** + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ + +import QtGraphicalEffects 1.0 + +import QtQuick 2.12 +import QtQuick.Controls 2.15 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 3.0 as PlasmaComponents + +ScrollView { + id: scrollView + + anchors { + top: parent.top + } + width: parent.width + height: parent.height + + contentWidth: - 1 //no horizontal scrolling + + property bool grabFocus: false + property bool showDescriptions: false + property int iconSize: units.iconSizes.medium + + property var pinnedModel: [globalFavorites, rootModel.modelForRow(0), rootModel.modelForRow(1)] + property var allAppsModel: [rootModel.modelForRow(2)] + + property var currentStateIndex: plasmoid.configuration.defaultPage + + property bool hasListener: false + property bool isRight: true + + property var scrollpositon: 0.0 + property var scrollheight: 0.0 + + function updateModels() { + item.pinnedModel = [globalFavorites, rootModel.modelForRow(0), rootModel.modelForRow(1)] + item.allAppsModel = [rootModel.modelForRow(2)] + } + + function reset(){ + ScrollBar.vertical.position = 0 + sortingImage.state = sortingImage.states[plasmoid.configuration.defaultPage].name + currentStateIndex = plasmoid.configuration.defaultPage + } + function get_position(){ + return ScrollBar.vertical.position; + } + function get_size(){ + return ScrollBar.vertical.size; + } + Connections { + target: root + function onVisibleChanged() { + sortingImage.state = sortingImage.states[plasmoid.configuration.defaultPage].name + currentStateIndex = plasmoid.configuration.defaultPage + } + } + onContentHeightChanged: { + ScrollBar.vertical.position = scrollpositon * scrollheight / scrollView.contentHeight + } + Column { + id: column + width: parent.width + onPositioningComplete: { + scrollView.contentHeight = height + if (height < backdrop.height) { + scrollView.contentHeight = backdrop.height + 1 + } + } + + Flow { //Favorites + id: flow + width: scrollView.width - 10 * PlasmaCore.Units.devicePixelRatio + spacing: 12 + leftPadding: 20 + visible: !main.showAllApps + Repeater { + model: pinnedModel[0] + delegate: + FavoriteItem { + id: favitem + } + } + } + + Image { + id: sortingImage + width: 15 * PlasmaCore.Units.devicePixelRatio + height: width + visible: main.showAllApps + //I don't like it this way but I have to assign custom images anyways, so it's not too bad... right? + states: [ + State { + name: "all"; + PropertyChanges { target: sortingLabel; text: i18n("All")} + PropertyChanges { target: sortingImage; source: 'icons/feather/file-text.svg'} + }, + State { + name: "dev"; + PropertyChanges { target: sortingLabel; text: i18n("Developement")} + PropertyChanges { target: sortingImage; source: 'icons/feather/code.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(3)} + }, + State { + name: "games"; + PropertyChanges { target: sortingLabel; text: i18n("Games")} + PropertyChanges { target: sortingImage; source: 'icons/lucide/gamepad-2.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(4)} + }, + State { + name: "graphics"; + PropertyChanges { target: sortingLabel; text: i18n("Graphics")} + PropertyChanges { target: sortingImage; source: 'icons/feather/image.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(5)} + }, + State { + name: "internet"; + PropertyChanges { target: sortingLabel; text: i18n("Internet")} + PropertyChanges { target: sortingImage; source: 'icons/feather/globe.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(6)} + }, + State { + name: "multimedia"; + PropertyChanges { target: sortingLabel; text: i18n("Multimedia")} + PropertyChanges { target: sortingImage; source: 'icons/lucide/film.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(8)} + }, + State { + name: "office"; + PropertyChanges { target: sortingLabel; text: i18n("Office")} + PropertyChanges { target: sortingImage; source: 'icons/lucide/paperclip.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(9)} + }, + State { + name: "science"; + PropertyChanges { target: sortingLabel; text: i18n("Science & Math")} + PropertyChanges { target: sortingImage; source: 'icons/lucide/flask-conical.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(10)} + }, + State { + name: "settings"; + PropertyChanges { target: sortingLabel; text: i18n("Settings")} + PropertyChanges { target: sortingImage; source: 'icons/feather/settings.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(11)} + }, + State { + name: "system"; + PropertyChanges { target: sortingLabel; text: i18n("System")} + PropertyChanges { target: sortingImage; source: 'icons/lucide/cpu.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(12)} + }, + State { + name: "utilities"; + PropertyChanges { target: sortingLabel; text: i18n("Utilities")} + PropertyChanges { target: sortingImage; source: 'icons/feather/tool.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(13)} + }, + State { + name: "lost"; + PropertyChanges { target: sortingLabel; text: i18n("Lost & Found")} + PropertyChanges { target: sortingImage; source: 'icons/feather/trash-2.svg'} + PropertyChanges { target: (currentStateIndex % 2 == 0 ? categoriesRepeater : categoriesRepeater2); model: rootModel.modelForRow(7)} + } + ] + PlasmaComponents.Label { + id: sortingLabel + x: parent.width + 10 * PlasmaCore.Units.devicePixelRatio + anchors.verticalCenter: parent.verticalCenter + text: i18n("All") + color: main.textColor + font.family: main.textFont + font.pixelSize: 12 * PlasmaCore.Units.devicePixelRatio + } + MouseArea { + id: mouseArea + width: parent.width + sortingLabel.width + 5 * PlasmaCore.Units.devicePixelRatio + height: parent.height + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + onClicked: { + if (mouse.button == Qt.LeftButton) { + isRight = false + currentStateIndex += 1 + } else if (mouse.button == Qt.RightButton) { + isRight = true + currentStateIndex -= 1 + } else if (mouse.button == Qt.MiddleButton) { + isRight = false + currentStateIndex = plasmoid.configuration.defaultPage + } + if (currentStateIndex > sortingImage.states.length - 1) { + currentStateIndex = 0 + } else if (currentStateIndex < 0) { + currentStateIndex = sortingImage.states.length - 1 + } + sortingImage.state = sortingImage.states[currentStateIndex].name + } + } + ColorOverlay { + visible: plasmoid.configuration.theming != 0 + anchors.fill: sortingImage + source: sortingImage + color: main.textColor + } + } + Item { //Spacer + id: spacer + width: 1 + height: 10 * PlasmaCore.Units.devicePixelRatio + } + + Grid { + id: allAppsGrid + x: - 10 * PlasmaCore.Units.devicePixelRatio + columns: 1 + width: scrollView.width - 10 * PlasmaCore.Units.devicePixelRatio + visible: opacity > 0 && main.showAllApps + Repeater { + id: allAppsRepeater + model: allAppsModel[0] + Repeater { + id: repeater2 + model: allAppsRepeater.model.modelForRow(index) + GenericItem { + id: genericItem + triggerModel: repeater2.model + } + } + } + states: [ + State { + name: "hidden"; when: (sortingImage.state != 'all') + PropertyChanges { target: allAppsGrid; opacity: 0.0 } + PropertyChanges { target: allAppsGrid; x: (!isRight ? -20 * PlasmaCore.Units.devicePixelRatio : 0) } + }, + State { + name: "shown"; when: (sortingImage.state == 'all') + PropertyChanges { target: allAppsGrid; opacity: 1.0 } + PropertyChanges { target: allAppsGrid; x: -10 } + }] + transitions: [ + Transition { + to: "hidden" + PropertyAnimation { properties: 'opacity'; duration: 80; easing: Easing.InQuart} + PropertyAnimation { properties: 'x'; from: -10 * PlasmaCore.Units.devicePixelRatio; duration: 80;easing: Easing.InQuart} + }, + Transition { + to: "shown" + PropertyAnimation { properties: 'opacity'; duration: 80; easing: Easing.InQuart} + PropertyAnimation { properties: 'x'; from: (isRight ? -20 * PlasmaCore.Units.devicePixelRatio : 0); duration: 80; easing: Easing.InQuart} + } + ] + onStateChanged: { + if (state == 'hidden') { + scrollpositon = scrollView.ScrollBar.vertical.position + scrollheight = scrollView.contentHeight + } + } + } + Grid { //Categories + id: appCategories + columns: 1 + width: scrollView.width - 10 * PlasmaCore.Units.devicePixelRatio + visible: opacity > 0 && main.showAllApps + Repeater { + id: categoriesRepeater + delegate: + GenericItem { + id: genericItemCat + triggerModel: categoriesRepeater.model + } + } + states: [ + State { + name: "hidden"; when: (currentStateIndex % 2 === 1) + PropertyChanges { target: appCategories; opacity: 0.0 } + PropertyChanges { target: appCategories; x: (isRight ? -20 * PlasmaCore.Units.devicePixelRatio : 0) } + }, + State { + name: "shown"; when: (currentStateIndex % 2 === 0) + PropertyChanges { target: appCategories; opacity: 1.0 } + PropertyChanges { target: appCategories; x: -10 * PlasmaCore.Units.devicePixelRatio } + }] + transitions: [ + Transition { + to: "hidden" + PropertyAnimation { properties: 'opacity'; duration: 80; easing: Easing.InQuart} + PropertyAnimation { properties: 'x'; from: -10 * PlasmaCore.Units.devicePixelRatio; duration: 80; easing: Easing.InQuart} + }, + Transition { + to: "shown" + PropertyAnimation { properties: 'opacity'; duration: 80; easing: Easing.InQuart} + PropertyAnimation { properties: 'x'; from: (isRight ? -20 * PlasmaCore.Units.devicePixelRatio : 0); duration: 80; easing: Easing.InQuart} + } + ] + onStateChanged: { + if (state == 'hidden') { + scrollpositon = scrollView.ScrollBar.vertical.position + scrollheight = scrollView.contentHeight + } + } + } + + Grid { //Categories + id: appCategories2 + columns: 1 + width: scrollView.width - 10 * PlasmaCore.Units.devicePixelRatio + visible: opacity > 0 && main.showAllApps + Repeater { + id: categoriesRepeater2 + delegate: + GenericItem { + id: genericItemCat2 + triggerModel: categoriesRepeater2.model + } + } + states: [ + State { + name: "hidden"; when: (currentStateIndex % 2 === 0) + PropertyChanges { target: appCategories2; opacity: 0.0 } + PropertyChanges { target: appCategories2; x: (isRight ? -20 * PlasmaCore.Units.devicePixelRatio : 0) } + }, + State { + name: "shown"; when: (currentStateIndex % 2 === 1) + PropertyChanges { target: appCategories2; opacity: 1.0 } + PropertyChanges { target: appCategories2; x: -10 * PlasmaCore.Units.devicePixelRatio} + }] + transitions: [ + Transition { + to: "hidden" + PropertyAnimation { properties: 'opacity'; duration: 80; easing: Easing.InQuart} + PropertyAnimation { properties: 'x'; from: -10 * PlasmaCore.Units.devicePixelRatio; duration: 80; easing: Easing.InQuart} + }, + Transition { + to: "shown" + PropertyAnimation { properties: 'opacity'; duration: 80; easing: Easing.InQuart} + PropertyAnimation { properties: 'x'; from: (isRight ? -20 * PlasmaCore.Units.devicePixelRatio : 0);duration: 80; easing: Easing.InQuart} + } + ] + onStateChanged: { + if (state == 'hidden') { + scrollpositon = scrollView.ScrollBar.vertical.position + scrollheight = scrollView.contentHeight + } + } + } + + Item { //Spacer + width: 1 + height: 20 * PlasmaCore.Units.devicePixelRatio + } + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/CompactRepresentation.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/CompactRepresentation.qml new file mode 100644 index 00000000..cd823eb7 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/CompactRepresentation.qml @@ -0,0 +1,101 @@ +/***************************************************************************** + * Copyright (C) 2013-2014 by Eike Hein * + * Copyright (C) 2021 by Prateek SU * + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 + +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore + +Item { + id: root + + property QtObject dashWindow: null + readonly property bool useCustomButtonImage: (plasmoid.configuration.useCustomButtonImage && plasmoid.configuration.customButtonImage.length != 0) + + PlasmaCore.IconItem { + id: buttonIcon + + width: plasmoid.configuration.activationIndicator ? parent.width * 0.65 : parent.width + height: plasmoid.configuration.activationIndicator ? parent.height * 0.65 : parent.height + anchors.centerIn: parent + + source: useCustomButtonImage ? plasmoid.configuration.customButtonImage : plasmoid.configuration.icon + + active: mouseArea.containsMouse + + smooth: true + + Rectangle { + id: indicator + width: 0 + anchors.horizontalCenter: parent.horizontalCenter + height: 3 * PlasmaCore.Units.devicePixelRatio + radius: 10 + y: parent.height + height + color: plasmoid.configuration.indicatorColor + visible: plasmoid.configuration.activationIndicator + + states: [ + State { name: "inactive" + when: !dashWindow.visible + PropertyChanges { + target: indicator + width: 0 + + } + }, + State { name: "active" + when: dashWindow.visible + PropertyChanges { + target: indicator + width: parent.width * 0.65 + } + } + ] + transitions: [ + Transition { + NumberAnimation { properties: 'width'; duration: 60} + } + ] + } + } + + MouseArea + { + id: mouseArea + + anchors.fill: parent + + hoverEnabled: true + + onClicked: { + dashWindow.visible = !dashWindow.visible; + } + } + + Component.onCompleted: { + dashWindow = Qt.createQmlObject("MenuRepresentation {}", root); + plasmoid.activated.connect(function() { + dashWindow.visible = !dashWindow.visible; + }); + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/ConfigGeneral.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/ConfigGeneral.qml new file mode 100644 index 00000000..f89a2aab --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/ConfigGeneral.qml @@ -0,0 +1,322 @@ +/***************************************************************************** + * Copyright (C) 2013-2014 by Eike Hein * + * Copyright (C) 2021 by Prateek SU * + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Controls 2.5 +import QtQuick.Dialogs 1.0 + +import org.kde.plasma.components 3.0 as PlasmaComponents +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons +import org.kde.draganddrop 2.0 as DragDrop +import org.kde.kirigami 2.3 as Kirigami + +import org.kde.plasma.private.kicker 0.1 as Kicker + +Kirigami.FormLayout { + id: configGeneral + + anchors.left: parent.left + anchors.right: parent.right + + property bool isDash: (plasmoid.pluginName === "org.kde.plasma.kickerdash") + + property string cfg_icon: plasmoid.configuration.icon + property bool cfg_useCustomButtonImage: plasmoid.configuration.useCustomButtonImage + property string cfg_customButtonImage: plasmoid.configuration.customButtonImage + property bool cfg_activationIndicator: plasmoid.configuration.activationIndicator + property color cfg_indicatorColor: plasmoid.configuration.indicatorColor + property bool cfg_enableGreeting: plasmoid.configuration.indicatorColor + property alias cfg_defaultPage: defaultPage.currentIndex + property alias cfg_theming: theming.currentIndex + property alias cfg_useExtraRunners: useExtraRunners.checked + property alias cfg_customGreeting: customGreeting.text + property alias cfg_floating: floating.checked + property alias cfg_launcherPosition: launcherPosition.currentIndex + property alias cfg_offsetX: screenOffset.value + property alias cfg_offsetY: panelOffset.value + + property alias cfg_enableGlow: enableGlowCheck.checked + property alias cfg_glowColor: glowColor.currentIndex + + Button { + id: iconButton + + Kirigami.FormData.label: i18n("Icon:") + + implicitWidth: previewFrame.width + units.smallSpacing * 2 + implicitHeight: previewFrame.height + units.smallSpacing * 2 + + // Just to provide some visual feedback when dragging; + // cannot have checked without checkable enabled + checkable: true + checked: dropArea.containsAcceptableDrag + + onPressed: iconMenu.opened ? iconMenu.close() : iconMenu.open() + + DragDrop.DropArea { + id: dropArea + + property bool containsAcceptableDrag: false + + anchors.fill: parent + + onDragEnter: { + // Cannot use string operations (e.g. indexOf()) on "url" basic type. + var urlString = event.mimeData.url.toString(); + + // This list is also hardcoded in KIconDialog. + var extensions = [".png", ".xpm", ".svg", ".svgz"]; + containsAcceptableDrag = urlString.indexOf("file:///") === 0 && extensions.some(function (extension) { + return urlString.indexOf(extension) === urlString.length - extension.length; // "endsWith" + }); + + if (!containsAcceptableDrag) { + event.ignore(); + } + } + onDragLeave: containsAcceptableDrag = false + + onDrop: { + if (containsAcceptableDrag) { + // Strip file:// prefix, we already verified in onDragEnter that we have only local URLs. + iconDialog.setCustomButtonImage(event.mimeData.url.toString().substr("file://".length)); + } + containsAcceptableDrag = false; + } + } + + KQuickAddons.IconDialog { + id: iconDialog + + function setCustomButtonImage(image) { + cfg_customButtonImage = image || cfg_icon || "start-here-kde" + cfg_useCustomButtonImage = true; + } + + onIconNameChanged: setCustomButtonImage(iconName); + } + + PlasmaCore.FrameSvgItem { + id: previewFrame + anchors.centerIn: parent + imagePath: plasmoid.location === PlasmaCore.Types.Vertical || plasmoid.location === PlasmaCore.Types.Horizontal + ? "widgets/panel-background" : "widgets/background" + width: units.iconSizes.large + fixedMargins.left + fixedMargins.right + height: units.iconSizes.large + fixedMargins.top + fixedMargins.bottom + + PlasmaCore.IconItem { + anchors.centerIn: parent + width: units.iconSizes.large + height: width + source: cfg_useCustomButtonImage ? cfg_customButtonImage : cfg_icon + } + } + + Menu { + id: iconMenu + + // Appear below the button + y: +parent.height + + onClosed: iconButton.checked = false; + + MenuItem { + text: i18nc("@item:inmenu Open icon chooser dialog", "Choose...") + icon.name: "document-open-folder" + onClicked: iconDialog.open() + } + MenuItem { + text: i18nc("@item:inmenu Reset icon to default", "Clear Icon") + icon.name: "edit-clear" + onClicked: { + cfg_icon = "start-here-kde" + cfg_useCustomButtonImage = false + } + } + } + } + CheckBox { + id: activationIndicatorCheck + Kirigami.FormData.label: i18n("Indicator:") + text: i18n("Enabled") + checked: plasmoid.configuration.activationIndicator + onCheckedChanged: { + plasmoid.configuration.activationIndicator = checked + cfg_activationIndicator = checked + } + } + Button { + id: colorButton + width: units.iconSizes.small + height: width + Kirigami.FormData.label: i18n("Indicator Color:") + + Rectangle { + anchors.centerIn: parent + anchors.fill: parent + radius: 10 + color: cfg_indicatorColor + } + onPressed: colorDialog.visible ? colorDialog.close() : colorDialog.open() + ColorDialog { + id: colorDialog + title: i18n("Please choose a color") + onAccepted: { + cfg_indicatorColor = colorDialog.color + } + } + } + Item { + Kirigami.FormData.isSection: true + } + CheckBox { + id: enableGreetingCheck + Kirigami.FormData.label: i18n("Greeting:") + text: i18n("Enabled") + checked: plasmoid.configuration.enableGreeting + onCheckedChanged: { + plasmoid.configuration.enableGreeting = checked + cfg_enableGreeting = checked + customGreeting.enabled = checked + } + } + TextField { + id: customGreeting + Kirigami.FormData.label: i18n("Custom Greeting Text:") + placeholderText: i18n("No custom greeting set") + } + Item { + Kirigami.FormData.isSection: true + } + CheckBox { + id: enableGlowCheck + Kirigami.FormData.label: i18n("Glow") + text: i18n("Enabled") + checked: plasmoid.configuration.enableGlow + onCheckedChanged: { + plasmoid.configuration.enableGlow = checked + } + } + ComboBox { + id: glowColor + Kirigami.FormData.label: i18n("Glow color:") + visible: plasmoid.configuration.enableGlow + model: [ + i18n("Purple (Default)"), + i18n("Blue"), + i18n("Red"), + ] + } + Item { + Kirigami.FormData.isSection: true + } + ComboBox { + id: launcherPosition + Kirigami.FormData.label: i18n("Launcher Positioning:") + model: [ + i18n("Default"), + i18n("Horizontal Center"), + i18n("Screen Center"), + ] + onCurrentIndexChanged: { + if (currentIndex == 2) { + floating.enabled = false + floating.checked = true + } else { + floating.enabled = true + } + } + } + CheckBox { + id: floating + text: i18n("Floating") + onCheckedChanged: { + screenOffset.visible = checked + panelOffset.visible = checked + } + } + Slider { + id: screenOffset + visible: plasmoid.configuration.floating + Kirigami.FormData.label: i18n("Offset Screen Edge (0 is Default):") + from: 0 + value: 0 + to: 100 + stepSize: 1 + PlasmaComponents.ToolTip { + text: screenOffset.value + } + } + Slider { + id: panelOffset + visible: plasmoid.configuration.floating + Kirigami.FormData.label: i18n("Offset Panel (0 is Default):") + from: 0 + value: 0 + to: 100 + stepSize: 1 + PlasmaComponents.ToolTip { + text: panelOffset.value + } + } + Item { + Kirigami.FormData.isSection: true + } + ComboBox { + id: defaultPage + Kirigami.FormData.label: i18n("Default Page:") + model: [ + i18n("All Applications (Default)"), + i18n("Developement"), + i18n("Games"), + i18n("Graphics"), + i18n("Internet"), + i18n("Multimedia"), + i18n("Office"), + i18n("Science & Math"), + i18n("Settings"), + i18n("System"), + i18n("Utilities"), + i18n("Lost & Found"), + ] + } + Item { + Kirigami.FormData.isSection: true + } + CheckBox { + id: useExtraRunners + Kirigami.FormData.label: i18n("Search:") + text: i18n("Expand search to bookmarks, files and emails") + } + Item { + Kirigami.FormData.isSection: true + } + ComboBox { + id: theming + Kirigami.FormData.label: i18n("Theming:") + model: [ + i18n("Dark (Default)"), + i18n("Light"), + i18n("Matching"), + ] + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/FavoriteItem.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/FavoriteItem.qml new file mode 100644 index 00000000..e9b4abd7 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/FavoriteItem.qml @@ -0,0 +1,211 @@ +/***************************************************************************** + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtGraphicalEffects 1.0 +import QtQuick.Window 2.2 +import org.kde.plasma.components 3.0 as PlasmaComponents +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.kcoreaddons 1.0 as KCoreAddons +import org.kde.kirigami 2.13 as Kirigami +import QtQuick.Controls 2.15 + +import "../code/tools.js" as Tools + +Item { + id: favItem + + property int iconSize: units.gridUnit * 3.2 + + width: Math.max(iconSize + units.largeSpacing * 2, appname.contentWidth) + 10 + height: iconSize + units.smallSpacing + appname.implicitHeight + 10 + + signal itemActivated(int index, string actionId, string argument) + + property bool highlighted: false + property bool isDraging: false + + property bool hasActionList: ((model.favoriteId !== null) + || (("hasActionList" in model) && (model.hasActionList === true))) + + + function openActionMenu(x, y) { + var actionList = hasActionList ? model.actionList : []; + console.log(model.favoriteId) + Tools.fillActionMenu(i18n, actionMenu, actionList, globalFavorites, model.favoriteId); + actionMenu.visualParent = favItem; + actionMenu.open(x, y); + } + + function actionTriggered(actionId, actionArgument) { + var close = (Tools.triggerAction(kicker.globalFavorites, index, actionId, actionArgument) === true); + if (close) { + root.toggle(); + } + } + + PlasmaCore.IconItem { + id: appicon + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + } + width: iconSize + height: iconSize + source: model.decoration + } + + PlasmaComponents.Label { + id: appname + text: ("name" in model ? model.name : model.display) + font.family: main.textFont + font.pixelSize: 14 * PlasmaCore.Units.devicePixelRatio + anchors { + top: appicon.bottom + topMargin: units.smallSpacing + left: parent.left + right: parent.right + } + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignTop + wrapMode: Text.WordWrap + } + + Rectangle { + id: rect + z: -20 + visible: !plasmoid.configuration.enableGlow + height: parent.height + width: parent.width + anchors.centerIn: parent + radius: 8 + + color: PlasmaCore.Theme.highlightColor + states: [ + State { + name: "highlight"; when: (highlighted) + PropertyChanges { target: rect; opacity: 0.3} + }, + State { + name: "default"; when: (!highlighted) + PropertyChanges { target: rect; opacity: 0} + } + ] + transitions: highlight + } + + DropShadow { + id:appIconGlow + visible: plasmoid.configuration.enableGlow + anchors.fill: appicon + cached: true + horizontalOffset: 0 + verticalOffset: 0 + radius: 15.0 + samples: 16 + color: main.glowColor1 + source: appicon + states: [ + State { + name: "highlight"; when: (highlighted) + PropertyChanges { target: appIconGlow; opacity: 1} + PropertyChanges { target: appNameGlow; opacity: 1} + }, + State { + name: "default"; when: (!highlighted) + PropertyChanges { target: appIconGlow; opacity: 0} + PropertyChanges { target: appNameGlow; opacity: 0} + } + ] + transitions: highlight + } + + DropShadow { + id: appNameGlow + visible: plasmoid.configuration.enableGlow + anchors.fill: appname + cached: true + horizontalOffset: 0 + verticalOffset: 0 + radius: 15.0 + samples: 16 + color: main.glowColor1 + source: appname + } + + MouseArea { + id: ma + anchors.fill: parent + z: parent.z + 1 + acceptedButtons: Qt.LeftButton | Qt.RightButton + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + onClicked: { + if (!isDraging) { + if (mouse.button == Qt.RightButton ) { + if (favItem.hasActionList) { + var mapped = mapToItem(favItem, mouse.x, mouse.y); + openActionMenu(mapped.x, mapped.y); + } + } else { + kicker.globalFavorites.trigger(index, "", null); + root.toggle() + } + } + } + onReleased: { + isDraging: false + } + onEntered: { + if(plasmoid.configuration.enableGlow) { + appIconGlow.state = "highlight" + } else { rect.state = "highlight" } + + } + onExited: { + if(plasmoid.configuration.enableGlow) { + appIconGlow.state = "default" + } else { rect.state = "default" } + } + onPositionChanged: { + isDraging = pressed + if (pressed){ + if ("pluginName" in model) { + dragHelper.startDrag(kicker, model.url, model.decoration, + "text/x-plasmoidservicename", model.pluginName); + } else { + dragHelper.startDrag(kicker, model.url, model.decoration); + } + } + } + } + ActionMenu { + id: actionMenu + + onActionClicked: { + visualParent.actionTriggered(actionId, actionArgument); + root.toggle() + } + } + Transition { + id: highlight + ColorAnimation {duration: 100 } + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/FloatingAvatar.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/FloatingAvatar.qml new file mode 100644 index 00000000..9a949b3a --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/FloatingAvatar.qml @@ -0,0 +1,99 @@ +/***************************************************************************** + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ +import QtQuick 2.12 +import QtQuick.Window 2.2 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.kirigami 2.13 as Kirigami +import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons + +PlasmaCore.Dialog { //cosmic background noise is less random than the placement of this dialog + id: avatarContainer + + property int avatarWidth + property bool isTop: false + + readonly property color borderGradientColor1: plasmoid.configuration.glowColor == 0 ? "#FEAC5E" : + plasmoid.configuration.glowColor == 1 ? "#a5fecb" : + "#ff005d" + readonly property color borderGradientColor2: plasmoid.configuration.glowColor == 0 ? "#C779D0" : + plasmoid.configuration.glowColor == 1 ? "#20bdff" : + "#ff005c" + readonly property color borderGradientColor3: plasmoid.configuration.glowColor == 0 ? "#4BC0C8" : + plasmoid.configuration.glowColor == 1 ? "#5433ff" : + "#ff8b26" + + type: "Notification" + + x: root.x + root.width / 2 - width / 2 + y: root.y - width / 2 //you can't even add 1 without everything breaking wtf + + mainItem: + Item { + onParentChanged: { + //This removes the dialog background + if (parent){ + var popupWindow = Window.window + if (typeof popupWindow.backgroundHints !== "undefined"){ + popupWindow.backgroundHints = PlasmaCore.Types.NoBackground + } + } + } + } + Item { + id: avatarFrame + anchors.centerIn: parent + width: avatarWidth + height: avatarWidth + Kirigami.Avatar { + id: mainFaceIcon + source: kuser.faceIconUrl + anchors { + fill: parent + margins: PlasmaCore.Units.smallSpacing + } + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: false + onClicked: { + KQuickAddons.KCMShell.openSystemSettings("kcm_users") + root.toggle() + } + } + } + + Rectangle { + visible: plasmoid.configuration.enableGlow + anchors.centerIn: mainFaceIcon + width: parent.width - 4 // Subtract to prevent fringing + height: width + radius: width / 2 + + gradient: Gradient { + GradientStop { position: 0.0; color: borderGradientColor1 } + GradientStop { position: 0.33; color: borderGradientColor2 } + GradientStop { position: 1.0; color: borderGradientColor3 } + } + + z:-1 + rotation: 270 + transformOrigin: Item.Center + } + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/GenericItem.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/GenericItem.qml new file mode 100644 index 00000000..c898d043 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/GenericItem.qml @@ -0,0 +1,193 @@ +/***************************************************************************** + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtGraphicalEffects 1.0 +import QtQuick.Window 2.2 +import org.kde.plasma.components 3.0 as PlasmaComponents +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.kcoreaddons 1.0 as KCoreAddons +import org.kde.kirigami 2.13 as Kirigami +import QtQuick.Controls 2.15 + +import "../code/tools.js" as Tools + +Item { + id: allItem + width: rect.width + 4 * PlasmaCore.Units.devicePixelRatio + height: rect.height + 4 * PlasmaCore.Units.devicePixelRatio + + property bool highlighted: false + property bool isDraging: false + property bool canDrag: true + property bool canNavigate: false + property bool isMouseHighlight: false + + property int subIndex: 0 + + signal highlightChanged + + property bool hasActionList: ((model.favoriteId !== null) + || (("hasActionList" in model) && (model.hasActionList === true))) + + property var triggerModel + + function openActionMenu(x, y) { + var actionList = hasActionList ? model.actionList : []; + Tools.fillActionMenu(i18n, actionMenu, actionList, globalFavorites, model.favoriteId); + actionMenu.visualParent = allItem; + actionMenu.open(x, y); + } + function actionTriggered(actionId, actionArgument) { + var close = (Tools.triggerAction(triggerModel, index, actionId, actionArgument) === true); + if (close) { + root.toggle(); + } + } + function trigger() { + triggerModel.trigger(index, "", null); + root.toggle() + } + function updateHighlight() { + if (navGrid.currentIndex == index){ + highlighted = true + } else { + highlighted = false + } + } + function deselect(){ + highlighted = false + listView.currentIndex = -1 + } + Item { + id: rect + x: 10 * PlasmaCore.Units.devicePixelRatio + y: 10 * PlasmaCore.Units.devicePixelRatio + width: main.width - 40 * PlasmaCore.Units.devicePixelRatio - allItem.x + height: 38 * PlasmaCore.Units.devicePixelRatio + + PlasmaCore.IconItem { + x: 9 * PlasmaCore.Units.devicePixelRatio + anchors.verticalCenter: rect.verticalCenter + id: appicon + width: 24 * PlasmaCore.Units.devicePixelRatio + height: width + source: model.decoration + PlasmaComponents.Label { + id: appname + x: appicon.width + 9 * PlasmaCore.Units.devicePixelRatio + anchors.verticalCenter: appicon.verticalCenter + text: ("name" in model ? model.name : model.display) + color: main.textColor + font.family: main.textFont + font.pixelSize: 12 * PlasmaCore.Units.devicePixelRatio + } + } + states: [ + State { + name: "highlight"; when: !canNavigate ? highlighted : runnerList.currentMainIndex == index && runnerList.currentSubIndex == subIndex + PropertyChanges { target: rectFill; opacity: 0.3} + PropertyChanges { target: appname; color: highlightedTextColor} + }, + State { + name: "default"; when: !canNavigate ? !highlighted : runnerList.currentMainIndex != index || runnerList.currentSubIndex != subIndex + PropertyChanges { target: rectFill; opacity: 0} + PropertyChanges { target: appname; color: textColor} + }] + transitions: highlight + onStateChanged: { + if (state == 'default'){ + isMouseHighlight = false + } + } + } + + Rectangle { + id: rectFill + color: PlasmaCore.Theme.highlightColor + radius: 6 + z: -20 + anchors.fill: rect + } + + MouseArea { + id: ma + anchors.fill: parent + z: parent.z + 1 + acceptedButtons: Qt.LeftButton | Qt.RightButton + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + onClicked: { + if (!isDraging) { + if (mouse.button == Qt.RightButton) { + if (allItem.hasActionList) { + var mapped = mapToItem(allItem, mouse.x, mouse.y); + openActionMenu(mapped.x, mapped.y); + } + } else { + trigger() + } + } + } + onReleased: { + isDraging: false + } + onExited: { + rect.state = "default" + isMouseHighlight = false + } + onPositionChanged: { + isDraging = pressed + if (pressed && canDrag){ + if ("pluginName" in model) { + dragHelper.startDrag(kicker, model.url, model.decoration, + "text/x-plasmoidservicename", model.pluginName); + } else { + dragHelper.startDrag(kicker, model.url, model.decoration); + } + } + if (containsMouse) { + isMouseHighlight = true + rect.state = "highlight" + if (canNavigate) { + if (runnerList.currentSubIndex != subIndex) { + repeater.itemAt(runnerList.currentSubIndex).nGrid.currentIndex = -1 + } + runnerList.currentSubIndex = subIndex + runnerList.currentMainIndex = index + listView.currentIndex = index + listView.focus = true + } + } + } + } + ActionMenu { + id: actionMenu + + onActionClicked: { + visualParent.actionTriggered(actionId, actionArgument); + root.toggle() + } + } + Transition { + id: highlight + ColorAnimation {duration: 100 } + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/Header.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/Header.qml new file mode 100644 index 00000000..73d0ce8b --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/Header.qml @@ -0,0 +1,95 @@ +/***************************************************************************** + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ +import org.kde.plasma.components 3.0 as PlasmaComponents +import org.kde.plasma.core 2.0 as PlasmaCore +import QtQuick.Controls 2.5 +import QtQuick 2.0 +import QtQuick.Window 2.2 +import QtGraphicalEffects 1.0 +import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons + +Item { + property var iconSize + width: iconSize * 3.75 + height: iconSize + PlasmaComponents.RoundButton { + id: settingsButton + visible: true + flat: true + height: iconSize * 2 + width: height + anchors.left: parent.left + + PlasmaComponents.ToolTip { + text: i18n("Settings") + } + Item { + id: visualParentSettings + y: 2 * iconSize + } + Image { + id: settingsImage + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + source: "icons/feather/settings.svg" + width: iconSize + height: width + ColorOverlay { + visible: plasmoid.configuration.theming != 0 + anchors.fill: settingsImage + source: settingsImage + color: main.textColor + } + } + onClicked: { + KQuickAddons.KCMShell.openSystemSettings("kcm_quick") + root.toggle() + //plasmoid.action("configure").trigger() //might implement later + } + } + PlasmaComponents.RoundButton { + id: powerOffButton + visible: true + flat: true + height: iconSize * 2 + width: height + anchors.right: parent.right + + PlasmaComponents.ToolTip { + text: i18n("Power Off") + } + Image { + id: powerImage + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + source: "icons/feather/power.svg" + width: iconSize + height: width + ColorOverlay { + visible: plasmoid.configuration.theming != 0 + anchors.fill: powerImage + source: powerImage + color: main.textColor + } + } + onClicked: { + pmEngine.performOperation("requestShutDown") + } + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/MainView.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/MainView.qml new file mode 100644 index 00000000..eaa1f5d3 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/MainView.qml @@ -0,0 +1,431 @@ +/***************************************************************************** + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ +import QtQuick 2.15 +import QtQuick.Layouts 1.12 +import QtGraphicalEffects 1.12 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 3.0 as PlasmaComponents +import org.kde.kcoreaddons 1.0 as KCoreAddons + +Item { + id: main + anchors.fill: parent + property bool searching: (searchBar.text != "") + signal newTextQuery(string text) + + readonly property color textColor: PlasmaCore.Theme.textColor + readonly property string textFont: "SF Pro Text" + readonly property color bgColor: PlasmaCore.Theme.backgroundColor + readonly property color highlightColor: PlasmaCore.Theme.highlightColor + readonly property color highlightedTextColor: PlasmaCore.Theme.highlightedTextColor + readonly property bool isTop: plasmoid.location == PlasmaCore.Types.TopEdge & plasmoid.configuration.launcherPosition != 2 & !plasmoid.configuration.floating + + readonly property color glowColor1: plasmoid.configuration.glowColor == 0 ? "#D300DC" : + plasmoid.configuration.glowColor == 1 ? "#20bdff" : + "#ff005d" + readonly property color glowColor2: plasmoid.configuration.glowColor == 0 ? "#8700FF" : + plasmoid.configuration.glowColor == 1 ? "#5433ff" : + "#ff8b26" + + property bool showAllApps: false + + KCoreAddons.KUser { + id: kuser + } + + PlasmaCore.DataSource { + id: pmEngine + engine: "powermanagement" + connectedSources: ["PowerDevil", "Sleep States"] + function performOperation(what) { + var service = serviceForSource("PowerDevil") + var operation = service.operationDescription(what) + service.startOperationCall(operation) + } + } + + function updateStartpage(){ + appList.currentStateIndex = plasmoid.configuration.defaultPage + } + + function reload() { + searchBar.clear() + searchBar.focus = true + appList.reset() + } + function reset(){ + searchBar.clear() + searchBar.focus = true + appList.reset() + } + + Rectangle { + id: backdrop + x: 0 + y: isTop ? 0 : 125 * PlasmaCore.Units.devicePixelRatio + width: main.width + height: isTop ? main.height - 200 * PlasmaCore.Units.devicePixelRatio : main.height - y - (searchBarContainer.height + 20) + color: bgColor + opacity: 0 + } + //Floating Avatar + Item { + id: avatarParent + x: main.width / 2 + y: - root.margins.top + FloatingAvatar { //Anyone looking for an unpredictable number generator? + id: floatingAvatar + //visualParent: root + isTop: main.isTop + avatarWidth: 125 * PlasmaCore.Units.devicePixelRatio + visible: root.visible && !isTop ? true : root.visible && plasmoid.configuration.floating ? true : false + } + } + //Power & Settings + Item { + Header { + id: powerSettings + x: main.width - width - iconSize / 2 + y: isTop ? main.height - 2 * height - iconSize / 2 : iconSize / 2 + iconSize: 20 * PlasmaCore.Units.devicePixelRatio + } + } + //Greeting + Item { + id: greeting + Text { + id: nameLabel + x: main.width / 2 - width / 2 //This centeres the Text + y: isTop ? main.height - height - 135 * PlasmaCore.Units.devicePixelRatio : 70 * PlasmaCore.Units.devicePixelRatio + text: plasmoid.configuration.enableGreeting && plasmoid.configuration.customGreeting ? plasmoid.configuration.customGreeting : plasmoid.configuration.enableGreeting ? 'Hi, ' + kuser.fullName : i18n("%1@%2", kuser.loginName, kuser.host) + color: textColor + font.family: textFont + font.pixelSize: 25 * PlasmaCore.Units.devicePixelRatio + font.bold: true + } + // Text shadow for greeting label + DropShadow { + anchors.fill: nameLabel + cached: true + horizontalOffset: 0 + verticalOffset: 0 + radius: 10.0 + samples: 16 + color: glowColor1 + source: nameLabel + visible: plasmoid.configuration.enableGlow + } + } + //Searchbar + Item { + Rectangle { + id: searchBarContainer + x: headerLabel.width * PlasmaCore.Units.devicePixelRatio + y: isTop ? main.height - height - (2 * powerSettings.height + powerSettings.iconSize / 2) - 10 * PlasmaCore.Units.devicePixelRatio : main.height - (height + x) * PlasmaCore.Units.devicePixelRatio + width: main.width - 2 * x + height: 45 * PlasmaCore.Units.devicePixelRatio + radius: 8 + color: Qt.lighter(theme.backgroundColor) // better contrast color + Image { + id: searchIcon + x: 15 * PlasmaCore.Units.devicePixelRatio + width: 15 * PlasmaCore.Units.devicePixelRatio + height: width + anchors.verticalCenter: parent.verticalCenter + source: 'icons/feather/search.svg' + ColorOverlay { + visible: true + anchors.fill: searchIcon + source: searchIcon + color: main.textColor + } + } + Rectangle { + x: 45 * PlasmaCore.Units.devicePixelRatio + width: parent.width - 60 * PlasmaCore.Units.devicePixelRatio + height: searchBar.height + anchors.verticalCenter: parent.verticalCenter + clip: true + color: 'transparent' + MouseArea { + anchors.fill: parent + cursorShape: Qt.IBeamCursor + hoverEnabled: false + } + TextInput { + id: searchBar + width: parent.width + anchors.verticalCenter: parent.verticalCenter + focus: true + color: textColor + selectByMouse: true + selectionColor: highlightedTextColor + font.family: textFont + font.pixelSize: 13 * PlasmaCore.Units.devicePixelRatio + Text { + anchors.fill: parent + text: i18n("Search your computer") + color: PlasmaCore.Theme.disabledTextColor + visible: !parent.text + } + onTextChanged: { + runnerModel.query = text; + newTextQuery(text) + } + function clear() { + text = ""; + } + function backspace() { + if (searching) { + text = text.slice(0, -1); + } + focus = true; + } + function appendText(newText) { + if (!root.visible) { + return; + } + focus = true; + text = text + newText; + } + Keys.onPressed: { + if (event.key == Qt.Key_Down) { + event.accepted = true; + runnerList.setFocus() + } else if (event.key == Qt.Key_Tab || event.key == Qt.Key_Up) { + event.accepted = true; + runnerList.setFocus() + } else if (event.key == Qt.Key_Escape) { + event.accepted = true; + if (searching) { + clear() + } else { + root.toggle() + } + } else if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + runnerList.setFocus() + runnerList.triggerFirst() + } + } + } + } + } + } + + // Fvorites / All apps label + Image { + id: headerLabel + source: "icons/feather/star.svg" + width: 15 + height: width + y: backdrop.y + width + anchors.leftMargin: units.largeSpacing + anchors.topMargin: units.largeSpacing + anchors.left: parent.left + + PlasmaComponents.Label { + id: mainLabelGrid + x: parent.width + 10 + anchors.verticalCenter: parent.verticalCenter + text: i18n(showAllApps ? "All apps" : "Favorite Apps") + font.family: "SF Pro Text" + font.pixelSize: 12 + } + + ColorOverlay { + visible: true + anchors.fill: headerLabel + source: headerLabel + color: main.textColor + } + } + // Show all app buttons + PlasmaComponents.Button { + MouseArea { + hoverEnabled: true + anchors.fill: parent + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + onClicked: showAllApps = !showAllApps + } + text: i18n(showAllApps ? "Back" : "All apps") + id: mainsecLabelGrid + icon.name: showAllApps ? "go-previous" : "go-next" + font.pointSize: 9 + icon.height: 15 + icon.width: icon.height + LayoutMirroring.enabled: true + LayoutMirroring.childrenInherit: !showAllApps + flat: false + background: Rectangle { + color: Qt.lighter(theme.backgroundColor) + border.width: 1 + border.color: Qt.darker(theme.backgroundColor, 1.14) + radius: plasmoid.configuration.enableGlow ? height / 2 : 5 + + Rectangle { + id: bgMask + width: parent.width + height: parent.height + radius: height / 2 + border.width: 0 + visible: plasmoid.configuration.enableGlow + } + Item { + visible: plasmoid.configuration.enableGlow + anchors.fill: bgMask + // x: container.x - 20 + layer.enabled: true + layer.effect: OpacityMask { + maskSource: bgMask + } + + LinearGradient { + anchors.fill: parent + start: Qt.point(bgMask.width, 0) + end: Qt.point(0, bgMask.height) + gradient: Gradient { + GradientStop { position: 0.0; color: glowColor1 } + GradientStop { position: 1.0; color: glowColor2 } + } + } + } + + } + topPadding: 4 + bottomPadding: topPadding + leftPadding: 8 + rightPadding: 8 + icon{ + width: height + height: visible ? units.iconSizes.small : 0 + name: showAllApps ? "go-previous" : "go-next" + } + + anchors { + topMargin: units.smallSpacing + verticalCenter: headerLabel.verticalCenter + rightMargin: units.largeSpacing + leftMargin: units.largeSpacing + left: parent.left + } + x: -units.smallSpacing + visible: !searching + } + // All apps button shadow + DropShadow { + anchors.fill: mainsecLabelGrid + cached: true + horizontalOffset: 0 + verticalOffset: 0 + radius: 11.0 + samples: 16 + color: glowColor1 + source: mainsecLabelGrid + visible: plasmoid.configuration.enableGlow + } + + //List of Apps + AppList { + id: appList + state: "visible" + anchors.top: headerLabel.bottom + anchors.topMargin: showAllApps ? headerLabel.width : headerLabel.width * 2 + width: main.width - 30 * PlasmaCore.Units.devicePixelRatio + height: showAllApps ? backdrop.height - (headerLabel.height * 3.5) : main.height - y + visible: opacity > 0 + states: [ + State { + name: "visible"; when: (!searching) + PropertyChanges { target: appList; opacity: 1.0 } + PropertyChanges { target: appList; x: 25 * PlasmaCore.Units.devicePixelRatio } + }, + State { + name: "hidden"; when: (searching) + PropertyChanges { target: appList; opacity: 0.0} + PropertyChanges { target: appList; x: 5 * PlasmaCore.Units.devicePixelRatio} + }] + transitions: [ + Transition { + to: "visible" + PropertyAnimation {properties: 'opacity'; duration: 100; easing.type: Easing.OutQuart} + PropertyAnimation {properties: 'x'; from: 5 * PlasmaCore.Units.devicePixelRatio; duration: 100; easing.type: Easing.OutQuart} + }, + Transition { + to: "hidden" + PropertyAnimation {properties: 'opacity'; duration: 100; easing.type: Easing.OutQuart} + PropertyAnimation {properties: 'x'; from: 25 * PlasmaCore.Units.devicePixelRatio; duration: 100; easing.type: Easing.OutQuart} + } + ] + } + RunnerList { + id: runnerList + model: runnerModel + state: "hidden" + visible: opacity > 0 + anchors.top: headerLabel.bottom + anchors.topMargin: headerLabel.width + width: main.width - 30 * PlasmaCore.Units.devicePixelRatio + height: backdrop.height - (headerLabel.height * 3.5) + states: [ + State { + name: "visible"; when: (searching) + PropertyChanges { target: runnerList; opacity: 1.0 } + PropertyChanges { target: runnerList; x: 20 * PlasmaCore.Units.devicePixelRatio} + }, + State { + name: "hidden"; when: (!searching) + PropertyChanges { target: runnerList; opacity: 0.0} + PropertyChanges { target: runnerList; x: 40 * PlasmaCore.Units.devicePixelRatio} + }] + transitions: [ + Transition { + to: "visible" + PropertyAnimation {properties: 'opacity'; duration: 100; easing.type: Easing.OutQuart} + PropertyAnimation {properties: 'x'; from: 80 * PlasmaCore.Units.devicePixelRatio; duration: 100; easing.type: Easing.OutQuart} + }, + Transition { + to: "hidden" + PropertyAnimation {properties: 'opacity'; duration: 100; easing.type: Easing.OutQuart} + PropertyAnimation {properties: 'x'; from: 20 * PlasmaCore.Units.devicePixelRatio; duration: 100; easing.type: Easing.OutQuart} + } + ] + } + + Keys.onPressed: { + if (event.key == Qt.Key_Backspace) { + event.accepted = true; + if (searching) + searchBar.backspace(); + else + searchBar.focus = true + } else if (event.key == Qt.Key_Escape) { + event.accepted = true; + if (searching) { + searchBar.clear() + } else { + root.toggle() + } + } else if (event.text != "" || event.key == Qt.Key_Down) { + if (event.key != Qt.Key_Return){ + event.accepted = true; + searchBar.appendText(event.text); + } + } + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/MenuRepresentation.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/MenuRepresentation.qml new file mode 100644 index 00000000..de390b06 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/MenuRepresentation.qml @@ -0,0 +1,166 @@ +/***************************************************************************** + * Copyright (C) 2014 by Weng Xuetian * + * Copyright (C) 2013-2017 by Eike Hein * + * Copyright (C) 2021 by Prateek SU * + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 3.0 as PlasmaComponents + +PlasmaCore.Dialog { + id: root + + objectName: "popupWindow" + flags: Qt.WindowStaysOnTopHint + + location: plasmoid.configuration.floating || plasmoid.configuration.launcherPosition == 2 ? "Floating" : plasmoid.location + + hideOnWindowDeactivate: true + + onVisibleChanged: { + if (!visible) { + reset(); + } else { + main.updateStartpage() + var pos = popupPosition(width, height); + x = pos.x; + y = pos.y; + requestActivate(); + } + } + + onHeightChanged: { + var pos = popupPosition(width, height); + x = pos.x; + y = pos.y; + } + + onWidthChanged: { + var pos = popupPosition(width, height); + x = pos.x; + y = pos.y; + } + + function toggle() { + root.visible = false; + } + + function reset() { + main.reset() + } + + function popupPosition(width, height) { + var screenAvail = plasmoid.availableScreenRect; + var screen/*Geom*/ = plasmoid.screenGeometry; + //QtBug - QTBUG-64115 + /*var screen = Qt.rect(screenAvail.x + screenGeom.x, + screenAvail.y + screenGeom.y, + screenAvail.width, + screenAvail.height);*/ + + var offset = 0 + + if (plasmoid.configuration.offsetX > 0 && plasmoid.configuration.floating) { + offset = plasmoid.configuration.offsetX + } else { + offset = plasmoid.configuration.floating ? parent.height * 0.75 : 0 + } + // Fall back to bottom-left of screen area when the applet is on the desktop or floating. + var x = offset; + var y = screen.height - height - offset; + var horizMidPoint = screen.x + (screen.width / 2); + var vertMidPoint = screen.y + (screen.height / 2); + var appletTopLeft = parent.mapToGlobal(0, 0); + var appletBottomLeft = parent.mapToGlobal(0, parent.height); + + if (plasmoid.configuration.launcherPosition != 0){ + x = horizMidPoint - width / 2; + } else { + x = (appletTopLeft.x < horizMidPoint) ? screen.x : (screen.x + screen.width) - width; + if (plasmoid.configuration.floating) { + if (appletTopLeft.x < horizMidPoint) { + x += offset + } else if (appletTopLeft.x + width > horizMidPoint){ + x -= offset + } + } + } + + if (plasmoid.configuration.launcherPosition != 2){ + if (plasmoid.location == PlasmaCore.Types.TopEdge) { + if (plasmoid.configuration.floating) { + /*this is floatingAvatar.width*/ + if (plasmoid.configuration.offsetY > 0) { + offset = (125 * PlasmaCore.Units.devicePixelRatio) / 2 + plasmoid.configuration.offsetY + } else { + offset = (125 * PlasmaCore.Units.devicePixelRatio) / 2 + parent.height * 0.125 + } + } + y = screen.y + parent.height + panelSvg.margins.bottom + offset; + } else { + if (plasmoid.configuration.offsetY > 0) { + offset = plasmoid.configuration.offsetY + } + y = screen.y + screen.height - parent.height - height - panelSvg.margins.top - offset; + } + } else { + y = vertMidPoint - height / 2 + } + + return Qt.point(x, y); + } + + FocusScope { + id: fs + focus: true + Layout.minimumWidth: 600 * PlasmaCore.Units.devicePixelRatio + Layout.minimumHeight: 550 * PlasmaCore.Units.devicePixelRatio + Layout.maximumWidth: Layout.minimumWidth + Layout.maximumHeight: Layout.minimumHeight + + Item { + x: - root.margins.left + y: - root.margins.top + width: parent.width + root.margins.left + root.margins.right + height: parent.height + root.margins.top + root.margins.bottom + + MainView { + id: main + } + } + + Keys.onPressed: { + if (event.key == Qt.Key_Escape) { + root.visible = false; + } + } + } + + function refreshModel() { + main.reload() + } + + Component.onCompleted: { + rootModel.refreshed.connect(refreshModel) + kicker.reset.connect(reset); + reset(); + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/NavGrid.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/NavGrid.qml new file mode 100644 index 00000000..bb93c81d --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/NavGrid.qml @@ -0,0 +1,140 @@ +/***************************************************************************** + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ +import QtQuick 2.12 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtras +import org.kde.kquickcontrolsaddons 2.0 + +import org.kde.draganddrop 2.0 + +FocusScope { + id: navGrid + + signal keyNavUp + signal keyNavDown + + property alias triggerModel: listView.model + property alias count: listView.count + property alias currentIndex: listView.currentIndex + property alias currentItem: listView.currentItem + property alias contentItem: listView.contentItem + + property int subIndex: 0 + + onFocusChanged: { + if (!focus) { + currentIndex = -1; + } + } + function setFocus() { + currentIndex = 0 + focus = true + runnerList.currentMainIndex = currentIndex + } + function setFocusLast() { + if (count > 0) { + currentIndex = count - 1 + focus = true + runnerList.currentMainIndex = currentIndex + } else { + setFocus() + } + } + + Component { + id: genericItem + GenericItem { + x: 20 + canNavigate: true + canDrag: false + triggerModel: listView.model + subIndex: navGrid.subIndex + } + } + + PlasmaExtras.ScrollArea { + id: scrollArea + + anchors.fill: parent + focus: true + + ListView { + id: listView + currentIndex: -1 + focus: true + keyNavigationEnabled: true + highlightFollowsCurrentItem: true + highlightMoveDuration: 0 + + delegate: genericItem + + onCurrentIndexChanged: { + if (currentIndex != -1) { + focus = true; + } + } + onModelChanged: { + currentIndex = -1; + } + onFocusChanged: { + if (!focus) { + currentIndex = -1 + } + } + Keys.onUpPressed: { + if (runnerList.currentSubIndex != subIndex) { + repeater.itemAt(runnerList.currentSubIndex).nGrid.currentIndex = -1 + } + if (currentIndex > 0) { + event.accepted = true; + currentIndex = currentIndex - 1 + runnerList.currentMainIndex = currentIndex + runnerList.currentSubIndex = subIndex + positionViewAtIndex(currentIndex, ListView.Contain); + } else { + navGrid.keyNavUp(); + } + } + Keys.onDownPressed: { + if (runnerList.currentSubIndex != subIndex) { + repeater.itemAt(runnerList.currentSubIndex).nGrid.currentIndex = -1 + } + if (currentIndex < count - 1) { + event.accepted = true; + currentIndex = currentIndex + 1; + runnerList.currentMainIndex = currentIndex + runnerList.currentSubIndex = subIndex + positionViewAtIndex(currentIndex, ListView.Contain); + } else { + navGrid.keyNavDown(); + } + } + Keys.onPressed: { + if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + event.accepted = true; + if (currentItem){ + currentItem.trigger() + } + } + } + } + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/RunnerList.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/RunnerList.qml new file mode 100644 index 00000000..8a56ab50 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/RunnerList.qml @@ -0,0 +1,198 @@ +/***************************************************************************** + * Copyright (C) 2022 by Friedrich Schriewer * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ****************************************************************************/ + +import QtQuick 2.12 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.extras 2.0 as PlasmaExtras + +import org.kde.plasma.private.kicker 0.1 as Kicker + +import QtQuick.Window 2.2 +import org.kde.plasma.components 3.0 as PlasmaComponents +import QtQuick.Layouts 1.15 +import QtQuick.Controls 2.15 + +import QtGraphicalEffects 1.0 + +PlasmaExtras.ScrollArea { + id: runnerList + focus: true + property alias model: repeater.model + property alias count: repeater.count + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + verticalScrollBarPolicy: Qt.ScrollBarAsNeeded + + property int currentMainIndex: 0 + property int currentSubIndex: 0 + + onFocusChanged: { + if (!focus) { + for (var i = 0; i < repeater.count; i++) { + repeater.itemAt(i).nGrid.focus = false + } + } else { + currentMainIndex = 0 + for (var i = 0; i < repeater.count; ++i) { + if (repeater.itemAt(i).nGrid.count > 0) { + currentSubIndex = i + repeater.itemAt(i).nGrid.setFocus(); + break + } + } + } + } + + function get_position(){ + return flickableItem.contentY / (flickableItem.contentHeight - height) + } + function get_size(){ + return (flickableItem.contentHeight <= height ? -1 : 0.99999) + } + function setFocus() { + currentMainIndex = 0 + for (var i = 0; i < repeater.count; ++i) { + if (repeater.itemAt(i).nGrid.count > 0) { + currentSubIndex = i + repeater.itemAt(i).nGrid.setFocus(); + break + } + } + } + function triggerFirst(){ + repeater.itemAt(currentSubIndex).nGrid.currentItem.trigger() + } + + Column { + x: -10 * PlasmaCore.Units.devicePixelRatio + Repeater { + id: repeater + delegate: + Item { + id: section + width: runnerList.width + height: headerLabel.height + navGrid.height + (index == repeater.count - 1 ? 0 : 10) + visible: navGrid.count > 0 + property Item nGrid: navGrid + Item { + id: headerLabel + anchors.top: parent.top + height: image.height + Image { + id: image + x: 20 * PlasmaCore.Units.devicePixelRatio + source: repeater.model.modelForRow(index).description === 'Command Line' ? "icons/feather/code.svg" : repeater.model.modelForRow(index).description == 'Desktop Search' ? "icons/feather/search.svg" : "icons/feather/file-text.svg" + width: 15 * PlasmaCore.Units.devicePixelRatio + height: width + //visible: repeater.model.modelForRow(index).count > 0 + PlasmaComponents.Label { + x: parent.width + 10 * PlasmaCore.Units.devicePixelRatio + anchors.verticalCenter: parent.verticalCenter + text: repeater.model.modelForRow(index).description + color: main.textColor + font.family: main.textFont + font.pixelSize: 12 * PlasmaCore.Units.devicePixelRatio + } + ColorOverlay { + visible: plasmoid.configuration.theming != 0 + anchors.fill: image + source: image + color: main.textColor + } + } + } + NavGrid { + id: navGrid + width: runnerList.width + height: Math.ceil(count * (42 * PlasmaCore.Units.devicePixelRatio )) + 10 * PlasmaCore.Units.devicePixelRatio + anchors.top: headerLabel.bottom + subIndex: index + triggerModel: repeater.model.modelForRow(index) + + onFocusChanged: { + if (focus) { + runnerList.focus = true; + } + } + onCountChanged: { + if (index == 0 && count > 0) { + currentIndex = 0; + focus = true; + } + } + onCurrentItemChanged: { + if (!currentItem) { + return; + } + if (currentItem.isMouseHighlight) { + return + } + if (index == 0 && currentIndex === 0) { + runnerList.flickableItem.contentY = 0; + return; + } + var y = currentItem.y; + y = contentItem.mapToItem(runnerList.flickableItem.contentItem, 0, y).y; + + if (y < runnerList.flickableItem.contentY) { + runnerList.flickableItem.contentY = y; + } else { + y += currentItem.height + 10 * PlasmaCore.Units.devicePixelRatio + 15 * PlasmaCore.Units.devicePixelRatio; + y -= runnerList.flickableItem.contentY; + y -= runnerList.viewport.height; + + if (y > 0) { + runnerList.flickableItem.contentY += y; + } + } + } + onKeyNavUp: { + if (index > 0) { + for (var i = index - 1; i > -1; --i) { + if (repeater.itemAt(i).nGrid.count > 0) { + repeater.itemAt(i).nGrid.setFocusLast() + currentSubIndex = index - 1 + break + } + } + } + } + + onKeyNavDown: { + if (index < repeater.count - 1) { + for (var i = index + 1; i < repeater.count; ++i) { + if (repeater.itemAt(i).nGrid.count > 0) { + repeater.itemAt(i).nGrid.setFocus() + currentSubIndex = index + 1 + break + } + } + } + } + } + Kicker.WheelInterceptor { + anchors.fill: navGrid + z: 1 + destination: findWheelArea(runnerList.flickableItem) + } + } + } + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/LICENSE b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/LICENSE new file mode 100644 index 00000000..b869713b --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2017 Cole Bemis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/code.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/code.svg new file mode 100644 index 00000000..3e718ae9 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/code.svg @@ -0,0 +1,48 @@ + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/file-text.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/file-text.svg new file mode 100644 index 00000000..5aa61d5f --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/file-text.svg @@ -0,0 +1,66 @@ + + + + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/globe.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/globe.svg new file mode 100644 index 00000000..aeec3e8b --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/globe.svg @@ -0,0 +1,57 @@ + + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/image.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/image.svg new file mode 100644 index 00000000..0b22c3f5 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/image.svg @@ -0,0 +1,59 @@ + + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/power.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/power.svg new file mode 100644 index 00000000..6773a703 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/power.svg @@ -0,0 +1,51 @@ + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/search.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/search.svg new file mode 100644 index 00000000..95df9e62 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/search.svg @@ -0,0 +1,53 @@ + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/settings.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/settings.svg new file mode 100644 index 00000000..fb7effea --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/settings.svg @@ -0,0 +1,50 @@ + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/star.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/star.svg new file mode 100644 index 00000000..ed8af3f0 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/star.svg @@ -0,0 +1,44 @@ + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/tool.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/tool.svg new file mode 100644 index 00000000..6790dc4a --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/tool.svg @@ -0,0 +1,44 @@ + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/trash-2.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/trash-2.svg new file mode 100644 index 00000000..7e808769 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/feather/trash-2.svg @@ -0,0 +1,62 @@ + + + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/LICENSE b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/LICENSE new file mode 100644 index 00000000..66cc0220 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2020, Lucide Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/cpu.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/cpu.svg new file mode 100644 index 00000000..fb452299 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/cpu.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/film.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/film.svg new file mode 100644 index 00000000..a4625490 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/film.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/flask-conical.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/flask-conical.svg new file mode 100644 index 00000000..a405ff4d --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/flask-conical.svg @@ -0,0 +1,51 @@ + + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/gamepad-2.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/gamepad-2.svg new file mode 100644 index 00000000..49e4da52 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/gamepad-2.svg @@ -0,0 +1,49 @@ + + + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/paperclip.svg b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/paperclip.svg new file mode 100644 index 00000000..3446bb5e --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/icons/lucide/paperclip.svg @@ -0,0 +1,43 @@ + + + + + + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/main.qml b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/main.qml new file mode 100644 index 00000000..96d2aa8a --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/contents/ui/main.qml @@ -0,0 +1,219 @@ +/*************************************************************************** + * Copyright (C) 2014-2015 by Eike Hein * + * Copyright (C) 2021 by Prateek SU * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import org.kde.plasma.plasmoid 2.0 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 3.0 as PlasmaComponents + +import org.kde.plasma.private.kicker 0.1 as Kicker + +Item { + id: kicker + + anchors.fill: parent + + signal reset + + property bool isDash: false + + Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation + + Plasmoid.compactRepresentation: null + Plasmoid.fullRepresentation: compactRepresentation + + property Item dragSource: null + + property QtObject globalFavorites: rootModel.favoritesModel + property QtObject systemFavorites: rootModel.systemFavoritesModel + + function action_menuedit() { + processRunner.runMenuEditor(); + } + + Component { + id: compactRepresentation + CompactRepresentation { } + } + + Component { + id: menuRepresentation + MenuRepresentation { } + } + + Kicker.RootModel { + id: rootModel + + autoPopulate: false + + appNameFormat: plasmoid.configuration.appNameFormat + flat: true + sorted: true + showSeparators: false + appletInterface: plasmoid + + showAllApps: true + showAllAppsCategorized: true + showTopLevelItems: !isDash + showRecentApps: plasmoid.configuration.showRecentApps + showRecentDocs: plasmoid.configuration.showRecentDocs + showRecentContacts: plasmoid.configuration.showRecentContacts + recentOrdering: plasmoid.configuration.recentOrdering + + onShowRecentAppsChanged: { + plasmoid.configuration.showRecentApps = showRecentApps; + } + + onShowRecentDocsChanged: { + plasmoid.configuration.showRecentDocs = showRecentDocs; + } + + onShowRecentContactsChanged: { + plasmoid.configuration.showRecentContacts = showRecentContacts; + } + + onRecentOrderingChanged: { + plasmoid.configuration.recentOrdering = recentOrdering; + } + + onFavoritesModelChanged: { + if ("initForClient" in favoritesModel) { + favoritesModel.initForClient("org.kde.plasma.kicker.favorites.instance-" + plasmoid.id) + + if (!plasmoid.configuration.favoritesPortedToKAstats) { + favoritesModel.portOldFavorites(plasmoid.configuration.favoriteApps); + plasmoid.configuration.favoritesPortedToKAstats = true; + } + } else { + favoritesModel.favorites = plasmoid.configuration.favoriteApps; + } + + favoritesModel.maxFavorites = pageSize; + } + + onSystemFavoritesModelChanged: { + systemFavoritesModel.enabled = false; + systemFavoritesModel.favorites = plasmoid.configuration.favoriteSystemActions; + systemFavoritesModel.maxFavorites = 6; + } + + Component.onCompleted: { + if ("initForClient" in favoritesModel) { + favoritesModel.initForClient("org.kde.plasma.kicker.favorites.instance-" + plasmoid.id) + + if (!plasmoid.configuration.favoritesPortedToKAstats) { + favoritesModel.portOldFavorites(plasmoid.configuration.favoriteApps); + plasmoid.configuration.favoritesPortedToKAstats = true; + } + } else { + favoritesModel.favorites = plasmoid.configuration.favoriteApps; + } + + favoritesModel.maxFavorites = pageSize; + rootModel.refresh(); + } + } + + Connections { + target: globalFavorites + + onFavoritesChanged: { + plasmoid.configuration.favoriteApps = target.favorites; + } + } + + Connections { + target: systemFavorites + + onFavoritesChanged: { + plasmoid.configuration.favoriteSystemActions = target.favorites; + } + } + + Connections { + target: plasmoid.configuration + + onFavoriteAppsChanged: { + globalFavorites.favorites = plasmoid.configuration.favoriteApps; + } + + onFavoriteSystemActionsChanged: { + systemFavorites.favorites = plasmoid.configuration.favoriteSystemActions; + } + } + + Kicker.RunnerModel { + id: runnerModel + + favoritesModel: globalFavorites + appletInterface: plasmoid + + deleteWhenEmpty: false + + } + + Kicker.DragHelper { + id: dragHelper + } + + Kicker.ProcessRunner { + id: processRunner; + } + + PlasmaCore.FrameSvgItem { + id: highlightItemSvg + + visible: false + + imagePath: "widgets/viewitem" + prefix: "hover" + } + + PlasmaCore.FrameSvgItem { + id: panelSvg + visible: false + imagePath: "widgets/panel-background" + } + + PlasmaComponents.Label { + id: toolTipDelegate + + width: contentWidth + height: contentHeight + + property Item toolTip + + text: (toolTip != null) ? toolTip.text : "" + } + + function resetDragSource() { + dragSource = null; + } + + Component.onCompleted: { + plasmoid.setAction("menuedit", i18n("Edit Applications...")); + + rootModel.refreshed.connect(reset); + + dragHelper.dropped.connect(resetDragSource); + } +} diff --git a/kde/plasma/plasmoids/AndromedaLauncher/metadata.desktop b/kde/plasma/plasmoids/AndromedaLauncher/metadata.desktop new file mode 100644 index 00000000..ea9d3512 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/metadata.desktop @@ -0,0 +1,19 @@ +[Desktop Entry] +Name=Andromeda Launcher +Comment=A modern Launcher for plasma! + +Type=Service +Icon=start-here-kde +X-KDE-ServiceTypes=Plasma/Applet + +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml +X-Plasma-Provides=org.kde.plasma.launchermenu + +X-KDE-PluginInfo-Author=EliverLara +X-KDE-PluginInfo-Email=eliverlara@gmail.com +X-KDE-PluginInfo-Name=AndromedaLauncher +X-KDE-PluginInfo-Version=0.6 +X-KDE-PluginInfo-Website=https://github.com/EliverLara/AndromedaLauncher +X-KDE-PluginInfo-Category=Application Launchers +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/kde/plasma/plasmoids/AndromedaLauncher/translate/build.sh b/kde/plasma/plasmoids/AndromedaLauncher/translate/build.sh new file mode 100644 index 00000000..c88cd5d5 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/translate/build.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# Version: 6 + +# This script will convert the *.po files to *.mo files, rebuilding the package/contents/locale folder. +# Feature discussion: https://phabricator.kde.org/D5209 +# Eg: contents/locale/fr_CA/LC_MESSAGES/plasma_applet_org.kde.plasma.eventcalendar.mo + +DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` +plasmoidName=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Name"` +website=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Website"` +bugAddress="$website" +packageRoot=".." # Root of translatable sources +projectName="plasma_applet_${plasmoidName}" # project name + +#--- +if [ -z "$plasmoidName" ]; then + echo "[build] Error: Couldn't read plasmoidName." + exit +fi + +if [ -z "$(which msgfmt)" ]; then + echo "[build] Error: msgfmt command not found. Need to install gettext" + echo "[build] Running 'sudo apt install gettext'" + sudo apt install gettext + echo "[build] gettext installation should be finished. Going back to installing translations." +fi + +#--- +echo "[build] Compiling messages" + +catalogs=`find . -name '*.po' | sort` +for cat in $catalogs; do + echo "$cat" + catLocale=`basename ${cat%.*}` + msgfmt -o "${catLocale}.mo" "$cat" + + installPath="$DIR/../contents/locale/${catLocale}/LC_MESSAGES/${projectName}.mo" + + echo "[build] Install to ${installPath}" + mkdir -p "$(dirname "$installPath")" + mv "${catLocale}.mo" "${installPath}" +done + +echo "[build] Done building messages" + +if [ "$1" = "--restartplasma" ]; then + echo "[build] Restarting plasmashell" + killall plasmashell + kstart5 plasmashell + echo "[build] Done restarting plasmashell" +else + echo "[build] (re)install the plasmoid and restart plasmashell to test." +fi diff --git a/kde/plasma/plasmoids/AndromedaLauncher/translate/de.po b/kde/plasma/plasmoids/AndromedaLauncher/translate/de.po new file mode 100644 index 00000000..2f93f9aa --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/translate/de.po @@ -0,0 +1,135 @@ +# Translation of MMcK Launcher in German +# Copyright (C) 2022 +# This file is distributed under the same license as the MMcK Launcher package. +# Friedrich Schriewer , 2022. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: mmcklauncher\n" +"Report-Msgid-Bugs-To: https://github.com/snoutbug/mmcklauncher\n" +"POT-Creation-Date: 2022-03-07 20:42-0000\n" +"PO-Revision-Date: 2022-03-07 20:42+0000\n" +"Last-Translator: Friedrich Schriewer \n" +"Language-Team: n/a\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Settings" +msgstr "Einstellungen" + +msgid "Power Off" +msgstr "Herunterfahren" + +msgid "Favorite Apps" +msgstr "Favoriten" + +msgid "General" +msgstr "Allgemein" + +msgid "Default Page:" +msgstr "Startseite:" + +msgid "All" +msgstr "Alle" + +msgid "Developement" +msgstr "Entwicklung" + +msgid "Games" +msgstr "Spiele" + +msgid "Graphics" +msgstr "Grafik" + +msgid "Internet" +msgstr "Internet" + +msgid "Multimedia" +msgstr "Multimedia" + +msgid "Office" +msgstr "Büro" + +msgid "Science & Math" +msgstr "Wissenschaft & Mathematik" + +msgid "System" +msgstr "System" + +msgid "Utilities" +msgstr "Werkzeuge" + +msgid "Lost & Found" +msgstr "Fundsachen" + +msgid "Icon:" +msgstr "Ikone:" + +msgid "Indicator:" +msgstr "Statusanzeige:" + +msgid "Enabled" +msgstr "Eingeschaltet" + +msgid "Indicator Color:" +msgstr "Farbe der Statusanzeige:" + +msgid "Please choose a color" +msgstr "Bitte wählen Sie eine Farbe" + +msgid "Greeting:" +msgstr "Begrüßung:" + +msgid "Custom Greeting Text:" +msgstr "Benutzerdefinierte Begrüßung:" + +msgid "No custom greeting set" +msgstr "Keine Begrüßung gesetzt" + +msgid "Launcher Positioning:" +msgstr "Startmenü Position:" + +msgid "Default" +msgstr "Standard" + +msgid "Horizontal Center" +msgstr "Horizontal zentriert" + +msgid "Screen Center" +msgstr "Bildschirmmitte" + +msgid "Floating" +msgstr "Schwebend" + +msgid "Offset Screen Edge (0 is Default):" +msgstr "Versatz Bildschirmkante (0 ist Standard):" + +msgid "Offset Panel (0 is Default):" +msgstr "Versatz Leiste (0 ist Standard):" + +msgid "All Applications (Default)" +msgstr "Alle Anwendungen (Standard)" + +msgid "Search:" +msgstr "Suche:" + +msgid "Expand search to bookmarks, files and emails" +msgstr "Erweiterte Suche für Lesezeichen, Dateien und E-Mails" + +msgid "Theming:" +msgstr "Thematisierung:" + +msgid "Dark (Default)" +msgstr "Dunkel (Standard)" + +msgid "Light" +msgstr "Hell" + +msgid "Matching" +msgstr "Automatisch anpassend" + +msgid "Search your computer" +msgstr "Computer durchsuchen" diff --git a/kde/plasma/plasmoids/AndromedaLauncher/translate/fr.po b/kde/plasma/plasmoids/AndromedaLauncher/translate/fr.po new file mode 100644 index 00000000..5fd534e6 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/translate/fr.po @@ -0,0 +1,135 @@ +# Translation of MMcK Launcher in French +# Copyright (C) 2022 +# This file is distributed under the same license as the MMcK Launcher package. +# Augustin Laurent , 2022. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: mmcklauncher\n" +"Report-Msgid-Bugs-To: https://github.com/snoutbug/mmcklauncher\n" +"POT-Creation-Date: 2022-08-07 10:00-0000\n" +"PO-Revision-Date: 2022-08-07 HO:MI+ZONE\n" +"Last-Translator: ugustin Laurent \n" +"Language-Team: French <>\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Settings" +msgstr "Réglages" + +msgid "Power Off" +msgstr "Éteindre" + +msgid "Favorite Apps" +msgstr "Applications préférées" + +msgid "General" +msgstr "Général" + +msgid "Default Page:" +msgstr "Page par défaut:" + +msgid "All" +msgstr "Tout" + +msgid "Developement" +msgstr "Développement" + +msgid "Games" +msgstr "Jeux" + +msgid "Graphics" +msgstr "Graphisme" + +msgid "Internet" +msgstr "Internet" + +msgid "Multimedia" +msgstr "Multimédia" + +msgid "Office" +msgstr "Office" + +msgid "Science & Math" +msgstr "Sciences & Math" + +msgid "System" +msgstr "Système" + +msgid "Utilities" +msgstr "Utilitaires" + +msgid "Lost & Found" +msgstr "Lost & Found" + +msgid "Icon:" +msgstr "Icône:" + +msgid "Indicator:" +msgstr "Indicateur:" + +msgid "Enabled" +msgstr "Activé" + +msgid "Indicator Color:" +msgstr "Couleur de l'indicateur:" + +msgid "Please choose a color" +msgstr "Veuillez choisir une couleur" + +msgid "Greeting:" +msgstr "Message d'acceuil:" + +msgid "Custom Greeting Text:" +msgstr "Texte d'acceuil personnalisé :" + +msgid "No custom greeting set" +msgstr "Aucun message d'accueil personnalisé défini" + +msgid "Launcher Positioning:" +msgstr "Positionnement du lanceur:" + +msgid "Default" +msgstr "Défaut" + +msgid "Horizontal Center" +msgstr "Centre horizontal" + +msgid "Screen Center" +msgstr "Centre de l'écran" + +msgid "Floating" +msgstr "Flottant" + +msgid "Offset Screen Edge (0 is Default):" +msgstr "Décalage par rapport au bord de l'écran (0 est la valeur par défaut):" + +msgid "Offset Panel (0 is Default):" +msgstr "Décalage par rapport à la barre de tâche (0 est la valeur par défaut):" + +msgid "All Applications (Default)" +msgstr "Toutes les applications (par défaut)" + +msgid "Search:" +msgstr "Rechercher:" + +msgid "Expand search to bookmarks, files and emails" +msgstr "Étendre la recherche aux signets, fichiers et e-mails" + +msgid "Theming:" +msgstr "Thème:" + +msgid "Dark (Default)" +msgstr "Dark (Default)" + +msgid "Light" +msgstr "Light" + +msgid "Matching" +msgstr "Correspondant" + +msgid "Search your computer" +msgstr "Rechercher dans votre ordinateur" diff --git a/kde/plasma/plasmoids/AndromedaLauncher/translate/id.po b/kde/plasma/plasmoids/AndromedaLauncher/translate/id.po new file mode 100644 index 00000000..767ce90e --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/translate/id.po @@ -0,0 +1,135 @@ +# Translation of MMcK Launcher in id +# Copyright (C) 2022 +# This file is distributed under the same license as the MMcK Launcher package. +# Adam Adrian <4.adam.adrian@gmail.com>, 2022. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: mmcklauncher\n" +"Report-Msgid-Bugs-To: https://github.com/snoutbug/mmcklauncher\n" +"POT-Creation-Date: 2022-03-07 20:42-0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Adam Adrian <4.adam.adrian@gmail.com>\n" +"Language-Team: Indonesia <>\n" +"Language: id\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Settings" +msgstr "Pengaturan" + +msgid "Power Off" +msgstr "Matikan Daya" + +msgid "Favorite Apps" +msgstr "Aplikasi Favorit" + +msgid "General" +msgstr "Umum" + +msgid "Default Page:" +msgstr "Halaman Bawaan" + +msgid "All" +msgstr "Semua" + +msgid "Developement" +msgstr "Pengembangan" + +msgid "Games" +msgstr "Permainan" + +msgid "Graphics" +msgstr "Grafis" + +msgid "Internet" +msgstr "Intenet" + +msgid "Multimedia" +msgstr "Multimedia" + +msgid "Office" +msgstr "Kantor" + +msgid "Science & Math" +msgstr "Sains & Matematika" + +msgid "System" +msgstr "Sistem" + +msgid "Utilities" +msgstr "Alat" + +msgid "Lost & Found" +msgstr "Hilang & Ditemukan" + +msgid "Icon:" +msgstr "Ikon:" + +msgid "Indicator:" +msgstr "Indkator:" + +msgid "Enabled" +msgstr "Diaktifkan" + +msgid "Indicator Color:" +msgstr "Warna Indikator" + +msgid "Please choose a color" +msgstr "Silahkan pilih sebuah warna" + +msgid "Greeting:" +msgstr "Sapaan:" + +msgid "Custom Greeting Text:" +msgstr "Teks Sapaan Kustom:" + +msgid "No custom greeting set" +msgstr "Tidak ada spaan kustom yang diatur" + +msgid "Launcher Positioning:" +msgstr "Pemosisian Peluncur:" + +msgid "Default" +msgstr "Default" + +msgid "Horizontal Center" +msgstr "Tengah Horizontal" + +msgid "Screen Center" +msgstr "Di Tengah Layar" + +msgid "Floating" +msgstr "Mengambang" + +msgid "Offset Screen Edge (0 is Default):" +msgstr "Offset Tepian Layar (0 = Default)" + +msgid "Offset Panel (0 is Default):" +msgstr "Offset Panel (0 = Default)" + +msgid "All Applications (Default)" +msgstr "Semua Aplikasi (Default)" + +msgid "Search:" +msgstr "Cari:" + +msgid "Expand search to bookmarks, files and emails" +msgstr "Luaskan pencaarian ke bookmark, file dan email" + +msgid "Theming:" +msgstr "Tema:" + +msgid "Dark (Default)" +msgstr "Gelap (Default)" + +msgid "Light" +msgstr "Terang" + +msgid "Matching" +msgstr "Cocokkan Tema" + +msgid "Search your computer" +msgstr "Cari di komputermu" diff --git a/kde/plasma/plasmoids/AndromedaLauncher/translate/merge.sh b/kde/plasma/plasmoids/AndromedaLauncher/translate/merge.sh new file mode 100644 index 00000000..b8ce86e0 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/translate/merge.sh @@ -0,0 +1,229 @@ +#!/bin/sh +# Version: 21 + +# https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems +# https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems/Outside_KDE_repositories +# https://invent.kde.org/sysadmin/l10n-scripty/-/blob/master/extract-messages.sh + +DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` +plasmoidName=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Name"` +widgetName="${plasmoidName##*.}" # Strip namespace +website=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Website"` +bugAddress="$website" +packageRoot=".." # Root of translatable sources +projectName="plasma_applet_${plasmoidName}" # project name + +#--- +if [ -z "$plasmoidName" ]; then + echo "[merge] Error: Couldn't read plasmoidName." + exit +fi + +if [ -z "$(which xgettext)" ]; then + echo "[merge] Error: xgettext command not found. Need to install gettext" + echo "[merge] Running 'sudo apt install gettext'" + sudo apt install gettext + echo "[merge] gettext installation should be finished. Going back to merging translations." +fi + +#--- +echo "[merge] Extracting messages" +potArgs="--from-code=UTF-8 --width=200 --add-location=file" + +# Note: xgettext v0.20.1 (Kubuntu 20.04) and below will attempt to translate Icon, +# so we need to specify Name, GenericName, Comment, and Keywords. +# https://github.com/Zren/plasma-applet-lib/issues/1 +# https://savannah.gnu.org/support/?108887 +find "${packageRoot}" -name '*.desktop' | sort > "${DIR}/infiles.list" +xgettext \ + ${potArgs} \ + --files-from="${DIR}/infiles.list" \ + --language=Desktop \ + -k -kName -kGenericName -kComment -kKeywords \ + -D "${packageRoot}" \ + -D "${DIR}" \ + -o "template.pot.new" \ + || \ + { echo "[merge] error while calling xgettext. aborting."; exit 1; } + +sed -i 's/"Content-Type: text\/plain; charset=CHARSET\\n"/"Content-Type: text\/plain; charset=UTF-8\\n"/' "template.pot.new" + +# See Ki18n's extract-messages.sh for a full example: +# https://invent.kde.org/sysadmin/l10n-scripty/-/blob/master/extract-messages.sh#L25 +# The -kN_ and -kaliasLocale keywords are mentioned in the Outside_KDE_repositories wiki. +# We don't need -kN_ since we don't use intltool-extract but might as well keep it. +# I have no idea what -kaliasLocale is used for. Googling aliasLocale found only listed kde1 code. +# We don't need to parse -ki18nd since that'll extract messages from other domains. +find "${packageRoot}" -name '*.cpp' -o -name '*.h' -o -name '*.c' -o -name '*.qml' -o -name '*.js' | sort > "${DIR}/infiles.list" +xgettext \ + ${potArgs} \ + --files-from="${DIR}/infiles.list" \ + -C -kde \ + -ci18n \ + -ki18n:1 -ki18nc:1c,2 -ki18np:1,2 -ki18ncp:1c,2,3 \ + -kki18n:1 -kki18nc:1c,2 -kki18np:1,2 -kki18ncp:1c,2,3 \ + -kxi18n:1 -kxi18nc:1c,2 -kxi18np:1,2 -kxi18ncp:1c,2,3 \ + -kkxi18n:1 -kkxi18nc:1c,2 -kkxi18np:1,2 -kkxi18ncp:1c,2,3 \ + -kI18N_NOOP:1 -kI18NC_NOOP:1c,2 \ + -kI18N_NOOP2:1c,2 -kI18N_NOOP2_NOSTRIP:1c,2 \ + -ktr2i18n:1 -ktr2xi18n:1 \ + -kN_:1 \ + -kaliasLocale \ + --package-name="${widgetName}" \ + --msgid-bugs-address="${bugAddress}" \ + -D "${packageRoot}" \ + -D "${DIR}" \ + --join-existing \ + -o "template.pot.new" \ + || \ + { echo "[merge] error while calling xgettext. aborting."; exit 1; } + +sed -i 's/# SOME DESCRIPTIVE TITLE./'"# Translation of ${widgetName} in LANGUAGE"'/' "template.pot.new" +sed -i 's/# Copyright (C) YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/'"# Copyright (C) $(date +%Y)"'/' "template.pot.new" + +if [ -f "template.pot" ]; then + newPotDate=`grep "POT-Creation-Date:" template.pot.new | sed 's/.\{3\}$//'` + oldPotDate=`grep "POT-Creation-Date:" template.pot | sed 's/.\{3\}$//'` + sed -i 's/'"${newPotDate}"'/'"${oldPotDate}"'/' "template.pot.new" + changes=`diff "template.pot" "template.pot.new"` + if [ ! -z "$changes" ]; then + # There's been changes + sed -i 's/'"${oldPotDate}"'/'"${newPotDate}"'/' "template.pot.new" + mv "template.pot.new" "template.pot" + + addedKeys=`echo "$changes" | grep "> msgid" | cut -c 9- | sort` + removedKeys=`echo "$changes" | grep "< msgid" | cut -c 9- | sort` + echo "" + echo "Added Keys:" + echo "$addedKeys" + echo "" + echo "Removed Keys:" + echo "$removedKeys" + echo "" + + else + # No changes + rm "template.pot.new" + fi +else + # template.pot didn't already exist + mv "template.pot.new" "template.pot" +fi + +potMessageCount=`expr $(grep -Pzo 'msgstr ""\n(\n|$)' "template.pot" | grep -c 'msgstr ""')` +echo "| Locale | Lines | % Done|" > "./Status.md" +echo "|----------|---------|-------|" >> "./Status.md" +entryFormat="| %-8s | %7s | %5s |" +templateLine=`perl -e "printf(\"$entryFormat\", \"Template\", \"${potMessageCount}\", \"\")"` +echo "$templateLine" >> "./Status.md" + +rm "${DIR}/infiles.list" +echo "[merge] Done extracting messages" + +#--- +echo "[merge] Merging messages" +catalogs=`find . -name '*.po' | sort` +for cat in $catalogs; do + echo "[merge] $cat" + catLocale=`basename ${cat%.*}` + + widthArg="" + catUsesGenerator=`grep "X-Generator:" "$cat"` + if [ -z "$catUsesGenerator" ]; then + widthArg="--width=400" + fi + + cp "$cat" "$cat.new" + sed -i 's/"Content-Type: text\/plain; charset=CHARSET\\n"/"Content-Type: text\/plain; charset=UTF-8\\n"/' "$cat.new" + + msgmerge \ + ${widthArg} \ + --add-location=file \ + --no-fuzzy-matching \ + -o "$cat.new" \ + "$cat.new" "${DIR}/template.pot" + + sed -i 's/# SOME DESCRIPTIVE TITLE./'"# Translation of ${widgetName} in ${catLocale}"'/' "$cat.new" + sed -i 's/# Translation of '"${widgetName}"' in LANGUAGE/'"# Translation of ${widgetName} in ${catLocale}"'/' "$cat.new" + sed -i 's/# Copyright (C) YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/'"# Copyright (C) $(date +%Y)"'/' "$cat.new" + + poEmptyMessageCount=`expr $(grep -Pzo 'msgstr ""\n(\n|$)' "$cat.new" | grep -c 'msgstr ""')` + poMessagesDoneCount=`expr $potMessageCount - $poEmptyMessageCount` + poCompletion=`perl -e "printf(\"%d\", $poMessagesDoneCount * 100 / $potMessageCount)"` + poLine=`perl -e "printf(\"$entryFormat\", \"$catLocale\", \"${poMessagesDoneCount}/${potMessageCount}\", \"${poCompletion}%\")"` + echo "$poLine" >> "./Status.md" + + # mv "$cat" "$cat.old" + mv "$cat.new" "$cat" +done +echo "[merge] Done merging messages" + +#--- +echo "[merge] Updating .desktop file" + +# Generate LINGUAS for msgfmt +if [ -f "$DIR/LINGUAS" ]; then + rm "$DIR/LINGUAS" +fi +touch "$DIR/LINGUAS" +for cat in $catalogs; do + catLocale=`basename ${cat%.*}` + echo "${catLocale}" >> "$DIR/LINGUAS" +done + +cp -f "$DIR/../metadata.desktop" "$DIR/template.desktop" +sed -i '/^Name\[/ d; /^GenericName\[/ d; /^Comment\[/ d; /^Keywords\[/ d' "$DIR/template.desktop" + +msgfmt \ + --desktop \ + --template="$DIR/template.desktop" \ + -d "$DIR/" \ + -o "$DIR/new.desktop" + +# Delete empty msgid messages that used the po header +if [ ! -z "$(grep '^Name=$' "$DIR/new.desktop")" ]; then + echo "[merge] Name in metadata.desktop is empty!" + sed -i '/^Name\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^GenericName=$' "$DIR/new.desktop")" ]; then + echo "[merge] GenericName in metadata.desktop is empty!" + sed -i '/^GenericName\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^Comment=$' "$DIR/new.desktop")" ]; then + echo "[merge] Comment in metadata.desktop is empty!" + sed -i '/^Comment\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^Keywords=$' "$DIR/new.desktop")" ]; then + echo "[merge] Keywords in metadata.desktop is empty!" + sed -i '/^Keywords\[/ d' "$DIR/new.desktop" +fi + +# Place translations at the bottom of the desktop file. +translatedLines=`cat "$DIR/new.desktop" | grep "]="` +if [ ! -z "${translatedLines}" ]; then + sed -i '/^Name\[/ d; /^GenericName\[/ d; /^Comment\[/ d; /^Keywords\[/ d' "$DIR/new.desktop" + if [ "$(tail -c 2 "$DIR/new.desktop" | wc -l)" != "2" ]; then + # Does not end with 2 empty lines, so add an empty line. + echo "" >> "$DIR/new.desktop" + fi + echo "${translatedLines}" >> "$DIR/new.desktop" +fi + +# Cleanup +mv "$DIR/new.desktop" "$DIR/../metadata.desktop" +rm "$DIR/template.desktop" +rm "$DIR/LINGUAS" + +#--- +# Populate ReadMe.md +echo "[merge] Updating translate/ReadMe.md" +sed -i -E 's`share\/plasma\/plasmoids\/(.+)\/translate`share/plasma/plasmoids/'"${plasmoidName}"'/translate`' ./ReadMe.md +if [[ "$website" == *"github.com"* ]]; then + sed -i -E 's`\[new issue\]\(https:\/\/github\.com\/(.+)\/(.+)\/issues\/new\)`[new issue]('"${website}"'/issues/new)`' ./ReadMe.md +fi +sed -i '/^|/ d' ./ReadMe.md # Remove status table from ReadMe +cat ./Status.md >> ./ReadMe.md +rm ./Status.md + +echo "[merge] Done" + diff --git a/kde/plasma/plasmoids/AndromedaLauncher/translate/nl.po b/kde/plasma/plasmoids/AndromedaLauncher/translate/nl.po new file mode 100644 index 00000000..4814d11e --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/translate/nl.po @@ -0,0 +1,136 @@ +# Translation of MMcK Launcher in LANGUAGE +# Copyright (C) 2022 +# This file is distributed under the same license as the MMcK Launcher package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: mmcklauncher\n" +"Report-Msgid-Bugs-To: https://github.com/snoutbug/mmcklauncher\n" +"POT-Creation-Date: 2022-03-07 20:42-0000\n" +"PO-Revision-Date: 2022-03-08 13:20+0100\n" +"Last-Translator: Heimen Stoffels \n" +"Language-Team: \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.0.1\n" + +msgid "Settings" +msgstr "Instellingen" + +msgid "Power Off" +msgstr "Uitschakelen" + +msgid "Favorite Apps" +msgstr "Favorieten" + +msgid "General" +msgstr "Algemeen" + +msgid "Default Page:" +msgstr "Startpagina:" + +msgid "All" +msgstr "Alles" + +msgid "Developement" +msgstr "Ontwikkeling" + +msgid "Games" +msgstr "Games" + +msgid "Graphics" +msgstr "Grafisch" + +msgid "Internet" +msgstr "Internet" + +msgid "Multimedia" +msgstr "Multimedia" + +msgid "Office" +msgstr "Kantoor" + +msgid "Science & Math" +msgstr "Wetenschap" + +msgid "System" +msgstr "Systeem" + +msgid "Utilities" +msgstr "Hulpmiddelen" + +msgid "Lost & Found" +msgstr "Overig" + +msgid "Icon:" +msgstr "Pictogram:" + +msgid "Indicator:" +msgstr "Indicator:" + +msgid "Enabled" +msgstr "Ingeschakeld" + +msgid "Indicator Color:" +msgstr "Indicatorkleur:" + +msgid "Please choose a color" +msgstr "Kies een kleur" + +msgid "Greeting:" +msgstr "Begroeting:" + +msgid "Custom Greeting Text:" +msgstr "Eigen tekst:" + +msgid "No custom greeting set" +msgstr "Geen eigen tekst ingesteld" + +msgid "Launcher Positioning:" +msgstr "Startmenu openen op locatie:" + +msgid "Default" +msgstr "Standaard" + +msgid "Horizontal Center" +msgstr "Midden (horizontaal)" + +msgid "Screen Center" +msgstr "Midden van scherm" + +msgid "Floating" +msgstr "Zweven" + +msgid "Offset Screen Edge (0 is Default):" +msgstr "Ruimte vanaf schermrand (standaard: 0)" + +msgid "Offset Panel (0 is Default):" +msgstr "Ruimte vanaf paneel (standaard: 0)" + +msgid "All Applications (Default)" +msgstr "Alle programma's (standaard)" + +msgid "Search:" +msgstr "Zoeken:" + +msgid "Expand search to bookmarks, files and emails" +msgstr "Ook bladwijzers, bestanden en e-mails doorzoeken" + +msgid "Theming:" +msgstr "Thema:" + +msgid "Dark (Default)" +msgstr "Donker (standaard)" + +msgid "Light" +msgstr "Licht" + +msgid "Matching" +msgstr "Systeemthema" + +msgid "Search your computer" +msgstr "Doorzoek je computer" diff --git a/kde/plasma/plasmoids/AndromedaLauncher/translate/template.pot b/kde/plasma/plasmoids/AndromedaLauncher/translate/template.pot new file mode 100644 index 00000000..53c62d15 --- /dev/null +++ b/kde/plasma/plasmoids/AndromedaLauncher/translate/template.pot @@ -0,0 +1,135 @@ +# Translation of MMcK Launcher in LANGUAGE +# Copyright (C) 2022 +# This file is distributed under the same license as the MMcK Launcher package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: mmcklauncher\n" +"Report-Msgid-Bugs-To: https://github.com/snoutbug/mmcklauncher\n" +"POT-Creation-Date: 2022-03-07 20:42-0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Settings" +msgstr "" + +msgid "Power Off" +msgstr "" + +msgid "Favorite Apps" +msgstr "" + +msgid "General" +msgstr "" + +msgid "Default Page:" +msgstr "" + +msgid "All" +msgstr "" + +msgid "Developement" +msgstr "" + +msgid "Games" +msgstr "" + +msgid "Graphics" +msgstr "" + +msgid "Internet" +msgstr "" + +msgid "Multimedia" +msgstr "" + +msgid "Office" +msgstr "" + +msgid "Science & Math" +msgstr "" + +msgid "System" +msgstr "" + +msgid "Utilities" +msgstr "" + +msgid "Lost & Found" +msgstr "" + +msgid "Icon:" +msgstr "" + +msgid "Indicator:" +msgstr "" + +msgid "Enabled" +msgstr "" + +msgid "Indicator Color:" +msgstr "" + +msgid "Please choose a color" +msgstr "" + +msgid "Greeting:" +msgstr "" + +msgid "Custom Greeting Text:" +msgstr "" + +msgid "No custom greeting set" +msgstr "" + +msgid "Launcher Positioning:" +msgstr "" + +msgid "Default" +msgstr "" + +msgid "Horizontal Center" +msgstr "" + +msgid "Screen Center" +msgstr "" + +msgid "Floating" +msgstr "" + +msgid "Offset Screen Edge (0 is Default):" +msgstr "" + +msgid "Offset Panel (0 is Default):" +msgstr "" + +msgid "All Applications (Default)" +msgstr "" + +msgid "Search:" +msgstr "" + +msgid "Expand search to bookmarks, files and emails" +msgstr "" + +msgid "Theming:" +msgstr "" + +msgid "Dark (Default)" +msgstr "" + +msgid "Light" +msgstr "" + +msgid "Matching" +msgstr "" + +msgid "Search your computer" +msgstr "" diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/config/config.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/config/config.qml new file mode 100644 index 00000000..c1f355a6 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/config/config.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 +import org.kde.plasma.configuration 2.0 +import "../ui/Mpdw.js" as Mpdw + +ConfigModel { + ConfigCategory { + name: qsTr("General") + icon: Mpdw.icons.appConfigGeneral + source: "Config/configGeneral.qml" + } + ConfigCategory { + name: qsTr("Appearance") + icon: Mpdw.icons.appConfigAppearance + source: "Config/configAppearance.qml" + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/config/main.xml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/config/main.xml new file mode 100644 index 00000000..fc79ddad --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/config/main.xml @@ -0,0 +1,49 @@ + + + + + + + 192.168.1.250 + + + + 0 + + + + 10 + + + + false + + + + $HOME/.cache/com.siezi.plasma.mpdWidget + + + + 30 + + + + 0 + + + + 0 + + + + #888888 + + + + false + + + + \ No newline at end of file diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/__init__.cpython-310.pyc b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 00000000..728afda8 Binary files /dev/null and b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/__init__.cpython-310.pyc differ diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/__init__.cpython-311.pyc b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 00000000..d8c49a4e Binary files /dev/null and b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/__init__.cpython-311.pyc differ diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/base.cpython-310.pyc b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/base.cpython-310.pyc new file mode 100644 index 00000000..42daa270 Binary files /dev/null and b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/base.cpython-310.pyc differ diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/base.cpython-311.pyc b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/base.cpython-311.pyc new file mode 100644 index 00000000..c6a97a1c Binary files /dev/null and b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/base.cpython-311.pyc differ diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/twisted.cpython-310.pyc b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/twisted.cpython-310.pyc new file mode 100644 index 00000000..a8ae0996 Binary files /dev/null and b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/twisted.cpython-310.pyc differ diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/twisted.cpython-311.pyc b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/twisted.cpython-311.pyc new file mode 100644 index 00000000..7fdd0cce Binary files /dev/null and b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/lib/python-mpd2/mpd/__pycache__/twisted.cpython-311.pyc differ diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/CoverManager.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/CoverManager.qml new file mode 100644 index 00000000..76738034 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/CoverManager.qml @@ -0,0 +1,153 @@ +import QtQuick 2.15 as QQ2 +import org.kde.plasma.core 2.0 as PlasmaCore +import "coverHelpers.js" as CoverHelpers + +QQ2.Item { + id: coverManager + + signal gotCover(string id) + signal afterReset + + property bool fetching: false + property var currentlyFetching + property string filePrefix: "mpdcover-" + property var covers: ({}) + property var fetchQueue: new CoverHelpers.FetchQueue() + + function reset() { + covers = {} + getLocalCovers() + afterReset() + } + + + /** + * @return {mixed} + * - string: Path to cover image + * - undefined: No cover information known (yet) + * - null: No cover available + */ + function getCover(item, priority = 100) { + let title = getId(item) + if (title in covers) { + if (covers[title] === null) { + return null + } else { + return encodeURIComponent(covers[title].path) + } + } + + fetchQueue.add(title, item, priority) + fetchingQueueTimer.start() + return undefined + } + + function getLocalCovers() { + let cmd = 'find ' + cfgCacheRoot + ' -name "' + coverManager.filePrefix + '*-large.jpg"' + executable.exec(cmd, function (exitCode, stdout) { + let lines = stdout.split("\n") + lines.forEach(function (line) { + if (!line) { + return + } + + line = line.replace("-large.jpg", "") + let id = coverManager.idFromCoverPath(line) + coverManager.covers[id] = { + "path": line + } + }) + mpdState.connect() + }) + } + + function getId(itemInfo) { + let id = itemInfo.file + if (itemInfo.album && (itemInfo.albumartist || itemInfo.artist)) { + id = (itemInfo.albumartist || itemInfo.artist) + " - " + itemInfo.album + } + + return id + } + + function getCoverFileName(itemInfo) { + // We assume that albums have the same cover, saving only one cover per + // album, not for every song. + let hash = encodeURIComponent(getId(itemInfo)) + return filePrefix + hash + } + + function idFromCoverPath(path) { + let id = path.replace(cfgCacheRoot + '/' + filePrefix, '') + id = decodeURIComponent(id) + return id + } + + function markFetched(success) { + let id = getId(currentlyFetching) + let coverPath = cfgCacheRoot + '/' + getCoverFileName(currentlyFetching) + + let item = null + if (success) { + item = { + "path": coverPath + } + } + + coverManager.covers[id] = item + coverManager.fetchQueue.delete(id) + fetching = false + + gotCover(id) + } + + function clearCache() { + let cmd = "rm " + cfgCacheRoot + "/" + filePrefix + "*" + executable.exec(cmd, function () { coverManager.reset() }) + } + + // Rotate cover cache + QQ2.Timer { + id: coverRotateTimer + running: true + interval: 10800000 + repeat: true + triggeredOnStart: true + onTriggered: { + let cmd = 'find "' + cfgCacheRoot + '" -type f -name "' + filePrefix + '*" -mtime +' + cfgCacheForDays + ' -exec rm "{}" \\;' + executable.exec(cmd, function () { coverManager.reset() }) + } + } + + // Trigger fetching new covers + QQ2.Timer { + id: fetchingQueueTimer + + property int watchdog + + repeat: true + interval: 500 + triggeredOnStart: true + onTriggered: { + if (fetching && watchdog !== 0) { + watchdog-- + return + } + let itemToFetch = fetchQueue.next() + if (!itemToFetch) { + fetchingQueueTimer.stop() + return + } + + watchdog = 120 + fetching = true + currentlyFetching = itemToFetch + // @TODO Execute here instead of mpdstate? + mpdState.getCover(itemToFetch.file, getCoverFileName(itemToFetch), cfgCacheRoot, filePrefix) + } + } + + ExecGeneric { + id: executable + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/ExecGeneric.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/ExecGeneric.qml new file mode 100644 index 00000000..a0cd1444 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/ExecGeneric.qml @@ -0,0 +1,43 @@ +import org.kde.plasma.core 2.0 as PlasmaCore + +PlasmaCore.DataSource { + id: root + + signal exited(int exitCode, int exitStatus, string stdout, string stderr, string sourceName) + + property var callbacks: ({}) + + function disconnect() { + sources.forEach(function (source) { + root.disconnectSource(source) + }) + } + + function exec(command, callback) { + let clbType = typeof (callback) + if (clbType === 'function') { + callbacks[command] = callback + } else if (clbType !== 'undefined') { + throw new Error("Invalid argument: callback must be a function - is " + clbType) + } + + connectSource(command) + } + + engine: "executable" + connectedSources: [] + onNewData: { + var exitCode = data["exit code"] + var exitStatus = data["exit status"] + var stdout = data["stdout"] + var stderr = data["stderr"] + + if (callbacks[sourceName]) { + callbacks[sourceName](exitCode, stdout, stderr, exitStatus) + delete callbacks[sourceName] + } + + exited(exitCode, stdout, stderr, exitStatus, sourceName) + disconnectSource(sourceName) + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/ExecMpc.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/ExecMpc.qml new file mode 100644 index 00000000..f47dd7cc --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/ExecMpc.qml @@ -0,0 +1,21 @@ +ExecGeneric { + id: root + + /** + * Executes mpc commands + * + * @param {string} command Command to execute + * @param {function} callback Callback to execute after the command + */ + function execMpc(command, callback) { + if (mpcAvailable !== true || mpcConnectionAvailable !== true) { + return + } + let cmd = ["mpc"] + if (cfgMpdHost !== "") { + cmd.push("--host=" + cfgMpdHost) + } + cmd.push(command) + exec(cmd.join(" "), callback) + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/MpdState.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/MpdState.qml new file mode 100644 index 00000000..15b797de --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/MpdState.qml @@ -0,0 +1,661 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.15 +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.core 2.0 as PlasmaCore +import "songLibrary.js" as SongLibrary + +Item { + id: mpdRoot + + signal gotPlaylist(var plData) + signal onSaveQueueAsPlaylist(bool success) + signal playedPlaylist(string title) + + property bool mpcAvailable: false + property bool mpcConnectionAvailable: false + property int mpdVolume: 0 + property string scriptRoot + property bool mpdPlaying: false + property var library + property bool libraryRequested: false + property var mpdInfo: ({}) + property var mpdOptions: ({}) + property var mpdPlaylists: ({}) + property var mpdQueue: [] + readonly property string _songInfoQuery: '{[\x1Fartist\x1F:\x1F%artist%\x1F,][\x1Falbumartist\x1F:\x1F%albumartist%\x1F,][\x1Falbum\x1F:\x1F%album%\x1F,][\x1Ftracknumber\x1F:\x1F%track%\x1F,]\x1Ftitle\x1F:\x1F%title%\x1F,[\x1Fdate\x1F:\x1F%date%\x1F,]\x1Ftime\x1F:\x1F%time%\x1F,\x1Ffile\x1F:\x1F%file%\x1F,\x1Fposition\x1F:\x1F%position%\x1F},' + + readonly property var mpdCmds: { + "cSongInfo": "-f '%1'", + "connectionCheck": "mpc --host=%1 status", + "lGet": "listall -f '%1'", + "mpcCheck": "which mpc", + "mpcIdleLoop": "idle player mixer playlist stored_playlist options", + "optGet": "status '{\x1Fconsume\x1F:\x1F%consume%\x1F,\x1Frandom\x1F:\x1F%random%\x1F,\x1Frepeat\x1F:\x1F%repeat%\x1F}'", + "optSet": "%1 %2", + "plLoad": "load %1", + "plGet": "playlist -f '%1' %2", + "plRm": "rm -- %1", + "plSave": "save -- %1", + "plsGet": "lsplaylist", + "qAdd": "add %1", + "qClear": "clear", + "qDel": "del %1", + "qGet": "playlist -f '%1'", + "qInsert": "insert %1", + "qMove": "move %1 %2", + "qNext": "next", + "qPlay": "play %1", + "qQueued": "queued -f '%1'", + "qToggle": "toggle", + "volumeGet": "volume", + "volumeSet": "volume %1" + } + + /** + * Starts the bootstrap process of a fresh connection to the mpd instance + */ + function connect() { + if (mpcAvailable !== true) { + mpdRoot.checkMpcAvailable() + return + } + + disconnect() + checkMpcConnectionAvailable() + } + + + /** + * Stops the current connection to the mpd instance + */ + function disconnect() { + executable.disconnect() + mpdRoot.mpcConnectionAvailable = false + mpdRootIdleLoopTimer.stop() + } + + + /** + * Check if mpc binary available on the host system + */ + function checkMpcAvailable() { + let callback = function (exitCode) { + if (exitCode !== 0) { + return + } + + mpdRoot.mpcAvailable = true + mpdRoot.connect() + } + + executable.exec(mpdCmds.mpcCheck, callback) + } + + + /** + * Checks if mpc is able to connect to mpd + */ + function checkMpcConnectionAvailable() { + if (mpcAvailable !== true) { + return + } + + let callback = function (exitCode) { + if (exitCode !== 0) { + mpdRootNetworkTimeout.start() + + return + } + + mpdRootNetworkTimeout.interval = mpdRootNetworkTimeout.startInterval + mpdRootIdleLoopTimer.start() + mpcConnectionAvailable = true + update() + + if (libraryRequested) { + getLibrary() + } + } + + // Bypass the build-in mpc faclities, they are gatekept by the result of this. + executable.exec(mpdCmds.connectionCheck.arg(cfgMpdHost), callback) + } + + function forceReloadEverything() { + if (library) { + mpdRoot.libraryRequested = true + } + connect() + } + + /** + * Inits update of all mpd data required by our plasmoid + */ + // @TODO this should be disentangled and properly attached/requested by our now exiting + // different views + function update() { + mpdRoot.getVolume() + mpdRoot.getQueue() + // @SOMEDAY make code more robust + // Leave getInfo() after getQueue(), since it evaluates the queue content + mpdRoot.getInfo() + mpdRoot.getPlaylists() + mpdRoot.getOptions() + } + + + /** + * Download whole song library + */ + function getLibrary() { + if (!mpcConnectionAvailable) { + libraryRequested = true + } + executable.execMpc(mpdCmds.lGet.arg(_songInfoQuery), function (exitCode, stdout) { + if (exitCode !== 0) { + return + } + library = new SongLibrary.SongLibrary(songInfoQueryResponseToJson(stdout)) + }) + } + + /** + * Saves queue as playlist + * + * @param {sting} title playlist title in MPD + */ + function saveQueueAsPlaylist(title) { + executable.execMpc(mpdCmds.plSave.arg(bEsc(title)), function (exitCode) { + if (exitCode !== 0) { + return + } + onSaveQueueAsPlaylist(!exitCode) + }) + } + + + /** + * Deletes a playlist + * + * @param {sting} title playlist title in MPD + */ + function removePlaylist(title) { + executable.execMpc(mpdCmds.plRm.arg(bEsc(title))) + } + + + /** + * Moves song in queue + * + * @param {int} from Position of the song to move (current) + * @param {int} to Positiong to move the song to (target) + */ + function moveInQueue(from, to) { + executable.execMpc(mpdCmds.qMove.arg(from).arg(to)) + } + + function getVolume() { + executable.execMpc(mpdCmds.volumeGet, function (exitCode, stdout) { + if (exitCode !== 0) { + return + } + + let parsed = stdout.match(/volume:\W*(\d*)/) + if (!parsed) { + throw new Error("Invalid mpc response: No volume information in " + stdout) + } + mpdRoot.mpdVolume = parseInt(parsed[1]) + }) + } + + /** + * Set volume + * + * @param {string} Absolute or +/- + */ + function setVolume(value) { + executable.execMpc(mpdCmds.volumeSet.arg(value)) + } + + /** + * Get info of currently playing song + * + * When mpd is stopped it evalutates what is going to be played next on + * toggling "play". + */ + function getInfo() { + let cmd = mpdCmds.cSongInfo.arg(_songInfoQuery) + executable.execMpc(cmd, function (exitCode, stdout) { + if (exitCode !== 0) { + return + } + let info = stdout.split("\n") + + // Normal playback + if (info.length > 2) { + mpdInfo = songInfoQueryResponseToJson(info.shift())[0] + mpdPlaying = info.shift().includes('[playing]') + + return + } + + // Qeueue is paused or in stopped state + mpdPlaying = false + + // Queue is empty, nothing will be played on a toggle + if (mpdState.mpdQueue.length === 0) { + return + } + + // Only one item on the queue, it must be played on a toggle + if (mpdState.mpdQueue.length === 1) { + mpdInfo = mpdQueue[0] + return + } + + executable.execMpc(mpdCmds.qQueued.arg(_songInfoQuery), function (exitCode, stdout) { + if (exitCode !== 0) { + return + } + + if (stdout === "") { + // More than one item in Queue but nothing queued. a) Queue is + // stopped and was never started before (1st item will be played) + // or b) we are at the last item. + // Since we only create case (a) we ignore (b) for our purposes. + mpdInfo = mpdQueue[0] + return + } + + // Queue was started before, we just can't get the item directly, + // so we cheat by asking for the next one. + let queued = songInfoQueryResponseToJson(stdout)[0] + mpdInfo = mpdQueue[queued.position - 2] + }) + }) + } + + function getQueue() { + let cmd = mpdCmds.qGet.arg(_songInfoQuery) + executable.execMpc(cmd, function (exitCode, stdout) { + if (exitCode !== 0) { + return + } + if (!stdout.length) { + // Empty queue + mpdQueue = [] + return + } + let queue = songInfoQueryResponseToJson(stdout) + mpdRoot.mpdQueue = queue + }) + } + + /** + * Add songs to the queue + * + * @param {array} array of mpd file IDs + * @param {string} insertion mode + * - "append" at end of queue + * - "insert" after currently playing track + */ + function addSongsToQueue(items, mode = "append") { + if (!Array.isArray(items)) { + throw new Error("Invalid argument: items must be an array") + } + + let cmd + switch (mode) { + case "append": + cmd = mpdCmds.qAdd + break + case "insert": + cmd = mpdCmds.qInsert + break + default: + throw new Error("Invalid argument: unknown mode") + } + + cmd = cmd.arg(items.map(function (item) { return bEsc(item) }).join(" ")) + + mpdCommandQueue.add(cmd) + } + + function replaceQueue(items) { + clearQueue() + addSongsToQueue(items) + playInQueue(1) + } + + /** + * Removes items from the queue + * + * @param {array} positions Positions of items to remove from the queue + */ + function removeFromQueue(positions) { + if (!Array.isArray(positions)) { + throw new Error("Invalid argument: positions must be an array") + } + executable.execMpc(mpdCmds.qDel.arg(positions.join(' '))) + } + + function playNext() { + executable.execMpc(mpdCmds.qNext) + } + + function toggle() { + executable.execMpc(mpdCmds.qToggle) + } + + + function clearQueue() { + // @BOGUS mpd/mpc doens't execute if used to fast + mpdCommandQueue.add(mpdCmds.qClear) + // executable.execMpc(mpdCmds.qClear) + } + + + /** + * Play specific item in queue + * + * @param {int} position Position in queue + */ + function playInQueue(position) { + mpdCommandQueue.add(mpdCmds.qPlay.arg(position)) + // executable.execMpc(mpdCmds.qPlay.arg(position)) + } + + function getPlaylists() { + executable.execMpc(mpdCmds.plsGet, function (exitCode, stdout) { + if (exitCode !== 0) { + return + } + let playlists = stdout.split("\n") + playlists = playlists.filter(value => { + return value && !value.includes('m3u') + }) + playlists = playlists.sort((a, b) => { + let textA = a.toUpperCase() + let textB = b.toUpperCase() + return (textA < textB) ? -1 : (textA > textB) ? 1 : 0 + }) + mpdRoot.mpdPlaylists = playlists + }) + } + + function getPlaylist(playlist) { + let cmd = mpdCmds.plGet.arg(_songInfoQuery).arg(bEsc(playlist)) + let clb = function (exitCode, stdout) { + gotPlaylist(songInfoQueryResponseToJson(stdout)) + } + executable.execMpc(cmd, clb) + } + + function playPlaylist(playlist) { + clearQueue() + addPlaylistToQueue(playlist) + playInQueue(1) + playedPlaylist(playlist) + } + + function getOptions() { + executable.execMpc(mpdCmds.optGet, function (exitCode, stdout) { + if (exitCode !== 0) { + return + } + mpdRoot.mpdOptions = songInfoQueryResponseToJson(stdout)[0] + }) + } + + function toggleOption(option) { + if (typeof option !== 'string') { + throw new Error("Invalid argument: mpd-options must be an string") + } + if (!['consume', 'random', 'repeat'].includes(option)) { + throw new Error("Invalid argument: mpd-option " + option) + } + + let newState = mpdRoot.mpdOptions[option] === "on" ? "off" : "on" + + executable.execMpc(mpdCmds.optSet.arg(option).arg(newState)) + } + + function addPlaylistToQueue(playlist) { + mpdCommandQueue.add(mpdCmds.plLoad.arg(bEsc(playlist))) + // executable.execMpc(mpdCmds.plLoad.arg(bEsc(playlist))) + } + + function getCover(title, ctitle, root, prefix) { + let cmd = '' + cmd += '/usr/bin/env bash' + cmd += ' "' + mpdRoot.scriptRoot + '/downloadCover.sh"' + cmd += ' ' + cfgMpdHost + cmd += ' ' + bEsc(title) + cmd += ' "' + root + '"' + cmd += ' ' + prefix + cmd += ' "' + ctitle.replace('/', '\\\\/') + '"' + + let clb = function (exitCode, stdout) { + if (exitCode !== 0) { + return + } + + coverManager.markFetched(!stdout.includes("No data")) + } + executable.exec(cmd, clb) + } + + function countQueue() { + return Object.keys(mpdRoot.mpdQueue).length + } + + + /** + * Escape special characters from strings before using as mpc arguments + * + * @param {string} str The string to quote + * @param {bool} quote Wrap the string in double quotes + * @return {string} The escaped string + */ + function bEsc(str, quote = true) { + if (typeof(str) !== "string") { + console.trace() + throw new Error("Invalid argument error: expected string, got " + typeof(str)) + } + if (str === "") { + throw new Error("Invalid argument error: got empty string") + } + let specialChars = ['$', '`', '"', '\\'] + let escapedStr = str.split('').map(character => { + if (specialChars.includes(character)) { + return '\\' + character + } else { + return character + } + }).join('') + if (quote) { + escapedStr = "\"" + escapedStr + "\"" + } + return escapedStr + } + + + /** + * Parses a response made in the songInfoQuery-format to JSON + * + * Main task is to solve " quoting issues + * + * @param {string} response The raw text of the mpd response + * @return {array} Array of JSON objects each representing one song + */ + function songInfoQueryResponseToJson(response) { + // [profiling] parse takes 90%+ of time + return JSON.parse('[' + response.replace(/"/g, '\\"').replace(/\x1F/g, '"').replace(/,\n?$/, "") + ']') + } + + + /** + * Replace mpc error messages with our own + * + * @param {string} msg The mpc error message + */ + function fmtErrorMessage(msg) { + let fmtMsg = msg + if (fmtMsg.includes("No route to host")) { + fmtMsg = qsTr("Can't find the MPD-server. - Check the MPD-address in the widget configuration.") + } else if (fmtMsg.includes("Network is unreachable")) { + fmtMsg = qsTr("No network connection.") + } else if (fmtMsg.includes("no mpc in")) { + fmtMsg = qsTr("'mpc' binary wasn't found. - Please install mpc on your system. It should be available in your system's package manager.") + } + + return fmtMsg + } + + // Throttle commands so we don't miss results on the event loop because we + // sending to fast. + Timer { + id: mpdCommandQueue + + property var cmdQueue: [] + + // The statusUpdateTimer is chained to this! + interval: 200 + running: true + repeat: true + + function add(cmd) { + cmdQueue.push(cmd) + } + + onTriggered: { + if (cmdQueue.length === 0) { + return + } + + let cmd = cmdQueue.shift() + executable.execMpc(cmd) + } + } + + // If something is happening on the queue let's have it settle on the mpd side. + Timer { + id: statusUpdateTimer + // If we populate the queue and send play we have to wait long enough to catch + // our own cmd. + interval: 2 * mpdCommandQueue.interval + onTriggered: { + mpdRoot.getQueue() + // Mpc spams a new "playlist" event for every song added to the queue, so + // maybe dozens if e.g. an album/playlist is added. Sometimes that's too + // fast for us to catch the last "player" event indicated the new populate + // queue started. We have to check what is playing after the queue + // changes. + mpdRoot.getInfo() + } + } + + // Mpc idle loop. After a mpc-event is registered and handled almost + // immediately reconnect the shut down connection. + Timer { + id: mpdRootIdleLoopTimer + interval: 10 + onTriggered: { + let clb = function (exitCode, stdout) { + if (exitCode !== 0) { + return + } + + // Restart the idle loop + mpdRootIdleLoopTimer.start() + + if (stdout.includes('player')) { + mpdRoot.getInfo() + } + + if (stdout.includes('mixer')) + mpdRoot.getVolume() + + if (stdout.includes('options')) + mpdRoot.getOptions() + + if (stdout.includes('playlist')) { + statusUpdateTimer.restart() + } + + if (stdout.includes('stored_playlist')) { + mpdRoot.getPlaylists() + } + } + executable.execMpc(mpdCmds.mpcIdleLoop, clb) + } + } + + // Handles network issues. E.g. if the network card needs a few seconds to + // become available after a system resume. Or the device is moved in and out + // of places with the mpd server (un)available. + Timer { + id: mpdRootNetworkTimeout + + property int startInterval: 500 + + interval: startInterval + running: false + triggeredOnStart: true + onTriggered: { + disconnect() + + // Gradually increase reconnect time until we find a minimum time + // necessary for a device stationary within the mpd network (desktop). + // At worst try a reconnect every minute (devices leaving the + // local network like laptops). + if (interval < 60000) + interval = interval + 500 + + mpdRoot.checkMpcConnectionAvailable() + } + } + + // Watchdog for system sleep/wake cycles. If we detect a "lost timespan" we + // assume the mpc idle connection is no longer valid and needs a reconnect. + Timer { + id: mpdRootReconnectTimer + + property int lastRun: Date.now() / 1000 + + interval: 2000 + running: true + repeat: true + onTriggered: { + if ((2 * interval / 1000 + lastRun) < (Date.now() / 1000)) { + mpdRoot.forceReloadEverything() + } + + lastRun = Date.now() / 1000 + } + } + + ExecMpc { + id: executable + } + + Connections { + function onExited(exitCode, stdout, stderr, exitStatus, cmd) { + main.appLastError = "" + if (exitCode !== 0) { + if (stderr.includes("No data")) { + // "No data" answer from mpd is a succesfull request for us. + return + } + main.appLastError = fmtErrorMessage(stderr) + mpdRootNetworkTimeout.start() + + return + } + main.appLastError = stderr || "" + } + + target: executable + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/VolumeState.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/VolumeState.qml new file mode 100644 index 00000000..7773253c --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/VolumeState.qml @@ -0,0 +1,121 @@ +import QtQuick 2.15 + +/** + * Decouples our internal volume state from immediatly reflecting mpd's + */ +Item { + id: root + + /** + * Our internal volume value that is considered as the "truth" by the UI + */ + property int volume: 50 + + function set(value) { + if (value < 0 || value > 100) { + throw new Error("Invalid argument: volume must be between 0 and 100, is " + value) + } + + // If one volume slider changes every other will update and therefore + // try to set that same value again. We ignore that identical value. + if (volume === value) { + return + } + + // Use int. Otherwise our value fights with mpd's if mpd sends back a + // value that doesn't fit the int step. + value = Math.round(value) + root.volume = value + + // Don't trigger sending to mpd again if we just received the "mixer" + // event value from mpd for our own value change. + + if (root.volume === mpdState.mpdVolume) { + return + } + + volumeDebounceTimer.value = value + // Don't use restart(). We don't want to send just the end value, + // the user has to receive volume change feedback while adjusting. + volumeDebounceTimer.start() + // Use restart(), we only care about the final value here and don't + // want to receive data we send before, but is outdated now (slider + // janks back to an older value). + volumeReceiverTimer.restart() + } + + /** + * Change volume by a volume step + * + * @param {int} Value to change the current volume on a 0 to 100 scale + */ + function change(value) { + value = root.volume + value + value = value < 0 ? 0 : value + value = value > 100 ? 100 : value + set(value) + } + + /** + * Takes a raw wheel input value, transforms into a volume value and applies + * + * @param {int} Raw mouse wheel value + */ + function wheel(value) { + // Wheel value is 120 int per "click". So divide by 120 for volume +/- 1. + // Hope it works for your mouse, it does for mine. Good luck. + let valueChangePerClick = 120 + let desiredVolumeChangePerClick = 2 + let volumeChange = value / valueChangePerClick * desiredVolumeChangePerClick + change(volumeChange) + } + + Connections { + target: mpdState + function onMpdVolumeChanged() { + // We want to react to volume changes not comming from us. But we + // have to respect the time window we set for our own debounce-send + // to pass - It could be us. So we have to wait for at least that + // amount of time. Since the timer takes care of the volume update + // if it was us we return early and let the timer handle it. + if (volumeReceiverTimer.running) { + return + } + // So it wasn't us, let's adjust our volume to the mpd state. + root.volume = mpdState.mpdVolume + } + } + + /** + * Debounce updating our "truth" from mpd + */ + Timer { + id: volumeReceiverTimer + property int value + // We have to at least wait for the time of our own send debounce-send to + // pass, otherwise we "jank back" to a previous, outdated value mpdState + // just received. Also wait at least a second, otherwise mpd may still + // serve the old value. + interval: 2 * volumeDebounceTimer.interval < 2000 ? 2000 : 2 * volumeDebounceTimer.interval + onTriggered: { + if (root.volume !== mpdState.mpdVolume) { + root.volume = mpdState.mpdVolume + } + } + } + + /** + * Debounce volume sending + * + * Don't send every volume event our input devices generate. Plasma and mpd + * (or someone along the way down) feel much to crash happy about that. + */ + Timer { + id: volumeDebounceTimer + property int value + interval: 100 + onTriggered: { + mpdState.setVolume(value) + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/coverHelpers.js b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/coverHelpers.js new file mode 100644 index 00000000..a1c1ecc2 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/coverHelpers.js @@ -0,0 +1,84 @@ +/** + * Implements a simple priority queue + */ +class FetchQueue { + constructor() { + this._queue = {} + // this._debug = true + } + + /** + * Adds item to the queue + * + * @param {string} id ID for the queue item + * @param {*} data Data for the item + * @param {int} priority Priority in the queue (the lower the number the higher the priority) + */ + add(id, data, priority) { + // @BOGUS only happens on actual plasma desktop, never in the simulator + if (typeof(data) === 'undefined') { + return + } + if (this._queue[id] && this._queue[id].priority < priority) { + // Already exists with higher priority, don't lower it by accident + return + } + this._queue[id] = { + // Looks silly. But alas sometimes if you just do a "data: data" it will + // store the whole queue-item as empty and therefore undefined. Don't know + // why. Looks like there could be an issue if the key is a file-ID instead + // of the album?? - Spend to much time on it already. This works. + data: { + "album": data.album, + "albumartist": data.albumartist, + "artist": data.artist, + "file": data.file, + }, + priority: priority + } + this._debugMsg(`Added ${id} with priority ${priority}`) + } + + /** + * Returns the next item in the queue by highest priority + * + * @returns Data of the item in the queue + */ + next() { + let keys = Object.keys(this._queue); + if (!keys || keys.length === 0) + return false; + + let nextItem + // let nextItem = this._queue[keys[0]] + keys.forEach(key => { + if (!nextItem) { + nextItem = this._queue[key] + } + else { + if (this._queue[key].priority < nextItem.priority) { + nextItem = this._queue[key] + } + } + }, this) + + this._debugMsg(`next() returned ${nextItem.data.file} with priority ${nextItem.priority}`) + return nextItem.data + } + + /** + * Deletes item from queue + * + * @param {string} id Id in queue + */ + delete(id) { + delete this._queue[id] + } + + _debugMsg(msg) { + if (!this._debug) { + return + } + console.log("FetchQueue - " + msg) + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/songLibrary.js b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/songLibrary.js new file mode 100644 index 00000000..f471788a --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/logic/songLibrary.js @@ -0,0 +1,119 @@ +class SongLibrary { + constructor(library) { + this._albums = {} + + this._buildAlbums(library) + } + + _buildAlbums(library) { + library.forEach(song => { + if (!song.albumartist || !song.album) { + return + } + if (!this._albums[song.albumartist]) { + this._albums[song.albumartist] = {} + } + if (!this._albums[song.albumartist][song.album]) { + this._albums[song.albumartist][song.album] = [] + } + this._albums[song.albumartist][song.album].push(song) + }, this) + } + + getSongsByAartistAndAlbum(album, albumartist) { + return this._albums[albumartist][album] + } + + getSongsOfAartist(aartist) { + let songs = [] + for (const album in this._albums[aartist]) { + this._albums[aartist][album].forEach(function (song) { + songs.push(song) + }) + } + return this._songSorter(songs) + } + + /** + * Returns one(!) song for every album of the aartist + * + * @param {string} albumartist + * @returns {array} of songs + */ + getASongsByAartistPerAlbum(albumartist) { + let songs = [] + for (const album in this._albums[albumartist]) { + songs.push(this._albums[albumartist][album][0]) + } + + return this._songSorter(songs) + } + + _songSorter(songs) { + return songs.sort((a, b) => { + if (a.date !== "" && b.date !== "") { + let aDate = parseInt(a.date) + let bDate = parseInt(b.date) + if (aDate > bDate) return 1 + if (aDate < bDate) return -1 + } + + let aAlbum = a.album.toLowerCase() + let bAlbum = b.album.toLowerCase() + if (aAlbum > bAlbum) return 1 + if (aAlbum < bAlbum) return -1 + + if (a.tracknumber !== "" && b.tracknumber !== "") { + let aTrack = a.tracknumber !== "" ? parseInt(a.tracknumber) : 0 + let bTrack = b.tracknumber !== "" ? parseInt(b.tracknumber) : 0 + + if (aTrack > bTrack) return 1 + if (aTrack < bTrack) return -1 + } + + return 0 + }) + } + + /** + * Searches albumartist, album and title for a search term + * + * @param {string} searchText text to search for + * @returns {array} List of albumartists + */ + searchAlbumartists(searchText = "") { + let found = [] + + if (searchText === "") { + found = Object.keys(this._albums) + } else { + searchText = searchText.toLowerCase() + onFound: + for (const aartist in this._albums) { + if (aartist.toLowerCase().indexOf(searchText) !== -1) { + found.push(aartist) + continue onFound + } + for (const album in this._albums[aartist]) { + if (album.toLowerCase().indexOf(searchText) !== -1) { + found.push(aartist) + continue onFound + } + + for (let i = 0; i < this._albums[aartist][album].length; i++) { + if (this._albums[aartist][album][i].title.toLowerCase().indexOf(searchText) !== -1) { + found.push(aartist) + continue onFound + } + } + } + } + } + + found.sort((a, b) => { + return a.toLowerCase() > b.toLowerCase() ? 1 : -1 + }) + + return found + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/scripts/downloadCover.sh b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/scripts/downloadCover.sh new file mode 100644 index 00000000..327a24c8 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/scripts/downloadCover.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +# Script args: +# 1: mpd host address +# 2: mpd file path +# 3: Path to cover directory +# 4: Prefix for cover file name +# 5: filename + +# Check if imagemagick is installed +if ! command -v convert &> /dev/null +then + echo "No data" + exit 0 +fi + +# Create cover path +if [ ! -d "${3}" ]; then + mkdir -p "${3}" +fi +# Use hash as cover identifier in path +coverPath="${3}/${5}" + +# Running multiple widget instances on the same system: Some other widget on the same +# system already started to request a cover, so this instance wont and waits instead. +lockfile="${coverPath}.lock" +if [ -f "${lockfile}" ]; then + i=1 + # Observed worst case download time so far 30 seconds + waitTarget=60 + while [ -f "${lockfile}" -a $i -lt $waitTarget ]; do + sleep 1 + ((i = i + 1)) + done + # Alas sometimes things go wrong while downloading, e.g. a plasmashell crash. This + # recovers eventually. + if [ $i = $waitTarget ]; then + rm "${lockfile}" + fi +else + # Migrating from from 4.x to 5.0: remove old, unprocessed images without suffix + if [ -f "${coverPath}" ]; then + rm "${coverPath}" + fi +fi + +if [ ! -f "${coverPath}" ]; then + touch "${lockfile}" + mpc --host=${1} readpicture "${2}" >"${coverPath}" 2>&1 + + # @SOMEDAY find a more efficient solution + if grep -q volume "${coverPath}"; then + echo "No data" + else + convert "${coverPath}" -resize 1500x\> "${coverPath}-large.jpg" + convert "${coverPath}" -resize 64x64 "${coverPath}-small.jpg" + fi + + rm "${coverPath}" + rm "${lockfile}" +fi + +exit 0 diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/scripts/formatHelpers.js b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/scripts/formatHelpers.js new file mode 100644 index 00000000..c9793602 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/scripts/formatHelpers.js @@ -0,0 +1,36 @@ +.pragma library + +function title(mpdItem) { + let title = mpdItem.title; + if (mpdItem.tracknumber) + title = mpdItem.tracknumber + ". " + title; + + return title; +} + +function artist(mpdItem) { + return mpdItem.artist || mpdItem.albumartist || ""; +} + +function album(mpdItem) { + let album = mpdItem.album || ""; + if (album && mpdItem.date) + album += " (" + mpdItem.date + ")"; + + return album +} + +function queueAlbumLine(model) { + let line = [] + line.push(model.tracknumber ? model.tracknumber + ". " : "") + + if (model.album) { + line.push(model.album + " ") + } + if (model.time) { + line.push("(" + model.time + ")") + } + + return line.join("") +} + diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Albumartists/AlbumartistSongsPage.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Albumartists/AlbumartistSongsPage.qml new file mode 100644 index 00000000..c39e5e99 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Albumartists/AlbumartistSongsPage.qml @@ -0,0 +1,29 @@ +import QtQuick 2.15 +import org.kde.kirigami 2.20 as Kirigami +import "../Songlist" + +Kirigami.ScrollablePage { + id: root + + property alias songs: listView.songs + + SonglistView { + id: listView + + property var songs + + delegate: SonglistItem { + id: songlistItem + parentView: listView + alternatingBackground: true + carretIndex: listView.currentIndex + } + + Component.onCompleted: { + listView.model.clear() + listView.songs.forEach(function (song) { + listView.model.append(song) + }) + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Albumartists/AlbumartistsPage.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Albumartists/AlbumartistsPage.qml new file mode 100644 index 00000000..5106c517 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Albumartists/AlbumartistsPage.qml @@ -0,0 +1,267 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 as QQC2 +import QtQuick.Layouts 1.15 +import org.kde.kirigami 2.20 as Kirigami +import org.kde.plasma.components 2.0 as PlasmaComponents +import "../../Mpdw.js" as Mpdw +import "../../Components/Elements" + +Kirigami.ScrollablePage { + id: root + + property int depth: 1 + property string shownAlbumartist + readonly property string globalShortcut: "2" + + visible: false + + globalToolBarStyle: Kirigami.ApplicationHeaderStyle.None + header: QQC2.ToolBar { + RowLayout { + anchors.fill: parent + GlobalNav { } + RowLayout { + Layout.fillWidth: true + Layout.alignment: Qt.AlignRight + Layout.rightMargin: Kirigami.Units.gritUnit + Kirigami.SearchField { + id: searchField + // Per default the text field is stuck at 200 width and cut off at + // small sizes + implicitWidth: root.width > 400 ? 200 : root.width / 2 + placeholderText: qsTr("Search…") + onTextChanged: listView.filter(text) + + Keys.onEscapePressed: { + if (searchField.text) { + searchField.text = "" + } else { + listView.forceActiveFocus() + } + } + Shortcut { + sequence: StandardKey.Find + onActivated: { + if (!searchField.visible) { + appWindow.showPage(albumartistsPage) + } + searchField.forceActiveFocus() + } + } + } + } + } + } + + ListViewGeneric { + id: listView + + /** + * Populates list model with hits according ot search field content + * + * @param {string} searchtext + */ + function filter(searchText = "") { + if (searchText) { + searchText = searchText.toLowerCase() + } + + model.clear() + let hits = mpdState.library.searchAlbumartists(searchText) + hits.forEach(hit => { + let item = { + "albumartist": hit + } + model.append(item) + }) + } + + model: ListModel { + id: model + } + + delegate: SwipeListItemGeneric { + id: listItemPlaylist + + width: ListView.view ? ListView.view.width : implicitWidth + + + contentItem: MouseArea { + implicitHeight: mainLayout.implicitHeight + implicitWidth: mainLayout.implicitWidth + + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: function (mouse) { + if (mouse.button === Qt.RightButton) { + if (!artistContextMenuLoader.item) { + artistContextMenuLoader.sourceComponent = contextMenuComponent + } + if (!artistContextMenuLoader.item.visible) { + artistContextMenuLoader.item.popup() + } + + return + } + + shownAlbumartist = model.albumartist + let properties = { + "depth": root.depth + 1, + "songs": mpdState.library.getSongsOfAartist(model.albumartist), + "title": model.albumartist, + } + appWindow.pageStack.push(Qt.resolvedUrl("AlbumartistSongsPage.qml"), properties) + } + + Loader { + id: artistContextMenuLoader + property var getSongs: function () { + return mpdState.library.getSongsOfAartist(model.albumartist) + } + } + + RowLayout { + id: mainLayout + // Layout.fillWidth: true + anchors.fill: parent + QQC2.Label { + Layout.fillHeight: true + Layout.fillWidth: true + text: model.albumartist + wrapMode: Text.Wrap + } + + GridLayout { + columns: appWindow.narrowLayout ? 4 : 6 + rows: appWindow.narrowLayout ? 1 : -1 + + Layout.alignment: Qt.AlignRight + Repeater { + id: images + model: ListModel {} + delegate: ListCoverimage { + id: image + loadingPriority: 200 + + QQC2.ToolTip { + text: model.album + delay: -1 + visible: mouseArea.containsMouse + } + + MouseArea { + id: mouseArea + hoverEnabled: true + anchors.fill: image + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: { + if (mouse.button == Qt.LeftButton) { + let properties = { + "depth": root.depth + 1, + "songs": mpdState.library.getSongsByAartistAndAlbum( + model.album, + model.albumartist), + // @i18n + "title": model.album + " - " + model.albumartist, + } + appWindow.pageStack.push(Qt.resolvedUrl("AlbumartistSongsPage.qml"), + properties) + } else if (mouse.button == Qt.RightButton) { + if (!contextMenuLoader.item) { + contextMenuLoader.sourceComponent = contextMenuComponent + } + if (!contextMenuLoader.item.visible) { + contextMenuLoader.item.popup() + } + } + } + + Loader { + id: contextMenuLoader + property var getSongs: function () { + return mpdState.library.getSongsByAartistAndAlbum(model.album, + model.albumartist) + } + } + } + } + } + + Component.onCompleted: { + let songs = mpdState.library.getASongsByAartistPerAlbum(model.albumartist) + songs.forEach(function (song) { + images.model.append(song) + }) + } + } + } + } + } + + Connections { + target: mpdState + function onLibraryChanged() { + listView.filter() + } + } + + Component.onCompleted: { + mpdState.getLibrary() + } + } + + Component { + id: contextMenuComponent + QQC2.Menu { + id: contextMenu + QQC2.MenuItem { + icon.name: Mpdw.icons.queuePlay + text: qsTr("Play") + onTriggered: { + let songs = getSongs() + mpdState.replaceQueue(songs.map(song => song.file)) + } + } + QQC2.MenuSeparator {} + QQC2.MenuItem { + text: qsTr("Append") + icon.name: Mpdw.icons.queueAppend + onTriggered: { + let songs = getSongs() + mpdState.addSongsToQueue(songs.map(song => song.file)) + } + } + QQC2.MenuItem { + text: qsTr("Insert") + icon.name:Mpdw.icons.queueInsert + onTriggered: { + let songs = getSongs() + mpdState.addSongsToQueue(songs.map(song => song.file), "insert") + } + } + } + + } + + + /* + // @FEATURE figure out how to keep the second column visible in width layout + Timer { + id: fooTimer + interval: 0 + onTriggered: { + appWindow.pageStack.push(Qt.resolvedUrl("AlbumartistSongsPage.qml"), { + "depth": root.depth + 1, + "songs": root.songs + }) + } + } + + onVisibleChanged: { + if (visible && shownAlbumartist) { + if (appWindow.width > 720) { + fooTimer.start() + } + } + } + */ +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Application/ApplicationWindow.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Application/ApplicationWindow.qml new file mode 100644 index 00000000..7de35d69 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Application/ApplicationWindow.qml @@ -0,0 +1,314 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.15 +import org.kde.kirigami 2.20 as Kirigami +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.core 2.0 as PlasmaCore +import "./../../Mpdw.js" as Mpdw +import "./../../Components/" +import "./../../Components/Albumartists" +import "./../../Components/Application" +import "./../../Components/Queue" +import "./../../Components/Playlists" +import "../../../scripts/formatHelpers.js" as FormatHelpers + +Kirigami.ApplicationWindow { + id: root + + property bool narrowLayout: appWindow.width < 520 + property int windowPreMinimizeSize: -1 + property int initialHeight: -1 + + flags: Qt.Window + title: qsTr("MPD") + maximumWidth: 719 + minimumWidth: 250 + minimumHeight: footer.height + + pageStack.initialPage: queuePage +// pageStack.initialPage: albumartistsPage + + function showPage(page) { + if (!page.visible) { + while (appWindow.pageStack.depth > 0) + appWindow.pageStack.pop() + appWindow.pageStack.push(page) + } + } + + Component.onCompleted: { + if (initialHeight > 800) { + height = initialHeight + } + } + + QueuePage { + id: queuePage + } + + PlaylistsPage { + id: playlistPage + } + + AlbumartistsPage { + id: albumartistsPage + } + + Repeater { + model: [queuePage, albumartistsPage, playlistPage] + Item { + Shortcut { + sequence: modelData.globalShortcut + onActivated: showPage(modelData) + } + } + } + + footer: ToolBar { + RowLayout { + anchors.fill: parent + RowLayout { + Layout.margins: Kirigami.Units.smallSpacing + spacing: Kirigami.Units.smallSpacing + Layout.alignment: Qt.AlignRight + Layout.fillHeight: true + Layout.fillWidth: true + + WidgetCoverImage { + id: coverImage + Layout.preferredHeight: songinfo.height + Layout.preferredWidth: songinfo.height + + sourceSize.height: songinfo.height + sourceSize.width: songinfo.height + + MouseArea { + anchors.fill: coverImage + acceptedButtons: Qt.MiddleButton + onClicked: function (mouse) { + if (mouse.button === Qt.MiddleButton) { + if (root.windowPreMinimizeSize === -1) { + root.minimize() + } else { + root.maximize() + } + } + } + } + } + + ColumnLayout { + id: songinfo + spacing: 0 + Layout.minimumWidth: 50 + Layout.minimumHeight: 50 + Layout.fillWidth: true + Text { + id: songTitle + Layout.fillWidth: true + Layout.leftMargin: Kirigami.Units.largeSpacing + Layout.bottomMargin: (appWindow.narrowLayout) ? Kirigami.Units.largeSpacing : 0 + color: Kirigami.Theme.textColor + font.bold: !appWindow.narrowLayout + elide: Text.ElideRight + Connections { + function onMpdInfoChanged() { + songTitle.text = FormatHelpers.title(mpdState.mpdInfo) + } + target: mpdState + } + } + Text { + id: songArtist + visible: !appWindow.narrowLayout + Layout.fillWidth: true + Layout.leftMargin: Kirigami.Units.largeSpacing + color: Kirigami.Theme.textColor + elide: Text.ElideRight + + Connections { + function onMpdInfoChanged() { + songArtist.text = FormatHelpers.artist(mpdState.mpdInfo) + } + target: mpdState + } + } + + Text { + id: songAlbum + visible: !appWindow.narrowLayout + Layout.fillWidth: true + Layout.leftMargin: Kirigami.Units.largeSpacing + Layout.bottomMargin: Kirigami.Units.largeSpacing + color: Kirigami.Theme.textColor + elide: Text.ElideRight + + Connections { + function onMpdInfoChanged() { + songAlbum.text = FormatHelpers.album(mpdState.mpdInfo) + } + target: mpdState + } + } + + RowLayout { + Layout.fillWidth: true + RowLayout { + Layout.leftMargin: Kirigami.Units.largeSpacing + ToolButton { + id: ppBtn + icon.name: mpdState.mpdPlaying ? Mpdw.icons.queuePause : Mpdw.icons.queuePlay + function toggle() { mpdState.toggle() } + onClicked: ppBtn.toggle() + Shortcut { + sequence: "p" + onActivated: ppBtn.toggle() + } + ToolTip { text: qsTr("Starts and pauses playback") + " (P)" } + } + + ToolButton { + id: volmBtn + icon.name: volumeState.volume > 75 + ? Mpdw.icons.volumeHigh + : volumeState.volume > 25 + ? Mpdw.icons.volumeMedium + : volumeState.volume > 0 + ? Mpdw.icons.volumeLow + : Mpdw.icons.volumeMuted + text: volumeState.volume + ToolTip {text: qsTr("Volume (+/=/-/Scroll Wheel)")} + Shortcut { + sequences: ["+", "="] + onActivated: volumeState.change(2) + } + Shortcut { + sequence: "-" + onActivated: volumeState.change(-2) + } + MouseArea { + anchors.fill: parent + onClicked: function (mouse) { + volmSlider.visible = volmSlider.visible? false : true + } + onWheel: function (wheel) { + volumeState.wheel(wheel.angleDelta.y) + } + } + + ToolTip { + id: volmSlider + delay: -1 + x: volmBtn.x - volmSlider.width / 2 + y: volmBtn.y + // visible: true // debug + contentItem: RowLayout { + height:parent.height + Kirigami.Icon { + Layout.preferredWidth: Kirigami.Units.iconSizes.small + Layout.fillHeight: false + source: Mpdw.icons.volumeMuted + } + PlasmaComponents.Slider { + id: volumeSlider + minimumValue: 0 + maximumValue: 100 + stepSize: 1 + onValueChanged: volumeState.set(volumeSlider.value) + value: volumeState.volume + } + Kirigami.Icon { + Layout.preferredWidth: Kirigami.Units.iconSizes.small + Layout.fillHeight: false + source: Mpdw.icons.volumeHigh + } + + } + } + } + } + + RowLayout { + Layout.fillWidth: true + Layout.rightMargin: Kirigami.Units.largeSpacing + + // Layout.alignment: Qt.AlignRight + Item { Layout.fillWidth: true } + + Repeater { + model: [ + mpdToggleRepeatAct, + mpdToggleRandomAct, + mpdToggleConsumeAct, + ] + MpdToggleOptionItem {} + } + } + } + } + } + } + } + + Kirigami.Action { + id: mpdToggleRepeatAct + property string mpdOption: "repeat" + text: qsTr("Repeat") + icon.name: Mpdw.icons.queueRepeat + shortcut: "Shift+Z" + tooltip: "Toggle MPD's Repeat mode" + onTriggered: { mpdState.toggleOption("repeat") } + } + + Kirigami.Action { + id: mpdToggleRandomAct + property string mpdOption: "random" + text: qsTr("Random") + icon.name: Mpdw.icons.queueRandom + shortcut: "Z" + tooltip: "Toggle MPD's Random mode" + onTriggered: { mpdState.toggleOption("random") } + } + Kirigami.Action { + id: mpdToggleConsumeAct + property string mpdOption: "consume" + text: qsTr("Consume") + icon.name: Mpdw.icons.queueConsume + shortcut: "R" + tooltip: "Toggle MPD's Consume mode" + onTriggered: { mpdState.toggleOption("consume") } + } + + Kirigami.Action { + shortcut: "F10" + onTriggered: { + if (!debugWindowLoader.item) { + debugWindowLoader.source = "./../../Components/Debug/DebugIcons.qml" + } else { + debugWindowLoader.item.visible = debugWindowLoader.item.visible ? false : true + } + } + } + Loader { + id: debugWindowLoader + } + + function minimize() { + windowPreMinimizeSize = root.height + root.height = footer.height + } + + function maximize() { + root.height = windowPreMinimizeSize + windowPreMinimizeSize = -1 + } + + Connections { + target: root + function onHeightChanged() { + if (root.height > footer.height) { + windowPreMinimizeSize = -1 + } + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Application/MpdToggleOptionItem.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Application/MpdToggleOptionItem.qml new file mode 100644 index 00000000..33eebfdf --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Application/MpdToggleOptionItem.qml @@ -0,0 +1,34 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 as QQC2 + +QQC2.ToolButton { + id: root + + checkable: true + icon.name: modelData.icon.name + visible: !appWindow.narrowLayout || checked + + QQC2.ToolTip { + text: modelData.tooltip + " (" + modelData.shortcut.toUpperCase() + ")" + } + + onCheckedChanged: { + let localState = mpdState.mpdOptions[modelData.mpdOption] === "on" + if (root.checked === localState) { + return + } + modelData.onTriggered() + } + + Connections { + function onMpdOptionsChanged() { + // This catches us getting our own cmd replied, so don't act on it. + let localState = mpdState.mpdOptions[modelData.mpdOption] === "on" + if (root.checked === localState) { + return + } + root.checked = mpdState.mpdOptions[modelData.mpdOption] === "on" + } + target: mpdState + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Debug/DebugIcons.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Debug/DebugIcons.qml new file mode 100644 index 00000000..ac633cad --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Debug/DebugIcons.qml @@ -0,0 +1,33 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 as QQC2 +import QtQuick.Layouts 1.15 +import org.kde.kirigami 2.20 as Kirigami +import "../../Mpdw.js" as Mpdw + +Kirigami.ApplicationWindow { + id: root + + Kirigami.ScrollablePage { + anchors.fill: parent + + GridLayout { + columns: 3 + + Repeater { + model: Object.keys(Mpdw.icons).map(function(title) { + return {title: title, icon: Mpdw.icons[title]} + }) + delegate: RowLayout { + Kirigami.Icon { + source: modelData.icon + } + QQC2.Label { + Layout.preferredWidth: 200 + text: modelData.title + } + } + + } + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/DialogConfirm.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/DialogConfirm.qml new file mode 100644 index 00000000..7baebe74 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/DialogConfirm.qml @@ -0,0 +1,55 @@ +import QtQuick 2.15 +import org.kde.kirigami 2.20 as Kirigami +import org.kde.plasma.components 2.0 as PlasmaComponents +import "../../Mpdw.js" as Mpdw + +Kirigami.PromptDialog { + id: root + + property alias icon: icon.source + property alias label: label.text + property alias buttonText: actionButton.text + property alias itemTitle: item.text + // @SOMEDAY figure out how to use as a property + property var onConfirmed: null + + standardButtons: Kirigami.Dialog.NoButton + showCloseButton: false + + customFooterActions: [ + Kirigami.Action { + id: actionButton + iconName: Mpdw.icons.dialogOk + onTriggered: { + if (onConfirmed) { + onConfirmed() + } + } + }, + Kirigami.Action { + text: qsTr("Cancel") + iconName: Mpdw.icons.dialogCancel + onTriggered: { + root.close() + } + } + ] + + Row { + spacing: Kirigami.Units.largeSpacing + Kirigami.Icon { + id: icon + height: Kirigami.Units.iconSizes.huge + width: Kirigami.Units.iconSizes.huge + } + Column { + PlasmaComponents.Label { + id: label + } + PlasmaComponents.Label { + id: item + font.weight: Font.Bold + } + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/GlobalNav.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/GlobalNav.qml new file mode 100644 index 00000000..6867b0f7 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/GlobalNav.qml @@ -0,0 +1,44 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 as QQC2 +import QtQuick.Layouts 1.15 +import "../../Mpdw.js" as Mpdw + +RowLayout { + Repeater { + model: [ + { + icon: Mpdw.icons.placeQueue, + page: queuePage, + shortcut: queuePage.globalShortcut, + text: qsTr("Queue"), + tooltip: qsTr("Show Queue") + }, + { + icon: Mpdw.icons.placeArtist, + page: albumartistsPage, + shortcut: albumartistsPage.globalShortcut, + text: qsTr("Artists"), + tooltip: qsTr("Show Artists") + }, + { + icon: Mpdw.icons.placePlaylist, + page: playlistPage, + shortcut: playlistPage.globalShortcut, + text: qsTr("Playlists"), + tooltip: qsTr("Show Playlists"), + } + ] + + QQC2.ToolButton { + icon.name: modelData.icon + text: appWindow.narrowLayout ? "" : modelData.text + checkable: true + checked: modelData.page.visible + onClicked: appWindow.showPage(modelData.page) + + QQC2.ToolTip { + text: modelData.tooltip + " (" + modelData.shortcut + ")" + } + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/ListCoverimage.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/ListCoverimage.qml new file mode 100644 index 00000000..410d5b9d --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/ListCoverimage.qml @@ -0,0 +1,86 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 as QQC2 +import QtQuick.Layouts 1.15 +import org.kde.kirigami 2.20 as Kirigami +import "./../../Mpdw.js" as Mpdw + +Item { + id: root + + property alias loadingPriority: image.loadingPriority + property bool isSelected: false + + Layout.preferredHeight: appWindow.narrowLayout ? Kirigami.Units.iconSizes.medium : Kirigami.Units.iconSizes.large + Layout.preferredWidth: appWindow.narrowLayout ? Kirigami.Units.iconSizes.medium : Kirigami.Units.iconSizes.large + + Kirigami.Icon { + id: coverPlaceholderIcon + source: Mpdw.icons.queuePlaceholderCover + anchors.fill: parent + visible: !image.source.toString() + } + + Image { + id: image + anchors.fill: parent + + property int loadingPriority: 100 + + mipmap: true + fillMode: Image.PreserveAspectFit + + sourceSize.height: Kirigami.Units.iconSizes.large + sourceSize.width: Kirigami.Units.iconSizes.large + + function setCover(coverPath) { + if (coverPath === null) { + return false + } + image.source = coverPath + "-small.jpg" + } + + function onGotCover(id) { + // @BOGUS Why did we do that? What's happening here? + if (typeof (coverManager) === "undefined") { + return + } + let coverPath = coverManager.getCover(model) + if (coverPath === undefined) { + return false + } + coverManager.gotCover.disconnect(onGotCover) + setCover(coverPath) + } + + Component.onCompleted: { + if (model.orphaned) { + return + } + + let coverPath = coverManager.getCover(model, loadingPriority) + if (coverPath) { + setCover(coverPath) + + return + } + coverManager.gotCover.connect(onGotCover) + } + } + + Rectangle { + readonly property int offset: 4 + height: Kirigami.Units.iconSizes.medium / 2 + width: Kirigami.Units.iconSizes.medium / 2 + x: parent.width - width + offset + y: parent.width - height + offset + color: Kirigami.Theme.activeBackgroundColor + border.color: Kirigami.Theme.hoverColor + visible: isSelected + + Kirigami.Icon { + color: Kirigami.Theme.activeTextColor + source: Mpdw.icons.selectMarker + anchors.fill: parent + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/ListViewGeneric.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/ListViewGeneric.qml new file mode 100644 index 00000000..05757e36 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/ListViewGeneric.qml @@ -0,0 +1,82 @@ +import QtQuick 2.15 + +ListView { + id: root + + // Scroll without animation when active item changes + highlightMoveDuration: 0 + + Keys.onPressed: { + event.accepted = true + + if (event.key === Qt.Key_PageUp) { + let xPos = root.contentX + let yPos = root.contentY + let height = root.height + + let yBottom = yPos + height + if (root.header) { + yBottom -= root.headerItem.height + } + + let topIndex = root.indexAt(xPos, yPos) + let bottomIndex = root.indexAt(xPos, yBottom) + + let scrollAdjustment = 1 + let itemsPerPage = bottomIndex - topIndex - scrollAdjustment + + if (itemsPerPage <= 0) { + itemsPerPage = scrollAdjustment + } + let newPosition = topIndex - itemsPerPage + + if (newPosition < 0) { + newPosition = 0 + } + + root.positionViewAtIndex(newPosition, root.Beginning) + root.currentIndex = newPosition + + return + } + + if (event.key === Qt.Key_PageDown) { + let bottomIndex = root.indexAt(root.contentX, root.contentY + root.height) + if (bottomIndex === -1) { + // We bottomed out + bottomIndex = root.count - 1 + } + root.positionViewAtIndex(bottomIndex, root.Beginning) + root.currentIndex = bottomIndex + return + } + + if (event.key === Qt.Key_Home) { + root.positionViewAtIndex(0, root.Beginning) + root.currentIndex = 0 + return + } + + if (event.key === Qt.Key_End) { + root.positionViewAtIndex(root.count - 1, root.Beginning) + root.currentIndex = root.count - 1 + return + } + + if (event.key === Qt.Key_Up) { + let newIndex = root.currentIndex - 1 + if (newIndex >= 0) { + root.currentIndex = newIndex + } + return + } + + if (event.key === Qt.Key_Down) { + let newIndex = root.currentIndex + 1 + if (newIndex < root.count) { + root.currentIndex = newIndex + } + return + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/SwipeListItemGeneric.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/SwipeListItemGeneric.qml new file mode 100644 index 00000000..6b0c6ba7 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Elements/SwipeListItemGeneric.qml @@ -0,0 +1,20 @@ +import QtQuick 2.15 +import org.kde.kirigami 2.20 as Kirigami + + +Kirigami.SwipeListItem { + property int highlightIndex: -1 + property int carretIndex: -1 + + width: root.width ? root.width : implicitWidth + + backgroundColor: + (highlightIndex !== index) + ? Kirigami.Theme.backgroundColor + : Kirigami.Theme.highlightColor + alternatingBackground: true + alternateBackgroundColor: + (highlightIndex !== index) + ? Kirigami.Theme.alternateBackgroundColor + : Kirigami.Theme.highlightColor +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Playlists/PlaylistSongsPage.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Playlists/PlaylistSongsPage.qml new file mode 100644 index 00000000..3e65ec30 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Playlists/PlaylistSongsPage.qml @@ -0,0 +1,36 @@ +import QtQuick 2.15 +import org.kde.kirigami 2.20 as Kirigami +import "../../Components/Songlist" + +Kirigami.ScrollablePage { + id: root + + property alias playlistId: listView.playlistId + + SonglistView { + id: listView + + property string playlistId + + delegate: SonglistItem { + id: songlistItem + parentView: listView + carretIndex: listView.currentIndex + } + + Component.onCompleted: { + mpdState.getPlaylist(playlistId) + } + + Connections { + function onGotPlaylist(playlistData) { + listView.model.clear() + for (let i in playlistData) { + listView.model.append(playlistData[i]) + } + } + + target: mpdState + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Playlists/PlaylistsPage.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Playlists/PlaylistsPage.qml new file mode 100644 index 00000000..0f59995d --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Playlists/PlaylistsPage.qml @@ -0,0 +1,117 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.15 +import org.kde.kirigami 2.20 as Kirigami +import org.kde.plasma.components 2.0 as PlasmaComponents +import "../../Mpdw.js" as Mpdw +import "../../Components/Elements" + +Kirigami.ScrollablePage { + id: root + + property int depth: 1 + readonly property string globalShortcut: "3" + + visible: false + title: qsTr("Playlists") + + globalToolBarStyle: Kirigami.ApplicationHeaderStyle.None + header: ToolBar { + RowLayout { + anchors.fill: parent + GlobalNav { } + } + } + + Component { + id: delegateComponentPlaylists + + SwipeListItemGeneric { + id: listItemPlaylist + + onClicked: { + let properties = { + "depth": root.depth + 1, + "playlistId": model.title, + "title": model.title, + } + appWindow.pageStack.push(Qt.resolvedUrl("PlaylistSongsPage.qml"), properties) + } + width: ListView.view ? ListView.view.width : implicitWidth + actions: [ + Kirigami.Action { + icon.name: Mpdw.icons.queuePlay + text: qsTr("Play") + onTriggered: { + mpdState.playPlaylist(model.title) + } + }, + Kirigami.Action { + icon.name: Mpdw.icons.queueAppend + text: qsTr("Append") + onTriggered: { + mpdState.addPlaylistToQueue(model.title) + } + }, + Kirigami.Action { + icon.name: Mpdw.icons.playlistDelete + text: qsTr("Remove Playlist…") + onTriggered: { + deleteConfirmationDialog.open() + } + } + ] + + contentItem: RowLayout { + Label { + Layout.fillWidth: true + height: Math.max(implicitHeight, Kirigami.Units.iconSizes.smallMedium) + text: model.title + wrapMode: Text.Wrap + } + DialogConfirm { + id: deleteConfirmationDialog + icon: Mpdw.icons.playlistDelete + title: qsTr("Delete Playlist") + label: qsTr("The following playlist will be deleted") + buttonText: qsTr("Delete Playlist") + itemTitle: model.title + + onConfirmed: function () { + mpdState.removePlaylist(model.title) + deleteConfirmationDialog.close() + } + } + } + } + } + + ListViewGeneric { + id: playlistList + + delegate: delegateComponentPlaylists + + Connections { + function onMpdPlaylistsChanged() { + playlistList.model.clear() + let playlists = mpdState.mpdPlaylists + for (let i in playlists) { + playlistList.model.append({ + "title": playlists[i] + }) + } + } + + target: mpdState + } + + model: ListModel {} + + moveDisplaced: Transition { + YAnimator { + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Queue/QueueDialogReplacePl.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Queue/QueueDialogReplacePl.qml new file mode 100644 index 00000000..276c803d --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Queue/QueueDialogReplacePl.qml @@ -0,0 +1,58 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 as QQC2 +import QtQuick.Layouts 1.15 +import org.kde.kirigami 2.20 as Kirigami +import org.kde.plasma.components 2.0 as PlasmaComponents +import "../../Mpdw.js" as Mpdw + +Kirigami.PromptDialog { + id: root + title: qsTr("Save Queue and Replace Playlist…") + standardButtons: Kirigami.Dialog.NoButton + showCloseButton: false + + function selectPlaylist(playlist) { + let found = listCombo.find(playlist) + if (found !== -1) { + listCombo.currentIndex = found + } + } + + customFooterActions: [ + Kirigami.Action { + text: qsTr("Replace Playlist") + id: actionButton + iconName: Mpdw.icons.dialogOk + onTriggered: { + mpdState.removePlaylist(listCombo.currentText) + mpdState.saveQueueAsPlaylist(listCombo.currentText) + root.close() + } + }, + Kirigami.Action { + text: qsTr("Cancel") + iconName: Mpdw.icons.dialogCancel + onTriggered: { + root.close() + } + } + ] + + QQC2.ComboBox { + id: listCombo + model: ListModel {} + Connections { + function onMpdPlaylistsChanged() { + listCombo.model.clear() + let playlists = mpdState.mpdPlaylists + for (let i in playlists) { + listCombo.model.append({ + "title": playlists[i] + }) + } + } + + target: mpdState + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Queue/QueueDialogSave.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Queue/QueueDialogSave.qml new file mode 100644 index 00000000..52bf0e03 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Queue/QueueDialogSave.qml @@ -0,0 +1,106 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 as QQC2 +import QtQuick.Layouts 1.15 +import org.kde.kirigami 2.20 as Kirigami +import org.kde.plasma.components 2.0 as PlasmaComponents +import "../../Mpdw.js" as Mpdw +import "../Elements" + +Kirigami.PromptDialog { + id: root + title: qsTr("Save Queue as New Playlist") + standardButtons: Kirigami.Dialog.NoButton + showCloseButton: false + + customFooterActions: [ + Kirigami.Action { + text: qsTr("Save") + id: actionButton + iconName: Mpdw.icons.dialogOk + enabled: !newPlaylistTitle.playlistTitleExists && newPlaylistTitle.text + onTriggered: { + mpdState.onSaveQueueAsPlaylist.connect(afterSave) + mpdState.saveQueueAsPlaylist(newPlaylistTitle.text) + } + + function afterSave(success) { + if (success) { + newPlaylistErrorMsg.visible = false + showPassiveNotification(qsTr('Saved'), 1000) + root.close() + } else { + newPlaylistErrorMsg.visible = true + } + mpdState.onSaveQueueAsPlaylist.disconnect(afterSave) + } + }, + Kirigami.Action { + text: qsTr("Cancel") + iconName: Mpdw.icons.dialogCancel + onTriggered: { + root.close() + } + } + ] + + ColumnLayout { + QQC2.TextField { + id: newPlaylistTitle + Layout.fillWidth: true + property bool playlistTitleExists + placeholderText: qsTr("New Playlist Name…") + // Doesn't work due to animation(?), we use a timer instead. + + function updatePlaylistTitleExists() { + playlistTitleExists = mpdState.mpdPlaylists.indexOf(text) !== -1 + } + + onTextChanged: { + updatePlaylistTitleExists() + } + + Connections { + function onMpdPlaylistsChanged() { + newPlaylistTitle.updatePlaylistTitleExists() + } + target: mpdState + } + + Connections { + function onVisibleChanged() { + if (root.visible) { + waitForAnimationToFinish.start() + } + } + target: root + } + + Timer { + id: waitForAnimationToFinish + running: false + interval: Kirigami.Units.longDuration + onTriggered: { + newPlaylistTitle.forceActiveFocus() + } + } + + } + + Kirigami.InlineMessage { + id: msg + Layout.fillWidth: true + visible: newPlaylistTitle.playlistTitleExists + type: Kirigami.MessageType.Warning + text: qsTr("Playlist with same name already exists.") + } + + Kirigami.InlineMessage { + id: newPlaylistErrorMsg + Layout.fillWidth: true + visible: false + type: Kirigami.MessageType.Error + // @SOMEDAY Better text + text: qsTr("Saving playlist failed.") + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Queue/QueuePage.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Queue/QueuePage.qml new file mode 100644 index 00000000..fc5852b6 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Queue/QueuePage.qml @@ -0,0 +1,309 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.0 +import org.kde.kirigami 2.20 as Kirigami +import "../../Mpdw.js" as Mpdw +import "../../Components/Elements" +import "../../Components/Songlist" +import "../../Components/Queue" + +Kirigami.ScrollablePage { + id: queuePage + + readonly property string globalShortcut: "1" + + Layout.fillWidth: true + title: qsTr("Queue") + visible: false + + globalToolBarStyle: Kirigami.ApplicationHeaderStyle.None + header: ToolBar { + RowLayout { + anchors.fill: parent + GlobalNav { } + RowLayout { + Kirigami.ActionToolBar { + id: actionToolBar + alignment: Qt.AlignRight + + actions: [ + Kirigami.Action { + id: followCurrentSong + text: qsTr("Follow Playing Song") + icon.name: Mpdw.icons.queueFollowMode + tooltip: qsTr("Follow Mode - Scroll the queue to keep the currently playing song visible.") + " (" + qsTr("L") + ")" // @i18n + shortcut: "shift+l" + displayHint: Kirigami.DisplayHint.IconOnly + checkable: true + checked: true + }, + Kirigami.Action { + text: qsTr("Queue") + Kirigami.Action { + icon.name: Mpdw.icons.queueSaveNew + text: qsTr("Save as New Playlist…") + shortcut: "s" + onTriggered: { + queueDialogSave.open() + } + } + Kirigami.Action { + icon.name: Mpdw.icons.queueSaveReplace + text: qsTr("Replace Playlist…") + shortcut: "shift+s" + onTriggered: { + queueDialogReplacePl.open() + } + } + Kirigami.Action { + separator: true + } + Kirigami.Action { + icon.name: mpdToggleConsumeAct.icon.name + text: mpdToggleConsumeAct.text + shortcut: mpdToggleConsumeAct.shortcut + tooltip: mpdToggleConsumeAct.tooltip + onTriggered: mpdToggleConsumeAct.onTriggered() + } + Kirigami.Action { + icon.name: mpdToggleRandomAct.icon.name + text: mpdToggleRandomAct.text + shortcut: mpdToggleRandomAct.shortcut + tooltip: mpdToggleRandomAct.tooltip + onTriggered: mpdToggleRandomAct.onTriggered() + } + Kirigami.Action { + icon.name: mpdToggleRepeatAct.icon.name + text: mpdToggleRepeatAct.text + shortcut: mpdToggleRepeatAct.shortcut + tooltip: mpdToggleRepeatAct.tooltip + onTriggered: mpdToggleRepeatAct.onTriggered() + } + Kirigami.Action { + separator: true + } + Kirigami.Action { + text: qsTr("Clear Queue") + icon.name: Mpdw.icons.queueClear + tooltip: text + " (" + qsTr("Shift+C") + ")" // @i18n + shortcut: "shift+c" + displayHint: Kirigami.DisplayHint.IconOnly + onTriggered: { + mpdState.clearQueue() + } + } + } + ] + } + } + } + } + + + SonglistView { + id: songlistView + + header: SonglistHeader { + leftActions: [ + Kirigami.Action { + id: rmSelctBtn + text: qsTr("Remove") + tooltip: qsTr("Remove Selected Songs") + icon.name: Mpdw.icons.queueRemoveSelected + shortcut: "Del" + enabled: numberSelected + onTriggered: { + let positions = songlistView.getSelectedPositionsMpdBased() + songlistView.removeSelection() + songlistView.updateMpdPositions() + mpdState.removeFromQueue(positions) + } + } + ] + // @TODO Should be default action of SonglistView without repeating here + rightActions: [ + Kirigami.Action { + text: appWindow.narrowLayout ? "" : qsTr("Deselect") + tooltip: qsTr("Deselect All") + icon.name: Mpdw.icons.selectNone + shortcut: "Shift+D" + onTriggered: { + songlistView.deselectAll() + } + } + ] + } + + function showCurrentItemInList() { + if (!appWindow.visible) { + return + } + + let index = mpdState.mpdInfo.position - 1 + songlistView.currentIndex = index + centerInView(index) + } + + onSelectedChanged: { + // @TODO + songlistView.headerItem.numberSelected = selected.length + } + + Kirigami.PlaceholderMessage { + anchors.centerIn: parent + width: parent.width - (Kirigami.Units.largeSpacing * 4) + text: qsTr("Queue is empty") + visible: !mpdState.countQueue() + } + + delegate: SonglistItem { + id: songlistItem + + coverLoadingPriority: 50 + isSortable: true + parentView: songlistView + playingIndex: mpdState.mpdInfo.position ? mpdState.mpdInfo.position - 1 : -1 + carretIndex: songlistView.currentIndex + + actions: [ + Kirigami.Action { + icon.name: (playingIndex === model.index && mpdState.mpdPlaying) + ? Mpdw.icons.queuePause + : Mpdw.icons.queuePlay + text: qsTr("Play Now") + onTriggered: { + if (playingIndex === model.index) { + mpdState.toggle() + } else { + mpdState.playInQueue(model.position) + } + } + }, + Kirigami.Action { + icon.name: Mpdw.icons.queueRemoveSingle + text: qsTr("Remove from Queue") + visible: !appWindow.narrowLayout + onTriggered: { + let index = model.index + songlistView.model.remove(index) + songlistView.updateMpdPositions() + mpdState.removeFromQueue([index + 1]) + } + } + ] + } + + Keys.onPressed: { + if (event.key === Qt.Key_L) { + songlistView.showCurrentItemInList() + } + } + + Connections { + function onUserInteracted() { + if (!followCurrentSong.checked) { + return + } + followCurrentSong.checked = false + disableFollowOnEditTimer.restart() + } + } + + Timer { + id: disableFollowOnEditTimer + interval: 120000 + onTriggered: { + followCurrentSong.checked = true + songlistView.showCurrentItemInList() + } + } + } + + Connections { + target: mpdState + + function onMpdQueueChanged() { + // Queue is empty, clear everything + if (mpdState.mpdQueue.length === 0) { + songlistView.model.clear() + return + } + + var i = 0 + for (i; i < mpdState.mpdQueue.length; i++) { + let mpdSong = mpdState.mpdQueue[i] + let ourSong = songlistView.model.get(i) + + //console.log("------- Queue Refresh Item ---------") + //console.log(`mpd-file: ${mpdSong.file}`) + + if (ourSong) { + // console.log(`our-file: ${ourSong.file}`) + if (mpdSong.file === ourSong.file) { + //console.log('Keeping our song.') + // As long as mpd-queue matches ours do nothing + continue + } else { + // Clear out selection (cache) of the item + songlistView.select(i, false) + // console.log('Removing our song.') + songlistView.model.remove(i) + } + + } + songlistView.model.insert(i, mpdSong) + } + + // Remove all additional items in our queue not in mpd's + for (let k = songlistView.count - 1; k >= i; k--) { + songlistView.model.remove(k) + } + + if (followCurrentSong.checked) { + songlistView.showCurrentItemInList() + } + } + + function onMpdInfoChanged() { + if (followCurrentSong.checked) { + songlistView.showCurrentItemInList() + } + } + + function onPlayedPlaylist(playlist) { + queueDialogReplacePl.selectPlaylist(playlist) + } + } + + Component.onCompleted: { + // @BOGUS Initiates triggering populating Queue and Playlists on app + // window opening. Make it ask properly for the already available data from + // mpdState in both places. Required for Loader those pages anyway. + mpdState.update() + } + + Connections { + target: appWindow + function onHeightChanged() { + if (followCurrentSong.checked) { + songlistView.showCurrentItemInList() + } + } + } + + onVisibleChanged: { + if (visible) { + songlistView.forceActiveFocus() + } + } + + // @SOMEDAY loader + QueueDialogSave { + id: queueDialogSave + } + + // @SOMEDAY loader + QueueDialogReplacePl { + id: queueDialogReplacePl + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistHeader.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistHeader.qml new file mode 100644 index 00000000..8d0b7d25 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistHeader.qml @@ -0,0 +1,81 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.15 as QQC2 +import org.kde.kirigami 2.20 as Kirigami +import QtGraphicalEffects 1.12 + +Item { + id: root + + property list leftActions + property list rightActions + property int numberSelected: 0 + + z: 10 + width: parent.width + height: row.height + + Rectangle + { + id: background + height: row.height + width: root.width + color: Kirigami.Theme.backgroundColor + } + + // Drop Shadow + Rectangle + { + height: 4 + width: root.width + anchors.top: background.bottom + + gradient: Gradient { + GradientStop { + position: 0.00; + color: "#33000000" + } + GradientStop { + position: 1.00; + color: "#00000000"; + } + } + } + + Component { + id: btnCmpt + + QQC2.Button{ + required property var modelData + icon.name: modelData.icon.name + text: appWindow.narrowLayout ? "" : modelData.text + onClicked: modelData.triggered() + enabled: modelData.enabled + flat: true + QQC2.ToolTip { + text: modelData.tooltip + (modelData.shortcut ? " (" + modelData.shortcut + ")" : "") + } + } + } + + RowLayout { + id: row + width: root.width + + RowLayout { + Layout.fillWidth: true + Repeater { + model: root.leftActions + delegate: btnCmpt + } + } + + RowLayout { + Layout.alignment: Qt.AlignRight + Repeater { + model: root.rightActions + delegate: btnCmpt + } + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistItem.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistItem.qml new file mode 100644 index 00000000..b63a58f2 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistItem.qml @@ -0,0 +1,142 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.0 +import org.kde.kirigami 2.20 as Kirigami +import "../../Components/Elements" +import "../../../scripts/formatHelpers.js" as FmH + +Item { + id: root + + property alias actions: listItem.actions + property alias alternatingBackground: listItem.alternatingBackground + property alias coverLoadingPriority: image.loadingPriority + property bool isSortable: false + property int carretIndex: -1 + property int playingIndex: -1 + property SonglistView parentView + + width: parentView.width + implicitHeight: listItem.implicitHeight + + SwipeListItemGeneric { + id: listItem + + highlightIndex: playingIndex + + MouseArea { + implicitHeight: mainLayout.implicitHeight + implicitWidth: mainLayout.implicitWidth + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: function (mouse) { + parentView.userInteracted() + if (mouse.button === Qt.LeftButton) { + if (mouse.modifiers & Qt.ShiftModifier) { + parentView.selectTo(index) + } else if (mouse.modifiers & Qt.ControlModifier) { + parentView.selectToggle(index) + } else { + parentView.selectToggle(index) + } + parent.forceActiveFocus() + parentView.currentIndex = index + } + if (mouse.button === Qt.RightButton) { + menuLoader.source = "SonglistItemContextMenu.qml" + if (!menuLoader.item.visible) { + menuLoader.item.popup() + } + } + } + + Loader { + id: menuLoader + } + + RowLayout { + id: mainLayout + width: root.width + // Without we don't have word wrap with the text below! + anchors.fill: parent + + Kirigami.ListItemDragHandle { + property int startIndex: -1 + property int endIndex + visible: isSortable + + Layout.preferredWidth: Kirigami.Units.iconSizes.medium + Layout.leftMargin: -Kirigami.Units.gridUnit / 2 + + listItem: listItem + listView: parentView + onMoveRequested: (oldIndex, newIndex) => { + if (startIndex === -1) { + startIndex = oldIndex + } + endIndex = newIndex + listView.model.move(oldIndex, newIndex, 1) + } + onDropped: { + parentView.userInteracted() + if (startIndex !== endIndex) { + mpdState.moveInQueue(startIndex + 1, endIndex + 1) + } + + startIndex = -1 + } + } + + ListCoverimage { + id: image + isSelected: model.checked + } + + Rectangle { + id: cursorMarker + Layout.fillHeight: true + width: Kirigami.Units.smallSpacing + opacity: carretIndex === index + color: playingIndex === index ? Kirigami.Theme.activeBackgroundColor : Kirigami.Theme.hoverColor + } + + // We need a layout-"anchor" for the MouseArea *and* to allow + // fillWide-aware word-wrap on the text fields + ColumnLayout { + id: mouseAreaAnchor + spacing: 0 + Layout.fillHeight: true + + ColumnLayout { + spacing: 0 + Text { + Layout.fillWidth: true + Layout.rightMargin: Kirigami.Units.small + color: (playingIndex === index) ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor + font.bold: !appWindow.narrowLayout + text: appWindow.narrowLayout ? FmH.title(model) : model.title + wrapMode: Text.WordWrap + } + Text { + visible: !appWindow.narrowLayout + Layout.fillWidth: true + Layout.rightMargin: Kirigami.Units.small + color: (playingIndex === index) ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.disabledTextColor + text: FmH.artist(model) + wrapMode: Text.WordWrap + } + + Text { + visible: !appWindow.narrowLayout + Layout.fillWidth: true + Layout.rightMargin: Kirigami.Units.small + color: (playingIndex === index) ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.disabledTextColor + text: FmH.queueAlbumLine(model) + wrapMode: Text.WordWrap + } + } + } + } + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistItemContextMenu.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistItemContextMenu.qml new file mode 100644 index 00000000..5b0bb369 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistItemContextMenu.qml @@ -0,0 +1,53 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 as QQC2 +import "../../Mpdw.js" as Mpdw + +QQC2.Menu { + id: contextMenu + QQC2.MenuItem { + text: qsTr('Select Album') + icon.name: Mpdw.icons.selectAlbum + onTriggered: { + parentView.selectNeighborsByAlbum(model, index) + } + } + QQC2.MenuItem { + text: qsTr('Select Album-Artist') + icon.name: Mpdw.icons.selectArtist + onTriggered: { + parentView.selectNeighborsByAartist(model, index) + } + } + QQC2.MenuSeparator {} + QQC2.MenuItem { + text: qsTr('Select Above') + icon.name: Mpdw.icons.selectAbove + onTriggered: { + parentView.selectAbove(index) + } + enabled: index > 0 + } + QQC2.MenuItem { + text: qsTr('Select Below') + icon.name: Mpdw.icons.selectBelow + onTriggered: { + parentView.selectBelow(index) + } + enabled: index < parentView.count - 1 + } + QQC2.MenuSeparator {} + QQC2.MenuItem { + text: qsTr("Select All") + icon.name: Mpdw.icons.selectAll + onTriggered: { + parentView.selectAll(true) + } + } + QQC2.MenuItem { + text: qsTr("Deselect") + icon.name: Mpdw.icons.selectNone + onTriggered: { + parentView.deselectAll() + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistModel.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistModel.qml new file mode 100644 index 00000000..d68a6b42 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistModel.qml @@ -0,0 +1,53 @@ +import QtQuick 2.15 +import org.kde.kirigami 2.20 as Kirigami + +ListModel { + id: root + + + /** + * Keep the "position" on our end in sync with MPD expeded result + * + * @param {int} start position 0-based + * @param {int} end position 0-based + */ + // @TODO double still + function updateMpdPositions(from = 0, to) { + to = to || count - 1 + if (from === to) { return } + + let start = to < from ? to : from + let end = to > from ? to : from + + for (let i = start; i <= end; i++) { + root.model.set(i, {"position": i+1+""}) + } + + return + } + + onRowsInserted: { + for(let i = first; i <= last; i++) { + let data = { + // Autoinitialize the checked property for item selection + "checked": false, + // MPD can giv us a song but has no information about it except + // "file". This can happen if a file is listed in loaded + // playlist but the actual file is missing on disk. + "orphaned": false, + } + + let insertedSong = root.get(i) + if (insertedSong.time === "") { + data.title = insertedSong.file + data.orphaned = true + } + + root.set(i, data) + } + } + + onRowsMoved: { + updateMpdPositions(start, row - 1) + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistView.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistView.qml new file mode 100644 index 00000000..734c9a88 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/Songlist/SonglistView.qml @@ -0,0 +1,338 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.0 +import org.kde.kirigami 2.20 as Kirigami +import "../../Mpdw.js" as Mpdw +import "../../Components/Elements" + +ListViewGeneric { + id: root + + signal userInteracted() + + /** + * Last selected item + * + * Used for selecting ranges. + */ + property int selectLastSelected: -1 + + /** + * List of the currently selected items + * + * Mostly for performance so we don't have to constantly query all models + */ + // @TODO do we really need it if we keep click without deselect? + property var selected: [] + + /** + * Set selection state of an list-item + * + * This shall be the only place actually changing the model data + * + * @param {int|array} indices Index or list of indices + * @param {bool} state select (true, default) or deselect (false) + */ + function select(indices, state = true) { + if (Number.isInteger(indices)) { + indices = [indices] + } + if (!Array.isArray(indices)) { + throw new Error("Invalid argument: indices must be an int or array") + } + + for (let i = indices.length - 1; i >= 0; i--) { + let index = indices[i] + var existsAtPosition = selected.indexOf(index) + if ((existsAtPosition > -1 && state) || (existsAtPosition === -1 && !state)) { + continue + } + + model.setProperty(index, "checked", state) + selectLastSelected = state ? index : -1 + + if (state) { + selected.push(index) + } else { + selected.splice(existsAtPosition, 1) + } + } + + selected.sort(function(a, b) { return a - b; }) + selectedChanged() + } + + function selectToggle(index) { + let newState = !model.get(index).checked + select(index, newState) + } + + function selectAll() { + select(Array.from({length: model.count}, (v,i) => i), true) + } + + function deselectAll() { + if (selected.length === 0) { + return + } + select(selected, false) + } + + function selectTo(to) { + if (selectLastSelected === -1 || selectLastSelected === to) { + return + } + if (to > selectLastSelected) { + for (var i = selectLastSelected; i <= to; i++) { + select(i) + } + } else { + for (var k = selectLastSelected; k >= to; k--) { + select(k) + } + } + } + + function selectNeighborsByAlbum(song, index, state = true) { + let positions = _getNeighbors(song, index, (a, b) => { return a.album === b.album }) + select(positions, state) + } + + function selectNeighborsByAartist(song, index, state = true) { + let positions = _getNeighbors(song, index, (a, b) => { return a.albumartist === b.albumartist }) + select(positions, state) + } + + function _getNeighbors(song, index, comparator) { + let found = [index] + // find previous + var i + for (i = index - 1; i >= 0; i--) { + var mdl = model.get(i) + if (comparator(song, mdl)) { + found.push(i) + } else { + break + } + } + // find next + for (i = index + 1; i < model.count; i++) { + let mdl = model.get(i) + if (comparator(song, mdl)) { + found.push(i) + } else { + break + } + } + + found.sort(function (a, b) { + return a - b; + }) + + return found + } + + function selectAbove(index) { + for (let i = 0; i < index; i++) { + select(i) + } + } + + function selectBelow(index) { + for (let i = index + 1 ; i < model.count; i++) { + select(i) + } + } + + function getSelectedSongs() { + return selected.map(function(index) { return model.get(index) }) + } + + function getSelected() { + return selected; + } + + function getSelectedPositionsMpdBased() { + return getSelected().map(function(position) { return position + 1 }) + } + + function removeSelection() { + let positions = getSelected() + + // removing from bottom otherwise the index of lower elements changes + for (let i = positions.length - 1; i >= 0; i--) { + model.remove(positions[i], 1) + } + } + + // @TODO rename; listen to model? + function updateMpdPositions(from) { + selected = [] + for (var i = 0; i < model.count; i++) { + if (model.get(i).checked) { + selected.push(i) + } + // @TODO still + model.set(i, {"position": i+1+""}) + } + } + + /** + * Get all the selected files in the list or all if none is selected + * + * @return {array} selected files + */ + function getSelectedFilesOrAll() { + let files = [] + var i + + for (i = 0; i < model.count; i++) { + let song = model.get(i) + if (song.checked === true ) { + files.push(song.file) + } + } + + if (files.length === 0) { + for (i = 0; i < model.count; i++) { + files.push(model.get(i).file) + } + } + + return files + } + + function centerInView(index) { + songlistView.positionViewAtIndex(index, ListView.Center) + } + + Keys.onPressed: { + if (event.key === Qt.Key_A) { + if (event.modifiers & Qt.ControlModifier) { + root.selectAll() + } + } else if (event.key === Qt.Key_B) { + let state = !(event.modifiers & Qt.ShiftModifier) + root.selectNeighborsByAlbum(model.get(root.currentIndex), root.currentIndex, state) + } + event.accepted = true + } + + + Keys.onUpPressed: { + if (root.currentIndex > 0) { + if (event.modifiers & Qt.ShiftModifier) { + root.select(root.currentIndex) + } + root.positionViewAtIndex(root.currentIndex, ListView.Contain) + root.currentIndex-- + } + + if (event.modifiers && (Qt.ShiftModifier)) { + root.select(root.currentIndex) + } + userInteracted() + event.accepted = true + } + + Keys.onDownPressed: { + if (root.currentIndex < root.count - 1) { + if (event.modifiers & Qt.ShiftModifier) { + root.select(root.currentIndex) + } + root.positionViewAtIndex(root.currentIndex, ListView.Contain) + root.currentIndex++ + } + + if (event.modifiers && Qt.ShiftModifier) { + root.select(root.currentIndex) + } + userInteracted() + event.accepted = true + } + + Keys.onSpacePressed: { + if (selectEndOfListDebounceTimer.running) { + selectEndOfListDebounceTimer.restart() + return + } else { + root.selectToggle(root.currentIndex) + } + + if (root.currentIndex < root.count - 1) { + root.positionViewAtIndex(root.currentIndex, ListView.Contain) + root.currentIndex++ + } else { + selectEndOfListDebounceTimer.start() + } + userInteracted() + event.accepted = true + } + + Keys.onReturnPressed: { + let position = model.get(root.currentIndex).position + mpdState.playInQueue(position) + userInteracted() + event.accepted = true + } + + Timer { + id: selectEndOfListDebounceTimer + interval: 400 + } + + // onCountChanged: { + // } + + model: SonglistModel {} + + moveDisplaced: Transition { + YAnimator { + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } + } + + + headerPositioning: ListView.OverlayHeader + header: SonglistHeader { + leftActions: [ + Kirigami.Action { + text: qsTr("Play") + tooltip: qsTr("Replace Queue and Start Playing") + icon.name: Mpdw.icons.queuePlay + onTriggered: { + mpdState.replaceQueue(getSelectedFilesOrAll()) + } + }, + Kirigami.Action { + text: qsTr("Append") + icon.name: Mpdw.icons.queueAppend + tooltip: qsTr("Append to End of Queue") + onTriggered: { + mpdState.addSongsToQueue(getSelectedFilesOrAll()) + } + + }, + Kirigami.Action { + text: qsTr("Insert") + tooltip: qsTr("Insert After Current Song") + icon.name: Mpdw.icons.queueInsert + onTriggered: { + mpdState.addSongsToQueue(getSelectedFilesOrAll(), "insert") + } + } + ] + rightActions: [ + Kirigami.Action { + text: appWindow.narrowLayout ? "" : qsTr("Deselect") + tooltip: qsTr("Deselect All") + icon.name: Mpdw.icons.selectNone + shortcut: "Shift+D" + onTriggered: { + root.deselectAll() + } + } + ] + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/WidgetCoverImage.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/WidgetCoverImage.qml new file mode 100644 index 00000000..623e5bd4 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/WidgetCoverImage.qml @@ -0,0 +1,147 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.15 +import QtGraphicalEffects 1.12 +import org.kde.kirigami 2.20 as Kirigami +import "./../Mpdw.js" as Mpdw + +Item { + id: coverImageContainer + + property alias sourceSize: coverImage.sourceSize + + property int coverRadius: 0 + property int shadowSpread: 0 + property string shadowColor + + Layout.fillHeight: true + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: function (mouse) { + if (mouse.button === Qt.LeftButton) { + mpdState.toggle() + } else if (mouse.button === Qt.RightButton) { + if (!contextMenuLoader.item) { + contextMenuLoader.sourceComponent = contextMenuComponent + } + if (contextMenuLoader.item.visible) { + contextMenuLoader.item.close() + } else { + contextMenuLoader.item.popup() + } + + } + } + + onWheel: function (wheel) { + volumeState.wheel(wheel.angleDelta.y) + } + onDoubleClicked: { + mpdState.playNext() + } + + Loader { + id: contextMenuLoader + } + + Component { + id: contextMenuComponent + Menu { + id: contextMenu + MenuItem { + text: qsTr("Update MPD Data") + icon.name: Mpdw.icons.mpdUpdate + onTriggered: { + mpdState.forceReloadEverything() + } + } + MenuSeparator {} + MenuItem { + text: qsTr("Clear Cover Cache") + icon.name: Mpdw.icons.clearCache + onTriggered: { + coverManager.clearCache() + } + } + } + } + } + + Kirigami.Icon { + id: coverPlaceholderIcon + source: Mpdw.icons.queuePlaceholderCover + anchors.fill: parent + visible: !coverImage.source.toString() + } + + Image { + id: coverImage + + visible: false + mipmap: true + anchors.fill: parent + Layout.maximumWidth: height > height ? width : height + fillMode: Image.PreserveAspectFit + + function updateCover() { + let cover = coverManager.getCover(mpdState.mpdInfo, 1) + if (typeof (cover) === "undefined") { + coverManager.gotCover.connect(updateCover) + return + } + coverManager.gotCover.disconnect(updateCover) + if (cover === null) { + coverImage.source = "" + return + } + // Force QML to update even if cover file stays the same. This helps if + // the cover "got stuck" for whatever reason: a play next even in the same + // album will always trigger. + coverImage.source = "" + coverImage.source = cover + "-large.jpg" + } + + Connections { + function onMpdInfoChanged() { + coverImage.updateCover() + } + + function onMpdQueueChanged() { + if (mpdState.countQueue() === 0) { + coverImage.source = "" + } + } + target: mpdState + } + } + + Item { + id: mask + anchors.fill: coverImage + visible: false + + Rectangle { + color: "white" + radius: coverRadius + anchors.centerIn: parent + width: coverImage.paintedWidth + height: coverImage.paintedHeight + } + } + + OpacityMask { + anchors.fill: coverImage + source: coverImage + maskSource: mask + + layer.enabled: shadowSpread > 0 && !!coverImage.source.toString() + layer.effect: DropShadow { + verticalOffset: 0 + horizontalOffset: 0 + color: shadowColor + radius: shadowSpread + samples: 17 + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/WidgetLabel.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/WidgetLabel.qml new file mode 100644 index 00000000..5a3917ad --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Components/WidgetLabel.qml @@ -0,0 +1,25 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.15 +import QtGraphicalEffects 1.12 +import org.kde.plasma.components 2.0 as PlasmaComponents + +PlasmaComponents.Label { + property int fontSize + + font.pointSize: cfgFontSize + horizontalAlignment: cfgAlignment == 2 ? Text.AlignRight : (cfgAlignment == 1 ? Text.AlignHCenter : Text.AlignLeft) + elide: Text.ElideRight + Layout.fillWidth: true + + layer.enabled: !cfgSolidBackground + // @TODO looks to strong in light plasma theme/desktop background + layer.effect: DropShadow { + verticalOffset: 1 + horizontalOffset: 0 + color: "#66000000" + spread: 0.4 + radius: 6 + samples: 17 + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Config/configAppearance.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Config/configAppearance.qml new file mode 100644 index 00000000..4690111e --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Config/configAppearance.qml @@ -0,0 +1,119 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.5 +import QtQuick.Dialogs 1.0 +import QtQuick.Layouts 1.15 +import org.kde.kirigami 2.20 as Kirigami +import org.kde.kquickcontrols 2.0 as KQControls + +Kirigami.FormLayout { + id: root + + property alias cfg_cfgAlignment: cfgAlignment.selected + property alias cfg_cfgHorizontalLayout: cfgHorizontalLayout.checked + property alias cfg_cfgFontSize: cfgFontSize.value + property alias cfg_cfgCornerRadius: cfgCornerRadius.value + property alias cfg_cfgShadowSpread: cfgShadowSpread.value + property alias cfg_cfgShadowColor: cfgShadowColor.color + property alias cfg_cfgSolidBackground: cfgSolidBackground.checked + + Item { + Kirigami.FormData.label: i18n("Layout") + Kirigami.FormData.isSection: true + } + + CheckBox { + id: cfgHorizontalLayout + + Kirigami.FormData.label: i18n("Horizontal Layout:") + } + + CheckBox { + id: cfgSolidBackground + + Kirigami.FormData.label: i18n("Solid Background:") + } + + Item { + Kirigami.FormData.label: i18n("Text") + Kirigami.FormData.isSection: true + } + + GroupBox { + Kirigami.FormData.label: i18n("Text Alignment:") + + RowLayout { + id: cfgAlignment + + property int selected + + Component.onCompleted: { + if (selected === 1) + cfgAlignmentCenter.checked = true + else if (selected === 2) + cfgAlignmentRight.checked = true + } + + RadioButton { + id: cfgAlignmentLeft + + text: i18n("Left") + checked: true + onClicked: { + focus = true + cfgAlignment.selected = 0 + } + } + + RadioButton { + id: cfgAlignmentCenter + + text: i18n("Center") + onClicked: { + focus = true + cfgAlignment.selected = 1 + } + } + + RadioButton { + id: cfgAlignmentRight + + text: i18n("Right") + onClicked: { + focus = true + cfgAlignment.selected = 2 + } + } + } + } + + SpinBox { + id: cfgFontSize + + to: 1000 + Kirigami.FormData.label: i18n("Font Size:") + } + + Item { + Kirigami.FormData.label: i18n("Cover Image") + Kirigami.FormData.isSection: true + } + + SpinBox { + id: cfgCornerRadius + + to: 10000 + Kirigami.FormData.label: i18n("Corner Radius:") + } + + RowLayout { + Kirigami.FormData.label: i18n("Shadow Size and Color:") + SpinBox { + id: cfgShadowSpread + } + + KQControls.ColorButton { + id: cfgShadowColor + showAlphaChannel: true + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Config/configGeneral.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Config/configGeneral.qml new file mode 100644 index 00000000..074c0204 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Config/configGeneral.qml @@ -0,0 +1,71 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.5 +import QtQuick.Dialogs 1.0 +import QtQuick.Layouts 1.15 +import org.kde.kirigami 2.20 as Kirigami +import org.kde.kquickcontrols 2.0 as KQControls + +Kirigami.FormLayout { + id: page + + property alias cfg_cfgMpdHost: cfgMpdHost.text + property alias cfg_cfgCacheRoot: cfgCacheRoot.cleanPath + property alias cfg_cfgCacheForDays: cfgCacheForDays.value + property int cfg_foo: 1 + + Item { + Kirigami.FormData.label: i18n("MPD Connection") + Kirigami.FormData.isSection: true + } + + TextField { + id: cfgMpdHost + + Kirigami.FormData.label: i18n("MPD Server Address:") + placeholderText: i18n("192.168.y.x") + Layout.preferredWidth: 200 + } + + Item { + Kirigami.FormData.label: i18n("Local Covers") + Kirigami.FormData.isSection: true + } + + RowLayout { + Kirigami.FormData.label: i18n("Path to Cover Folder:") + + TextField { + id: cfgCacheRootText + + text: cfgCacheRoot.cleanPath + placeholderText: i18n("No file selected.") + Layout.preferredWidth: 200 + } + + Button { + text: i18n("Select Folder") + onClicked: cfgCacheRoot.open() + } + + FileDialog { + id: cfgCacheRoot + + property string cleanPath + + selectFolder: true + title: i18n("Please Choose a Folder") + folder: shortcuts.home + onAccepted: { + cleanPath = decodeURIComponent(cfgCacheRoot.fileUrl.toString( + ).replace(/^file:\/\//, "")) + } + } + } + + SpinBox { + id: cfgCacheForDays + + Kirigami.FormData.label: i18n("Cache Covers for Days:") + } + +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Mpdw.js b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Mpdw.js new file mode 100644 index 00000000..1d552f1b --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/Mpdw.js @@ -0,0 +1,46 @@ +.pragma library + +const icons = { + queuePlay: "media-playback-start", + queuePause: "media-playback-pause", + queueAppend: "media-playlist-append", + queueInsert: "timeline-insert", + queueConsume: "draw-eraser", + queueRandom: "media-playlist-shuffle", + queueRepeat: "media-playlist-repeat", + queueFollowMode: "mark-location", + queueSaveNew: "document-save-as", + queueSaveReplace: "document-replace", + queueRemoveSingle: "edit-delete", + queueRemoveSelected: "edit-delete-remove", + queueClear: "edit-delete", + queuePlaceholderCover: "media-default-album", + + playlistDelete: "edit-delete", + + selectAll: "edit-select-all-symbolic", + selectNone: "edit-select-none", + selectAbove: "arrow-up", + selectBelow: "arrow-down", + selectAlbum: "media-album-cover", + selectArtist: "view-media-artist", + selectMarker: "object-select-symbolic", + + placeQueue: "media-playback-playing", + placeArtist: "view-media-artist", + placePlaylist: "view-media-playlist", + + dialogOk: "dialog-ok", + dialogCancel: "dialog-cancel", + dialogClose: "dialog-close", + + volumeMuted: "audio-volume-muted", + volumeLow: "audio-volume-low", + volumeMedium: "audio-volume-medium", + volumeHigh: "audio-volume-high", + + appConfigGeneral: "configure", + appConfigAppearance: "preferences-desktop-color", + clearCache: "emblem-warning", + mpdUpdate: "view-refresh", +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/WidgetLayout.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/WidgetLayout.qml new file mode 100644 index 00000000..0c67ca42 --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/WidgetLayout.qml @@ -0,0 +1,164 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.15 +import QtGraphicalEffects 1.12 +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.kirigami 2.20 as Kirigami +import "./Mpdw.js" as Mpdw +import "./Components" +import "./Components/Queue" +import "../scripts/formatHelpers.js" as FormatHelpers + +Item { + id: root + + anchors.fill: parent + + GridLayout { + columns: cfgHorizontalLayout ? 3 : 1 + rows: cfgHorizontalLayout ? 1 : 3 + anchors.fill: parent + + // Cover Image + WidgetCoverImage { + id: coverImageContainer + + coverRadius: cfgCornerRadius + shadowColor: cfgShadowColor + shadowSpread: cfgShadowSpread + + onHeightChanged: sourceSizeTimer.restart() + onWidthChanged: sourceSizeTimer.restart() + + // Delay setting the source otherwise resizing the widget is very shoppy. + Timer { + id: sourceSizeTimer + interval: 1000 + onTriggered: { + coverImageContainer.sourceSize.height = height + coverImageContainer.sourceSize.width = height + } + } + + Component.onCompleted: { + sourceSizeTimer.start() + } + + Layout.minimumWidth: cfgHorizontalLayout ? parent.height : parent.width + } + + // Volume Slider + PlasmaComponents.Slider { + id: volumeSlider + + Layout.fillHeight: cfgHorizontalLayout + Layout.fillWidth: !cfgHorizontalLayout + Layout.leftMargin: !cfgHorizontalLayout ? Kirigami.Units.largeSpacing : 0 + Layout.rightMargin: !cfgHorizontalLayout ? Kirigami.Units.largeSpacing : 0 + + // Orientation bugged? Hide on horizontal layout for now + // See: https://bugs.kde.org/show_bug.cgi?id=474611 + // Layout.maximumWidth: cfgHorizontalLayout ? 15 : -1 + // orientation: cfgHorizontalLayout ? Qt.Vertical : Qt.Horizontal + visible: !cfgHorizontalLayout + minimumValue: 0 + maximumValue: 100 + stepSize: 1 + onValueChanged: volumeState.set(volumeSlider.value) + value: volumeState.volume + } + + // Title + ColumnLayout { + id: descriptionContainer + Layout.leftMargin: Kirigami.Units.largeSpacing + Layout.rightMargin: Kirigami.Units.largeSpacing + + ColumnLayout { + WidgetLabel { + id: songTitle + font.weight: Font.Bold + Connections { + function onMpdInfoChanged() { + songTitle.text = FormatHelpers.title(mpdState.mpdInfo) + } + function onMpdQueueChanged() { + if (mpdState.countQueue() === 0) { + songTitle.text = "" + } + } + target: mpdState + } + } + + WidgetLabel { + id: songArtist + Connections { + function onMpdInfoChanged() { + songArtist.text = FormatHelpers.artist(mpdState.mpdInfo) + } + function onMpdQueueChanged() { + songArtist.font.italic = false + if (mpdState.countQueue() === 0) { + songArtist.font.italic = true + songArtist.text = qsTr("Queue is empty") + return + } + + } + target: mpdState + } + } + + WidgetLabel { + id: songAlbum + Connections { + function onMpdInfoChanged() { + songAlbum.text = FormatHelpers.album(mpdState.mpdInfo) + } + function onMpdQueueChanged() { + if (mpdState.countQueue() === 0) { + songAlbum.text = "" + } + } + target: mpdState + } + } + + MouseArea { + width: parent.width + height: parent.height + onClicked: { + main.toggleAppWindow() + } + } + } + + // Notifications + RowLayout { + visible: !!notification.text + WidgetLabel { + id: notification + + visible: text.length > 0 + font.italic: true + + Connections { + function onAppLastErrorChanged() { + notification.text = main.appLastError + } + + target: main + } + } + + ToolButton { + icon.name: Mpdw.icons.dialogClose + icon.height: Kirigami.Units.iconSizes.small + icon.width: Kirigami.Units.iconSizes.small + onClicked: notification.text = '' + } + } + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/main.qml b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/main.qml new file mode 100644 index 00000000..b380544e --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/contents/ui/main.qml @@ -0,0 +1,89 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.15 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.plasmoid 2.0 +import "./../logic" + +Item { + id: main + + property alias appWindow: appWindowLoader.item + property bool cfgHorizontalLayout: Plasmoid.configuration.cfgHorizontalLayout + property bool cfgSolidBackground: Plasmoid.configuration.cfgSolidBackground + property int cfgCornerRadius: Plasmoid.configuration.cfgCornerRadius + property int cfgFontSize: Plasmoid.configuration.cfgFontSize + property int cfgShadowSpread: Plasmoid.configuration.cfgShadowSpread + property string cfgAlignment: Plasmoid.configuration.cfgAlignment + property string cfgCacheForDays: Plasmoid.configuration.cfgCacheForDays + property string cfgCacheRoot: Plasmoid.configuration.cfgCacheRoot // without trailing slash + property string cfgMpdHost: Plasmoid.configuration.cfgMpdHost + property string cfgShadowColor: Plasmoid.configuration.cfgShadowColor + + property string appLastError: "" + + Plasmoid.backgroundHints: cfgSolidBackground ? PlasmaCore.Types.StandardBackground : PlasmaCore.Types.NoBackground + + // Make sure a somewhat reasonable layout with text and cover image is visible + // when the user puts the widget on the desktop for the first time. + Layout.minimumHeight: cfgHorizontalLayout ? 40 : 180 + Layout.minimumWidth: cfgHorizontalLayout ? 150 : 50 + + Component.onCompleted: { + // toggleAppWindow() + } + + function toggleAppWindow() { + if (!appWindowLoader.item) { + appWindowLoader.setSource( + "Components/Application/ApplicationWindow.qml", + { initialHeight: 0.95 * Plasmoid.availableScreenRect.height }) + } else { + appWindowLoader.item.visible = appWindowLoader.item.visible ? false : true + } + appWindowUnloader.restart() + } + + Connections { + function onCfgMpdHostChanged() { + mpdState.connect() + } + } + + CoverManager { + id: coverManager + } + + MpdState { + id: mpdState + scriptRoot: plasmoid.file('', 'scripts/') + } + + VolumeState { + id: volumeState + } + + // Widget shown on desktop + WidgetLayout { + // @TODO currently used to access volmeslider + id: widgetLayout + anchors.fill: parent + } + + Loader { + id: appWindowLoader + } + + Timer { + id: appWindowUnloader + interval: 120000 + onTriggered: { + if (appWindowLoader.item.visible) { + start() + return + } + appWindowLoader.source = "" + mpdState.library = undefined + } + } +} diff --git a/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/metadata.json b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/metadata.json new file mode 100644 index 00000000..923ef60e --- /dev/null +++ b/kde/plasma/plasmoids/com.siezi.plasma.mpdWidget/metadata.json @@ -0,0 +1,23 @@ +{ + "KPlugin": { + "Authors": [ + { + "Email": "openmail@siezi.com", + "Name": "Schlaefer" + } + ], + "Category": "Multimedia", + "Description": "Show information and control MPD", + "Icon": "org.kde.plasma.mediacontroller", + "Id": "com.siezi.plasma.mpdWidget", + "Name": "MPD Plasma Widget", + "Version": "5.6.0", + "Website": "https://github.com/Schlaefer/mpd-plasma-widget", + "License": "GPLv3" + }, + "X-Plasma-API": "declarativeappletscript", + "X-Plasma-MainScript": "ui/main.qml", + "KPackageStructure": "Plasma/Applet" +} + + diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/config/config.qml b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/config/config.qml new file mode 100644 index 00000000..544dee52 --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/config/config.qml @@ -0,0 +1,38 @@ +/* + * Copyright 2023 Barry Strong + * + * This file is part of Process Monitor Plasmoid + * + * Process Monitor Plasmoid is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Monitor Plasmoid is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with System Monitor Plasmoid. If not, see . +*/ +import QtQuick 2.0 +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n("Layout") + icon: "configure" + source: "configLayout.qml" + } + ConfigCategory { + name: i18n("Font") + icon: "preferences-desktop-font" + source: "selectFont.qml" + } + ConfigCategory { + name: i18n("Help") + icon: "help-browser" + source: "help.qml" + } +} diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/config/main.xml b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/config/main.xml new file mode 100644 index 00000000..29ec12f0 --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/config/main.xml @@ -0,0 +1,72 @@ + + + + + + 10 + + + true + + + false + + + false + + + false + + + false + + + true + + + false + + + false + + + false + + + false + + + true + + + true + + + true + + + 30 + + + true + + + false + + + false + + + false + + + true + + + "Hack" + + + 10 + + + diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/FullRepresentation.qml b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/FullRepresentation.qml new file mode 100644 index 00000000..94b71687 --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/FullRepresentation.qml @@ -0,0 +1,444 @@ +/* + * Copyright 2023 Barry Strong + * + * This file is part of Process Monitor Plasmoid + * + * Process Monitor Plasmoid is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Monitor Plasmoid is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with System Monitor Plasmoid. If not, see . +*/ + +import QtQuick 2.5 +import QtQuick.Layouts 1.0 +import org.kde.plasma.components 2.0 as PlasmaComponents +import Processes 1.0 + +Rectangle { + id: viewPort + color: "transparent" + radius: 3; + property var numClkTicks + property var rowWidth + property var rowHeight + property var hdrHeight + property var disHeight + property font listFont + property font hdrFont + property var colSpacing: 5 + property var rowSpacing: 0 + property var numColumns + property font sysFont: pinfo.getSystemFont() + border { + property color borderColor: theme.textColor + color: Qt.hsla(borderColor.hslHue, + borderColor.hslSaturation, + borderColor.hslLightness, .5) + width: plasmoid.configuration.showBorders ? 1 : 0 + } + TextMetrics { + id: listSize + font: listFont + text: "" + } + TextMetrics { + id: hdrSize + font: hdrFont + text: "" + } + Component { + id: listHeader; + Row { + spacing: colSpacing + property font hdrFont: listFont + + Component { + id: hdrText + PlasmaComponents.Label { + font: hdrFont + height: text.paintedHeight + text: hdrValue + } + } + Loader { + property var hdrValue: "Name " + sourceComponent: plasmoid.configuration.showName ? hdrText : undefined + } + Loader { + property var hdrValue: " PID" + sourceComponent: plasmoid.configuration.showPID ? hdrText : undefined + } + Loader { + property var hdrValue: " CPU" + sourceComponent: plasmoid.configuration.showCPU || + plasmoid.configuration.sortbyCPU ? hdrText : undefined + } + Loader { + property var hdrValue: " Memory" + sourceComponent: plasmoid.configuration.showMem || + plasmoid.configuration.sortbyMem ? hdrText : undefined + } + Loader { + property var hdrValue: " Read" + sourceComponent: plasmoid.configuration.showIOReads || + plasmoid.configuration.sortbyIOReads ? hdrText : undefined + } + Loader { + property var hdrValue: " Write" + sourceComponent: plasmoid.configuration.showIOWrites || + plasmoid.configuration.sortbyIOWrites ? hdrText : undefined + } + } + } + Component { + id: listItem + Row { + spacing: colSpacing + property font itemFont: listFont + Component { + id: colItem + PlasmaComponents.Label { + font: itemFont + height: text.paintedHeight + text: itmValue + } + } + Loader { + property var itmValue: name + sourceComponent: plasmoid.configuration.showName ? colItem : undefined + } + Loader { + property var itmValue: pid + sourceComponent: plasmoid.configuration.showPID ? colItem : undefined + } + Loader { + property var itmValue: cpu + sourceComponent: plasmoid.configuration.showCPU || + plasmoid.configuration.sortbyCPU? colItem : undefined + } + Loader { + property var itmValue: mem + sourceComponent: plasmoid.configuration.showMem || + plasmoid.configuration.sortbyMem? colItem : undefined + } + Loader { + property var itmValue: ior + sourceComponent: plasmoid.configuration.showIOReads || + plasmoid.configuration.sortbyIOReads? colItem : undefined + } + Loader { + property var itmValue: iow + sourceComponent: plasmoid.configuration.showIOWrites || + plasmoid.configuration.sortbyIOWrites? colItem : undefined + } + } + } + ListView { + id: procView + anchors.fill: parent + width: parent.width + height: parent.height + anchors.leftMargin: viewPort.border.width * 4 + anchors.topMargin: viewPort.border.width + interactive: false + clip: true + spacing: rowSpacing + model: procModel + } + ListModel { + id: procModel + } + PInfo { + id: pinfo + } + Timer { + id: updTimer + interval: plasmoid.configuration.updateInterval * 100 + running: true + repeat: true + + onTriggered: { + pinfo.updateProcesses(); + } + } + function checkWidth() { + var spacingWrk + + if (numColumns > 0) { + spacingWrk = (width - rowWidth) / numColumns; + colSpacing = spacingWrk + 5; + } else { + colSpacing = 5; + } + procView.anchors.leftMargin = viewPort.border.width * 4; + } + function checkHeight() { + var spacingWrk + + if (plasmoid.configuration.numProcesses > 1) { + spacingWrk = (height - disHeight) / (plasmoid.configuration.numProcesses - 1); + rowSpacing = spacingWrk; + if (spacingWrk < 0) + rowSpacing = 0; + } else { + rowSpacing = 0; + } + procView.anchors.topMargin = viewPort.border.width; + } + onWidthChanged: { + checkWidth(); + } + onHeightChanged: { + checkHeight(); + } + function setWidth() { + numColumns = 0; + listSize.text = ""; + if (plasmoid.configuration.showName) { + listSize.text += "Name "; + numColumns += 1 + } + if (plasmoid.configuration.showPID) { + listSize.text += " PID"; + numColumns += 1 + } + if (plasmoid.configuration.showCPU || plasmoid.configuration.sortbyCPU) { + listSize.text += " CPU"; + numColumns += 1 + } + if (plasmoid.configuration.showMem || plasmoid.configuration.sortbyMem) { + listSize.text += " Memory"; + numColumns += 1 + } + if (plasmoid.configuration.showIOReads || plasmoid.configuration.sortbyIOReads) { + listSize.text += " Read"; + numColumns += 1 + } + if (plasmoid.configuration.showIOWrites || plasmoid.configuration.sortbyIOWrites) { + listSize.text += " Write"; + numColumns += 1 + } + numColumns -= 1; + rowHeight = Math.ceil(listSize.height); + if (plasmoid.configuration.boldHeaders) { + hdrFont = listFont; + hdrFont.bold = true; + hdrSize.font = hdrFont; + hdrSize.text = listSize.text; + hdrHeight = Math.ceil(hdrSize.height); + rowWidth = Math.ceil(hdrSize.advanceWidth); + } else { + hdrHeight = rowHeight; + rowWidth = Math.ceil(listSize.advanceWidth); + } + rowWidth += (numColumns * 5) + (viewPort.border.width * 8); + if (rowWidth <= width) + checkWidth(); + viewPort.Layout.minimumWidth = rowWidth; + viewPort.Layout.preferredWidth = rowWidth; + } + function setHeight() { + disHeight = rowHeight * plasmoid.configuration.numProcesses; + disHeight += (viewPort.border.width * 2); + if (plasmoid.configuration.showHeaders) { + disHeight += hdrHeight; + } + if (disHeight <= height) + checkHeight(); + viewPort.Layout.minimumHeight = disHeight; + viewPort.Layout.preferredHeight = disHeight; + } + function setHdr() { + if (procView.header != null) + procView.header = null; + setWidth(); + if (plasmoid.configuration.showHeaders) { + procView.header = listHeader; + procView.headerItem.hdrFont.bold = plasmoid.configuration.boldHeaders; + } + } + function setList() { + if (procView.delegate != null) + procView.delegate = null; + procView.delegate = listItem; + setHdr(); + } + function getSortField() { + if (plasmoid.configuration.sortbyCPU) return 1; + if (plasmoid.configuration.sortbyMem) return 2; + if (plasmoid.configuration.sortbyIOReads) return 3; + if (plasmoid.configuration.sortbyIOWrites) return 4; + } + function getWitchProcs() { + if (plasmoid.configuration.ownProcs) return 0; + if (plasmoid.configuration.userProcs) return 1; + if (plasmoid.configuration.systemProcs) return 2; + if (plasmoid.configuration.allProcs) return 3; + } + function setFastMem() { + pinfo.setFastMem(!(plasmoid.configuration.sortbyMem || plasmoid.configuration.showMem)); + } + Connections { + target: plasmoid.configuration + function onNumProcessesChanged() { + procModel.clear(); + pinfo.setNumProcesses(plasmoid.configuration.numProcesses); + setHeight(); + } + function onShowNameChanged() { + setList(); + } + function onShowPIDChanged() { + setList(); + } + function onShowCPUChanged() { + if (!plasmoid.configuration.sortbyCPU) + setList(); + } + function onShowMemChanged() { + if (!plasmoid.configuration.sortbyMem) { + setFastMem(); + setList(); + } + } + function onShowIOReadsChanged() { + if (!plasmoid.configuration.sortbyIOReads) + setList(); + } + function onShowIOWritesChanged() { + if (!plasmoid.configuration.sortbyIOWrites) + setList(); + } + function onSortbyCPUChanged() { + if (plasmoid.configuration.sortbyCPU) + pinfo.setSortField(getSortField()); + if (!plasmoid.configuration.showCPU) + setList(); + } + function onSortbyMemChanged() { + if (plasmoid.configuration.sortbyMem) + pinfo.setSortField(getSortField()); + if (!plasmoid.configuration.showMem) { + setFastMem(); + setList(); + } + } + function onSortbyIOReadsChanged() { + if (plasmoid.configuration.sortbyIOReads) + pinfo.setSortField(getSortField()); + if (!plasmoid.configuration.showIOReads) + setList(); + } + function onSortbyIOWritesChanged() { + if (plasmoid.configuration.sortbyIOWrites) + pinfo.setSortField(getSortField()); + if (!plasmoid.configuration.showIOWrites) + setList(); + } + function onShowBordersChanged() { + setHdr(); + setHeight(); + } + function onShowHeadersChanged() { + setHdr(); + setHeight(); + } + function onBoldHeadersChanged() { + if (plasmoid.configuration.showHeaders) + procView.headerItem.hdrFont.bold = plasmoid.configuration.boldHeaders; + setHdr(); + setHeight(); + } + function onOwnProcsChanged() { + if (plasmoid.configuration.ownProcs) pinfo.setProcUids(getWitchProcs()); + } + function onUserProcsChanged() { + if (plasmoid.configuration.userProcs) pinfo.setProcUids(getWitchProcs()); + } + function onSystemProcsChanged() { + if (plasmoid.configuration.systemProcs) pinfo.setProcUids(getWitchProcs()); + } + function onAllProcsChanged() { + if (plasmoid.configuration.allProcs) pinfo.setProcUids(getWitchProcs()); + } + function onFontFamilyChanged() { + if (!plasmoid.configuration.systemFont) { + listFont.family = plasmoid.configuration.fontFamily; + listFont.bold = false; + setList(); + setHeight(); + } + } + function onFontSizeChanged() { + if (!plasmoid.configuration.systemFont) { + listFont.pointSize = plasmoid.configuration.fontSize; + listFont.bold = false; + setList(); + setHeight(); + } + } + function onSystemFontChanged() { + if (plasmoid.configuration.systemFont) { + listFont.family = sysFont.family; + listFont.pointSize = sysFont.pointSize; + listFont.bold = false; + } else { + listFont.family = plasmoid.configuration.fontFamily; + listFont.pointSize = plasmoid.configuration.fontSize; + listFont.bold = false; + } + setList(); + setHeight(); + } + } + Connections { + target: pinfo + function onResult(totalCPU, procIDs, procNames, procCPU, procMem, procDRead, procDWrite) { + var numSecs; + + function fmtData (value, len, suffix) { + value = value.toFixed(1).substring(0, len); + if (value != "0.0") { + value = value.padStart(len) + suffix; + } else { + value = "".padStart(len + suffix.length); + } + return value; + } + numSecs = totalCPU / numClkTicks + for (var idx = 0; idx < plasmoid.configuration.numProcesses; idx++) { + procModel.set(idx, { + name: procNames[idx].substring(0, 15).padEnd(15), + pid: procIDs[idx].substring(0, 8).padStart(8), + cpu: fmtData((procCPU[idx] / totalCPU) * 100, 5, "%"), + mem: fmtData(procMem[idx] / 1024, 7, "M"), + ior: fmtData(procDRead[idx] / 1048576 / numSecs, 7, "Ms"), + iow: fmtData(procDWrite[idx] / 1048576 / numSecs, 7, "Ms") + }); + } + } + } + Component.onCompleted: { + numClkTicks = pinfo.getClkTicks() * pinfo.getNumProcs(); + if (plasmoid.configuration.systemFont) { + listFont.family = sysFont.family; + listFont.pointSize = sysFont.pointSize; + } else { + listFont.family = plasmoid.configuration.fontFamily; + listFont.pointSize = plasmoid.configuration.fontSize; + } + listFont.bold = false; + setList(); + setHeight(); + pinfo.configProcesses(getWitchProcs(), plasmoid.configuration.numProcesses, getSortField(), + !(plasmoid.configuration.sortbyMem || plasmoid.configuration.showMem)); + } +} diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/configLayout.qml b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/configLayout.qml new file mode 100644 index 00000000..ed824968 --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/configLayout.qml @@ -0,0 +1,206 @@ +/* + * Copyright 2023 Barry Strong + * + * This file is part of Process Monitor Plasmoid + * + * Process Monitor Plasmoid is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Monitor Plasmoid is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with System Monitor Plasmoid. If not, see . +*/ +import QtQuick 2.0 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.0 + +Item { + property alias cfg_numProcesses: numProcesses.value + property alias cfg_sortbyCPU: sortbyCPU.checked + property alias cfg_sortbyMem: sortbyMem.checked + property alias cfg_sortbyIOReads: sortbyIOReads.checked + property alias cfg_sortbyIOWrites: sortbyIOWrites.checked + property alias cfg_showPID: showPID.checked + property alias cfg_showName: showName.checked + property alias cfg_showCPU: showCPU.checked + property alias cfg_showMem: showMem.checked + property alias cfg_showIOReads: showIOReads.checked + property alias cfg_showIOWrites: showIOWrites.checked + property alias cfg_showBorders: showBorders.checked + property alias cfg_showHeaders: showHeaders.checked + property alias cfg_boldHeaders: boldHeaders.checked + property alias cfg_updateInterval: updateInterval.value + property alias cfg_ownProcs: ownProcs.checked + property alias cfg_userProcs: userProcs.checked + property alias cfg_systemProcs: systemProcs.checked + property alias cfg_allProcs: allProcs.checked + + ColumnLayout { + RowLayout { + Layout.alignment: Qt.AlignCenter + Label { + text: i18n("Number of Processes to Display") + } + SpinBox { + id: numProcesses + from: 1 + to: 50 + } + } + Label { + text: " " + } + Label { + Layout.alignment: Qt.AlignCenter + font.bold: true + text: i18n("Select Processes") + } + GridLayout { + columns: 2 + Layout.alignment: Qt.AlignCenter + RadioButton { + id: ownProcs + text: i18n("Own Processes") + } + RadioButton { + id: userProcs + text: i18n("User Processes") + } + RadioButton { + id: systemProcs + text: i18n("System Processes") + } + RadioButton { + id: allProcs + text: i18n("All Processes") + } + } + Label { + text: " " + } + Label { + Layout.alignment: Qt.AlignCenter + font.bold: true + text: i18n("Sort Processes by") + } + RowLayout { + Layout.alignment: Qt.AlignCenter + RadioButton { + id: sortbyCPU + text: i18n("CPU") + } + RadioButton { + id: sortbyMem + text: i18n("Memory") + } + RadioButton { + id: sortbyIOReads + text: i18n("Reads") + } + RadioButton { + id: sortbyIOWrites + text: i18n("Writes") + } + } + Label { + text: " " + } + Label { + Layout.alignment: Qt.AlignCenter + font.bold: true + text: i18n("Information to be listed for each Process") + } + RowLayout { + Layout.alignment: Qt.AlignCenter + CheckBox { + id: showName + text: i18n("Name") + } + CheckBox { + id: showPID + text: i18n("PID") + } + CheckBox { + id: showCPU + text: i18n("CPU") + enabled: !sortbyCPU.checked + } + CheckBox { + id: showMem + text: i18n("Memory") + enabled: !sortbyMem.checked + } + CheckBox { + id: showIOReads + text: i18n("Reads") + enabled: !sortbyIOReads.checked + } + CheckBox { + id: showIOWrites + text: i18n("Writes") + enabled: !sortbyIOWrites.checked + } + } + Label { + text: " " + } + Label { + Layout.alignment: Qt.AlignCenter + font.bold: true + text: i18n("Other Options") + } + RowLayout { + Layout.alignment: Qt.AlignCenter + CheckBox { + id: showBorders + text: i18n("Show Border") + } + CheckBox { + id: showHeaders + text: i18n("Show Column Headers") + } + } + CheckBox { + id: boldHeaders + Layout.alignment: Qt.AlignCenter + text: i18n("Bold Column Headers") + enabled: showHeaders.checked + } + RowLayout { + Layout.alignment: Qt.AlignCenter + Label { + text: i18n("Update Every") + } + SpinBox { + id: updateInterval + from: 1 + to: 100 + value: 10 + ToolTip.text: qsTr("Interval between display updates in seconds") + ToolTip.visible: hovered + ToolTip.delay: 1000 + ToolTip.timeout: 5000 + inputMethodHints: Qt.ImhFormattedNumbersOnly + textFromValue: function(value, locale) { + return Number(value / 10).toLocaleString(locale, 'f', 1) + } + valueFromText: function(text, locale) { + return Number.fromLocaleString(locale, text) * 10 + } + validator: DoubleValidator { + bottom: Math.min(updateInterval.from, updateInterval.to) + top: Math.max(updateInterval.from, updateInterval.to) + } + } + Text { + text: "s" + } + } + } +} diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/help.qml b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/help.qml new file mode 100644 index 00000000..6f4b514a --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/help.qml @@ -0,0 +1,57 @@ +/* + * Copyright 2023 Barry Strong + * + * This file is part of Process Monitor Plasmoid + * + * Process Monitor Plasmoid is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Monitor Plasmoid is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with System Monitor Plasmoid. If not, see . +*/ +import QtQuick 2.0 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.0 + +Item { + ColumnLayout { + Label { + id: helpText + } + } + Component.onCompleted: { + helpText.text = + " Number of Processes to Display:\n" + + " Sets the number of rows in the display.\n" + + " Select Processes:\n" + + " Sets witch processes to list, Own (current user processes),\n" + + " User (all users processes), system (only system processes),\n" + + " All (all processes).\n" + + " Sort Processes by:\n" + + " Sets the information to sort on. Higher values will be shown\n" + + " at the top of the list. This Information will also be\n" + + " displayed as a column in the list.\n" + + " Information to be listed for each Process:\n" + + " Sets additional information displayed as columns in the list.\n" + + " Show Borders:\n" + + " Creates a thin border around the list.\n" + + " Show Column Headers:\n" + + " Add a header above each column.\n" + + " Bold Column Headers:\n" + + " Display column headers with bold font.\n" + + " Update Everly:\n" + + " How often to update the list in seconds.\n" + + " Font Tab:\n"+ + " Sets the font to be used for the process list.\n" + + " When added to a panel or other small space Process Monitor\n" + + " will only show an icon, Left click the icon to show the\n" + + " full display in a popup." + } +} diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/imports/Processes/libprocessesplugin.so b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/imports/Processes/libprocessesplugin.so new file mode 100755 index 00000000..b840eb11 Binary files /dev/null and b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/imports/Processes/libprocessesplugin.so differ diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/imports/Processes/plugins.qmltypes b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/imports/Processes/plugins.qmltypes new file mode 100644 index 00000000..5bc4ca10 --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/imports/Processes/plugins.qmltypes @@ -0,0 +1,60 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + dependencies: ["QtQuick 2.0"] + Component { + file: "processes.h" + name: "Processes" + prototype: "QObject" + exports: ["Processes/PInfo 1.0"] + exportMetaObjectRevisions: [0] + Signal { + name: "result" + Parameter { name: "totalCPU"; type: "QVariant" } + Parameter { name: "pID"; type: "QStringList" } + Parameter { name: "pName"; type: "QStringList" } + Parameter { name: "pCPU"; type: "QVariantList" } + Parameter { name: "pMem"; type: "QVariantList" } + Parameter { name: "dRead"; type: "QVariantList" } + Parameter { name: "dWrites"; type: "QVariantList" } + } + Method { + name: "configProcesses" + Parameter { name: "uids"; type: "int" } + Parameter { name: "numProcs"; type: "int" } + Parameter { name: "sortField"; type: "int" } + Parameter { name: "fast"; type: "bool" } + } + Method { + name: "setNumProcesses" + Parameter { name: "numProcs"; type: "int" } + } + Method { + name: "setSortField" + Parameter { name: "sortField"; type: "int" } + } + Method { + name: "setFastMem" + Parameter { name: "fast"; type: "bool" } + } + Method { + name: "setProcUids" + Parameter { name: "uids"; type: "int" } + } + Method { name: "getClkTicks"; type: "long" } + Method { name: "getNumProcs"; type: "long" } + Method { name: "getSystemFont"; type: "QFont" } + Method { name: "getFixedFonts"; type: "QStringList" } + Method { + name: "getFontSizes" + type: "QStringList" + Parameter { name: "family"; type: "string" } + } + Method { name: "updateProcesses" } + } +} diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/main.qml b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/main.qml new file mode 100644 index 00000000..72b771c6 --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/main.qml @@ -0,0 +1,48 @@ +/* + * Copyright 2023 Barry Strong + * + * This file is part of Process Monitor Plasmoid + * + * Process Monitor Plasmoid is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Monitor Plasmoid is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with System Monitor Plasmoid. If not, see . +*/ + +import QtQuick 2.0 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore + +Item { + id: procMonitor + Plasmoid.fullRepresentation: FullRepresentation {} + function setForm() { + switch (Plasmoid.formFactor) { + case PlasmaCore.Types.Vertical: + Plasmoid.switchWidth = units.gridUnit * 5; + Plasmoid.switchHeight = 1; + break; + case PlasmaCore.Types.Horizontal: + Plasmoid.switchWidth = 1; + Plasmoid.switchHeight = units.gridUnit * 5; + break; + default: + Plasmoid.switchWidth = units.gridUnit * 5; + Plasmoid.switchHeight = units.gridUnit * 5; + } + } + Component.onCompleted: { + setForm(); + } + Plasmoid.onFormFactorChanged: { + setForm(); + } +} diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/qmldir b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/qmldir new file mode 100644 index 00000000..3658eccf --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/qmldir @@ -0,0 +1 @@ +plugin processesplugin ./imports/Processes diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/selectFont.qml b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/selectFont.qml new file mode 100644 index 00000000..cc18f502 --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/contents/ui/selectFont.qml @@ -0,0 +1,132 @@ +/* + * Copyright 2023 Barry Strong + * + * This file is part of Process Monitor Plasmoid + * + * Process Monitor Plasmoid is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Monitor Plasmoid is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with System Monitor Plasmoid. If not, see . +*/ +import QtQuick 2.0 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.0 +import Processes 1.0 + +Item { + property alias cfg_systemFont: systemFont.checked + property alias cfg_fontFamily: fontList.currentText + property alias cfg_fontSize: sizeList.currentText + property font sysFont: pinfo.getSystemFont() + PInfo { + id: pinfo + } + QtObject { + id: data + property var fontFamily + property var fontSize + } + ColumnLayout { + RowLayout { + Layout.alignment: Qt.AlignLeft + CheckBox { + id: systemFont + text: i18n("Use System Font: " + sysFont.family + i18n(" Size: ") + + sysFont.pointSize) + } + } + ListModel { + id: fontModel + } + ListModel { + id: sizeModel + } + RowLayout { + Layout.alignment: Qt.AlignLeft + Label { + text: i18n("Font:") + } + ComboBox { + id: fontList + model: fontModel + enabled: !systemFont.checked + onActivated: { + var sizes + var prevIdx + + sizes = pinfo.getFontSizes(currentText) + prevIdx = sizeList.currentIndex; + for (var idx = 0; idx < sizes.length; idx ++) + if (idx < sizes.length) { + sizeModel.set(idx, {size: sizes[idx]}) + } else { + sizeModel.append({size: sizes[idx]}); + } + if (prevIdx < sizes.length) { + sizeList.currentIndex = prevIdx; + } else { + for (var idx = 0; idx < sizeModel.count; idx++) { + if (sizeModel.get(idx).size == sysFont.pointSize) { + sizeList.currentIndex = idx; + break; + } + } + } + } + } + Label { + text: i18n("Size:") + } + ComboBox { + id: sizeList + model: sizeModel + enabled: !systemFont.checked + } + Component.onCompleted: { + var fonts + var sizes + var curFont; + + fontModel.clear(); + fonts = pinfo.getFixedFonts(); + for (var idx = 0; idx < fonts.length; idx++) + fontModel.append({fontFamily: fonts[idx]}); + fontList.currentIndex = 0; + for (var idx = 0; idx < fontModel.count; idx++) { + if (fontModel.get(idx).fontFamily == plasmoid.configuration.fontFamily) { + fontList.currentIndex = idx; + break; + } + } + sizes = pinfo.getFontSizes(fontList.currentText) + sizeModel.clear(); + for (var idx = 0; idx < sizes.length; idx ++) + sizeModel.append({fontSize: sizes[idx]}); + sizeList.currentIndex = 0; + for (var idx = 0; idx < sizeModel.count; idx++) { + if (sizeModel.get(idx).fontSize == plasmoid.configuration.fontSize) { + sizeList.currentIndex = idx; + break; + } + } + } + } + Label { + id: sampleText + property var fontFamily: systemFont.checked ? sysFont.family : fontList.currentText + property var fontSize: systemFont.checked ? sysFont.pointSize : sizeList.currentText + font.family: fontFamily + font.pointSize: fontSize + font.bold: false + text: "Sample text for chosen font 10.0%" + } + } +} diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/metadata.desktop b/kde/plasma/plasmoids/com.softtechok.processmonitor/metadata.desktop new file mode 100755 index 00000000..4258aaf8 --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/metadata.desktop @@ -0,0 +1,20 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Process Monitor +Comment=List Process resource usage (CPU, Mem, etc) +Icon=view-process-all + +Type=Service +ServiceTypes=Plasma/Applet + +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml + +X-KDE-PluginInfo-Author=Barry Strong +X-KDE-PluginInfo-Email=bstrong@softtechok.com +X-KDE-PluginInfo-Name=com.softtechok.processmonitor +X-KDE-PluginInfo-License=GPL-3.0+ +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=https://www.opencode.net/bstrong5280 +X-KDE-PluginInfo-Category=System Information +X-KDE-ServiceTypes=Plasma/Applet diff --git a/kde/plasma/plasmoids/com.softtechok.processmonitor/metadata.json b/kde/plasma/plasmoids/com.softtechok.processmonitor/metadata.json new file mode 100755 index 00000000..0b99b23a --- /dev/null +++ b/kde/plasma/plasmoids/com.softtechok.processmonitor/metadata.json @@ -0,0 +1,23 @@ +{ + "KPlugin": { + "Authors": [ + { + "Email": "bstrong@softtechok.com", + "Name": "Barry Strong" + } + ], + "Category": "System Information", + "Description": "List Process resource usage (CPU, Mem, etc)", + "Icon": "view-process-all", + "Id": "com.softtechok.processmonitor", + "License": "GPL-3.0+", + "Name": "Process Monitor", + "ServiceTypes": [ + "Plasma/Applet" + ], + "Version": "1.0", + "Website": "https://www.opencode.net/bstrong5280" + }, + "X-Plasma-API": "declarativeappletscript", + "X-Plasma-MainScript": "ui/main.qml" +} diff --git a/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/config/config.qml b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/config/config.qml new file mode 100644 index 00000000..7253f1c1 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/config/config.qml @@ -0,0 +1,10 @@ +import QtQuick 2.12 +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n("General") + icon: "preferences-desktop" + source: "GeneralConfig.qml" + } +} \ No newline at end of file diff --git a/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/config/main.xml b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/config/main.xml new file mode 100644 index 00000000..8f027ae4 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/config/main.xml @@ -0,0 +1,23 @@ + + + + + + + 100 + + + + @multiplex + + + + "Noto Sans" + + + + + diff --git a/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/fonts/Aller_Bd.ttf b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/fonts/Aller_Bd.ttf new file mode 100644 index 00000000..b0513c46 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/fonts/Aller_Bd.ttf differ diff --git a/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/fonts/Aller_Lt.ttf b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/fonts/Aller_Lt.ttf new file mode 100644 index 00000000..ce8f3da9 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/fonts/Aller_Lt.ttf differ diff --git a/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/ui/GeneralConfig.qml b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/ui/GeneralConfig.qml new file mode 100644 index 00000000..98d3a6f7 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/ui/GeneralConfig.qml @@ -0,0 +1,95 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.11 +import org.kde.plasma.core 2.0 as PlasmaCore + +Item { + id: configRoot + + signal configurationChanged + + property alias cfg_opacity: opacitySpinBox.value + + property string cfg_preferredSource + + property string cfg_fontFamily + + ColumnLayout { + spacing: units.smallSpacing * 2 + + + RowLayout{ + Label { + text: i18n("Opacity percent") + } + SpinBox { + id: opacitySpinBox + from: 0 + to: 100 + } + } + + RowLayout{ + + Label { + text: i18n("Preferred media source") + } + + ListModel { + id: sourcesModel + Component.onCompleted: { + var arr = [] + arr.push({ + "text": cfg_preferredSource + }) + var sources = dataSource.sources + for (var i = 0, j = sources.length; i < j; ++i) { + if (sources[i] === cfg_preferredSource) { + continue + } + arr.push({ + "text": sources[i] + }) + } + append(arr) + } + } + + ComboBox { + id: sourcesComboBox + model: sourcesModel + focus: true + currentIndex: 0 + textRole: "text" + onCurrentIndexChanged: { + var current = model.get(currentIndex) + if (current) { + cfg_preferredSource = current.text + configRoot.configurationChanged() + } + } + } + } + + RowLayout{ + Label { + text: i18n("Font") + } + ComboBox{ + id: fontFamilyComboBox + model: Qt.fontFamilies() + onCurrentIndexChanged: { + var current = Qt.fontFamilies()[currentIndex] + cfg_fontFamily=current + configRoot.configurationChanged() + } + } + } + + } + + PlasmaCore.DataSource { + id: dataSource + engine: "mpris2" + } +} diff --git a/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/ui/Representation.qml b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/ui/Representation.qml new file mode 100644 index 00000000..18e11aed --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/ui/Representation.qml @@ -0,0 +1,189 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.11 +import QtQuick.Controls 2.12 +import org.kde.plasma.components 3.0 as PlasmaComponents +import org.kde.plasma.core 2.0 as PlasmaCore +import QtGraphicalEffects 1.0 + +RowLayout { + id: fullView + focus: true + + // loading fonts + + FontLoader { + id: antonio_Bold + source: "../fonts/Antonio-Bold.ttf" + } + FontLoader { + id: aller_Lt + source: "../fonts/Aller_Lt.ttf" + } + FontLoader { + id: aller_Bd + source: "../fonts/Aller_Bd.ttf" + } + + Keys.onReleased: { + if (!event.modifiers) { + event.accepted = true + if (event.key === Qt.Key_Space || event.key === Qt.Key_K) { + root.mediaToggle() + } else if (event.key === Qt.Key_P) { + root.mediaPrev() + } else if (event.key === Qt.Key_N) { + root.mediaNext() + } else { + event.accepted = false + } + } + } + RowLayout { + Layout.fillWidth: true + Layout.maximumWidth: fullView.width + Layout.fillHeight: true + Layout.maximumHeight: 190 + ColumnLayout { + id: leftWidget + Layout.fillWidth: false + width: 100 + Layout.fillHeight: true + Item { + width: 91 + height: 91 + Rectangle { + anchors.centerIn: parent + id: mask + width: parent.width + height: parent.height + visible: false + color: "transparent" + Rectangle { + anchors.centerIn: parent + width: parent.width*.90 + height: parent.height*.90 + color: "black" + radius: width/2 + } + } + Rectangle { + visible: mediaSource.track + id: backgroundCover + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + width: parent.width + height: parent.height + radius: width/2 + color: "white" + } + Image { + visible: mediaSource.track + id: coverImage + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + width: parent.width + height: parent.height + source: mediaSource.albumArt ? mediaSource.albumArt : "../images/.face.icon" + fillMode: Image.PreserveAspectCrop + layer.enabled: true + layer.effect: OpacityMask { + maskSource: mask + } + } + + MouseArea { + // Layout.alignment: Qt.AlignRight + id: mediaControlsMouseArea + height: title.height + Layout.fillWidth: true + anchors.bottom: parent.bottom + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + hoverEnabled: true + RowLayout { + id: mediaControls + opacity: mediaControlsMouseArea.containsMouse + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + Behavior on opacity { + PropertyAnimation { + easing.type: Easing.InOutQuad + duration: 250 + } + } + Button { + Layout.preferredWidth: fullwidget.height/2 + Layout.preferredHeight: fullwidget.height/1.5 + contentItem: PlasmaCore.IconItem { + source: "media-skip-backward" + } + padding: 0 + background: null + onClicked: { + root.mediaPrev() + console.log("prev clicked") + } + } + Button { + Layout.preferredWidth: fullwidget.height/2 + Layout.preferredHeight: fullwidget.height/1.5 + id: playButton + contentItem: PlasmaCore.IconItem { + source: mediaSource.playbackStatus + === "Playing" ? "media-playback-start" : "media-playback-pause" + } + padding: 0 + background: null + onClicked: { + root.mediaToggle() + console.log("pause clicked") + } + } + Button { + Layout.preferredWidth: fullwidget.height/2 + Layout.preferredHeight: fullwidget.height/1.5 + contentItem: PlasmaCore.IconItem { + source: "media-skip-forward" + } + onClicked: { + root.mediaNext() + console.log(mediaSource.playbackStatus) + console.log("next clicked") + } + padding: 0 + background: null + } + } + } + } + } + ColumnLayout { + Layout.fillWidth: true + id: fullwidget + PlasmaComponents.Label { + id: title + text: mediaSource.track + Layout.fillWidth: true + font.pixelSize: 20 + font.family: aller_Bd.name + // color: "red" + lineHeight: 0.8 + font.bold: true + elide: Text.ElideRight + } + + PlasmaComponents.Label { + font.family: aller_Lt.name + Layout.maximumWidth: 300 + Layout.fillWidth: true + text: mediaSource.artist + font.pixelSize: 16 + // color: "red" + lineHeight: 0.8 + elide: Text.ElideRight + } + + + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/ui/main.qml b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/ui/main.qml new file mode 100644 index 00000000..5f94a6e9 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/contents/ui/main.qml @@ -0,0 +1,123 @@ +import QtQuick 2.12 +import QtQuick.Layouts 1.11 +import QtQuick.Controls 2.12 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore + +Item { + id: root + + Layout.minimumWidth: units.gridUnit*25 + Layout.minimumHeight: units.gridUnit*5 + + Plasmoid.backgroundHints: "NoBackground" + + opacity: plasmoid.configuration.opacity/100 + + Representation { + anchors.fill: parent + } + + PlasmaCore.DataSource { + id: mediaSource + engine: "mpris2" + connectedSources: sources + + property string currentSource: plasmoid.configuration.preferredSource + property var currentData: data[currentSource] + property var currentMetadata: currentData ? currentData.Metadata : {} + + property bool loaded: hasLoaded() + + property string playerIcon: loaded ? currentData["Desktop Icon Name"] : "" + property string playerName: loaded ? currentData.Identity : "" + property string playbackStatus: loaded ? currentData.PlaybackStatus : "" + property string track: currentMetadata ? currentMetadata["xesam:title"] + || "" : "" + property string artist: currentMetadata ? currentMetadata["xesam:artist"] + || "" : "" + property string album: currentMetadata ? currentMetadata["xesam:album"] + || "" : "" + property string albumArt: currentMetadata ? currentMetadata["mpris:artUrl"] + || "" : "" + property double length: currentMetadata ? currentMetadata["mpris:length"] + || 0 : 0 + property double position: loaded ? currentData.Position || 0 : 0 + + function hasLoaded() { + if (typeof currentData === "undefined" + || typeof currentMetadata === "undefined") { + return false + } else { + return true + } + } + + onSourceRemoved: { + if (source === currentSource) { + currentSource = "@multiplex" + } + } + } + + function formatTrackTime(s) { + var hours = Math.floor(s / 3600) + var minutes = Math.floor((s - (hours * 3600)) / 60) + var seconds = Math.ceil(s - (hours * 3600) - (minutes * 60)) + minutes = (minutes < 10) ? "0" + minutes : minutes + seconds = (seconds < 10) ? "0" + seconds : seconds + var time = minutes + ":" + seconds + return time + } + function action_open() { + serviceOp("Raise") + } + function mediaPlay() { + serviceOp("Play") + } + function mediaPause() { + serviceOp("Pause") + } + function mediaToggle() { + serviceOp("PlayPause") + } + function mediaPrev() { + serviceOp("Previous") + } + function mediaNext() { + serviceOp("Next") + } + function mediaStop() { + serviceOp("Stop") + } + function updatePosition() { + serviceOp("GetPosition") + } + function setPosition(s) { + serviceOp("SetPosition", s) + } + function mediaSeek(s) { + serviceOp("Seek", s) + } + function serviceOp(op, n) { + var service = mediaSource.serviceForSource(mediaSource.currentSource) + var operation = service.operationDescription(op) + if (typeof n === "number") { + operation.microseconds = n + } + service.startOperationCall(operation) + } + + Timer { + interval: 500 + running: true + repeat: true + onTriggered: { + updatePosition() + } + } + + Component.onCompleted: { + mediaSource.serviceForSource("@multiplex").enableGlobalShortcuts() + } +} diff --git a/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/metadata.desktop b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/metadata.desktop new file mode 100644 index 00000000..c1e514c1 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.Circle.Minimal.Music/metadata.desktop @@ -0,0 +1,20 @@ +[Desktop Entry] +Encoding=UTF-8 + +Name= Circle Music Minimal +Comment=minimalist widget, with information about the track being played, based on the NowPlaylis widget by nhilistdev +Icon=applications-multimedia +Type=Service + +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml + +X-KDE-PluginInfo-Author=zayronxio and nhilistdev +X-KDE-PluginInfo-Category=Multimedia +X-KDE-PluginInfo-Name=org.kde.Circle.Minimal.Music +X-KDE-PluginInfo-License=GPLv3 +X-KDE-PluginInfo-Version=0.1 +X-Plasma-StandAloneApp=true +X-KDE-PluginInfo-Website=https://github.com/zayronxio/MinimalMusic-plasma +X-Plasma-Provides=org.kde.plasma.multimediacontrols +X-KDE-ServiceTypes=Plasma/Applet diff --git a/kde/plasma/plasmoids/org.kde.activeApplication/README.md b/kde/plasma/plasmoids/org.kde.activeApplication/README.md new file mode 100644 index 00000000..fb3d1469 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.activeApplication/README.md @@ -0,0 +1,39 @@ +# Plasma Active Application + +KDE plasma applet to show the active application name. Thought to be used in a panel together with plasma's global menu. + +## Motivation + +Unfortunately [AWC](https://github.com/kotelnik/plasma-applet-active-window-control) does not seem to be maintained anymore. The experience from the official plasma global menu is currently better, but it is currently missing the active application name. + +## Features + +- Easy replacements through the configuration interface (see issue [#1](https://github.com/kupiqu/plasma-active-application/issues/1) for instructions) +- Maximaze/Restore (double-click) or close (middle-click) +- Full window title tooltip +- Configurable: Bold text, Show window icon, Spacing (Left, Right and in between of Icon and AppName), No window text (activity friendly), No window icon + +## Preview + +![d1](https://i.imgur.com/HSh6aHc.png) + +## Installing + +**Git:** + + git clone https://github.com/kupiqu/plasma-active-application + plasmapkg2 -i . + +[KDE Store](https://store.kde.org/p/1269296/) + +## Updating + + plasmapkg2 -u . + +## Uninstalling + + plasmapkg2 -r org.kde.activeApplication + +## Credit where it is due + +Strongly based on [AWC](https://github.com/kotelnik/plasma-applet-active-window-control) diff --git a/kde/plasma/plasmoids/org.kde.activeApplication/contents/config/config.qml b/kde/plasma/plasmoids/org.kde.activeApplication/contents/config/config.qml new file mode 100644 index 00000000..46c099c5 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.activeApplication/contents/config/config.qml @@ -0,0 +1,10 @@ +import QtQuick 2.2 +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n("Appearance") + icon: "preferences-desktop-color" + source: "config/ConfigAppearance.qml" + } +} diff --git a/kde/plasma/plasmoids/org.kde.activeApplication/contents/config/main.xml b/kde/plasma/plasmoids/org.kde.activeApplication/contents/config/main.xml new file mode 100644 index 00000000..a7df0048 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.activeApplication/contents/config/main.xml @@ -0,0 +1,35 @@ + + + + + + + true + + + false + + + 12 + + + 16 + + + 10 + + + "Mozilla ", ""; "Google ", ""; ": Chromium", " — Chromium"; " Player", "" + + + plasma-kde@%activity% + + + applications-other + + + + diff --git a/kde/plasma/plasmoids/org.kde.activeApplication/contents/ui/config/ConfigAppearance.qml b/kde/plasma/plasmoids/org.kde.activeApplication/contents/ui/config/ConfigAppearance.qml new file mode 100644 index 00000000..51bbc20e --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.activeApplication/contents/ui/config/ConfigAppearance.qml @@ -0,0 +1,126 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.3 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.0 as PlasmaCore + +Item { + id: appearancePage + + property alias cfg_boldFontWeight: boldFontWeight.checked + property alias cfg_showWindowIcon: showWindowIcon.checked + property alias cfg_leftSpacing: leftSpacing.value + property alias cfg_iconAppNameSpacing: iconAppNameSpacing.value + property alias cfg_rightSpacing: rightSpacing.value + property alias cfg_titleReplacements: titleReplacements.text + + property alias cfg_noWindowText: noWindowText.text + property string cfg_noWindowIcon: plasmoid.configuration.noWindowIcon + + GridLayout { + columns: 2 + + Layout.columnSpan: 2 + + Label { + text: i18n('Plasmoid version: ') + '0.2' + Layout.columnSpan: 2 + } + + Item { + width: 2 + height: 15 + Layout.columnSpan: 2 + } + + GridLayout { + columns: 2 + + Layout.columnSpan: 2 + + CheckBox { + id: boldFontWeight + text: i18n("Bold text") + Layout.columnSpan: 2 + } + + CheckBox { + id: showWindowIcon + text: i18n("Show window icon") + Layout.columnSpan: 2 + } + + Label { + text: i18n("Spacing (Left/Icon-AppName/Right):") + } + Row { + spacing: 50 + SpinBox { + id: leftSpacing + decimals: 1 + stepSize: 0.5 + minimumValue: 0 + maximumValue: 50 + } + SpinBox { + id: iconAppNameSpacing + decimals: 1 + stepSize: 0.5 + minimumValue: 0 + maximumValue: 50 + } + SpinBox { + id: rightSpacing + decimals: 1 + stepSize: 0.5 + minimumValue: 0 + maximumValue: 50 + } + } + + Item { + width: 2 + height: 15 + Layout.columnSpan: 2 + } + + Label { + text: i18n('Replacements:\nuse newline or ";" as delimiter') + wrapMode: Text.Wrap + } + + TextArea { + id: titleReplacements + text: '".* Firefox", "Firefox";\n".* Chromium", "Chromium";\n"Google ", "";\n " Player", "";\n"Gimp.*", "Gimp";\n' + onTextChanged: cfg_titleReplacements = text + Layout.preferredWidth: 400 + } + + Item { + width: 2 + height: 15 + Layout.columnSpan: 2 + } + + Label { + text: i18n('No window text:\nuse %activity% for activity name') + wrapMode: Text.Wrap + } + TextField { + id: noWindowText + placeholderText: 'KDE :: Plasma Desktop @ %activity%' + onTextChanged: cfg_noWindowText = text + Layout.preferredWidth: 400 + } + + Label { + text: i18n("No window icon:") + } + IconPicker { + currentIcon: cfg_noWindowIcon + defaultIcon: '' + onIconChanged: cfg_noWindowIcon = iconName + } + } + } + +} diff --git a/kde/plasma/plasmoids/org.kde.activeApplication/contents/ui/config/IconPicker.qml b/kde/plasma/plasmoids/org.kde.activeApplication/contents/ui/config/IconPicker.qml new file mode 100644 index 00000000..90486972 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.activeApplication/contents/ui/config/IconPicker.qml @@ -0,0 +1,94 @@ +/* + * Copyright 2015 Martin Kotelnik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import QtQuick 2.2 +import QtQuick.Controls 1.3 +import QtQuick.Layouts 1.1 +import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +// basically taken from kickoff +Button { + id: iconButton + + property string currentIcon + property string defaultIcon + + signal iconChanged(string iconName) + + Layout.minimumWidth: previewFrame.width + units.smallSpacing * 2 + Layout.maximumWidth: Layout.minimumWidth + Layout.minimumHeight: previewFrame.height + units.smallSpacing * 2 + Layout.maximumHeight: Layout.minimumWidth + + KQuickAddons.IconDialog { + id: iconDialog + onIconNameChanged: { + iconPreview.source = iconName + iconChanged(iconName) + } + } + + // just to provide some visual feedback, cannot have checked without checkable enabled + checkable: true + onClicked: { + checked = Qt.binding(function() { // never actually allow it being checked + return iconMenu.status === PlasmaComponents.DialogStatus.Open + }) + + iconMenu.open(0, height) + } + + PlasmaCore.FrameSvgItem { + id: previewFrame + anchors.centerIn: parent + imagePath: plasmoid.location === PlasmaCore.Types.Vertical || plasmoid.location === PlasmaCore.Types.Horizontal + ? "widgets/panel-background" : "widgets/background" + width: units.iconSizes.large + fixedMargins.left + fixedMargins.right + height: units.iconSizes.large + fixedMargins.top + fixedMargins.bottom + + PlasmaCore.IconItem { + id: iconPreview + anchors.centerIn: parent + width: units.iconSizes.large + height: width + source: currentIcon + } + } + + function setDefaultIcon() { + iconPreview.source = defaultIcon + iconChanged(defaultIcon) + } + + // QQC Menu can only be opened at cursor position, not a random one + PlasmaComponents.ContextMenu { + id: iconMenu + visualParent: iconButton + + PlasmaComponents.MenuItem { + text: i18nc("@item:inmenu Open icon chooser dialog", "Choose...") + icon: "document-open-folder" + onClicked: iconDialog.open() + } + PlasmaComponents.MenuItem { + text: i18nc("@item:inmenu Reset icon to default", "Clear Icon") + icon: "edit-clear" + onClicked: setDefaultIcon() + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.activeApplication/contents/ui/main.qml b/kde/plasma/plasmoids/org.kde.activeApplication/contents/ui/main.qml new file mode 100644 index 00000000..8d20d03b --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.activeApplication/contents/ui/main.qml @@ -0,0 +1,264 @@ +/* + * Copyright 2018 avlas (based on Kotalnik and Broulik + * work) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.taskmanager 0.1 as TaskManager +import org.kde.activities 0.1 as Activities +import org.kde.plasma.private.appmenu 1.0 as AppMenuPrivate + +Item { + id: main + + property bool windowActive: false + property bool mouseHover: false + property var activeTaskLocal: null + property string tooltipText: '' + + anchors.fill: parent + anchors.left: parent.left + + Layout.fillWidth: false + Layout.minimumWidth: activeWindow.width + Layout.maximumWidth: activeWindow.width + + Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation + + //TasksModel + TaskManager.TasksModel { + id: tasksModel + + onActiveTaskChanged: { + updateActiveWindowInfo() + } + onDataChanged: { + updateActiveWindowInfo() + } + onCountChanged: { + updateActiveWindowInfo() + } + } + + //AppMenuModel (focus state) + AppMenuPrivate.AppMenuModel { + id: appMenuModel + } + + TaskManager.ActivityInfo { + id: activityInfo + + onCurrentActivityChanged: { + updateActiveWindowInfo(); + } + } + + Activities.ActivityModel { + id: activityModel + } + + function activeTask() { + return activeTaskLocal + } + + function activeTaskExists() { + return activeTask().display !== undefined || activeTask().appName !== undefined + } + + function toggleMaximized() { + tasksModel.requestToggleMaximized(tasksModel.activeTask); + } + + function toggleMinimized() { + tasksModel.requestToggleMinimized(tasksModel.activeTask); + } + + function toggleClose() { + tasksModel.requestClose(tasksModel.activeTask); + } + + function updateTooltip() { + tooltipText = activeTask().display || '' + } + + function composeNoWindowText() { + return plasmoid.configuration.noWindowText.replace('%activity%', activityInfo.activityName(activityInfo.currentActivity)) + } + + function updateActiveWindowInfo() { + + var activeTaskIndex = tasksModel.activeTask + + var abstractTasksModel = TaskManager.AbstractTasksModel + var isActive = abstractTasksModel.IsActive + + if (!tasksModel.data(activeTaskIndex, isActive)) { + activeTaskLocal = {} + } else { + activeTaskLocal = { + appName: tasksModel.data(activeTaskIndex, abstractTasksModel.AppName), + display: tasksModel.data(activeTaskIndex, Qt.DisplayRole), + decoration: tasksModel.data(activeTaskIndex, Qt.DecorationRole), + } + } + + var actTask = activeTask() + windowActive = activeTaskExists() + if (windowActive) { + activeWindowName.text = fineTuning(actTask.appName) + iconItem.source = actTask.decoration + } else if (!appMenuModel.menuAvailable || activeWindowName.text === "") { + activeWindowName.text = composeNoWindowText() + iconItem.source = plasmoid.configuration.noWindowIcon + } + updateTooltip() + } + + // active window info + Item { + id: activeWindow + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + + anchors.leftMargin: plasmoid.configuration.leftSpacing + anchors.rightMargin: plasmoid.configuration.rightSpacing + + width: plasmoid.configuration.showWindowIcon ? anchors.leftMargin + iconItem.width + plasmoid.configuration.iconAppNameSpacing + activeWindowName.width + anchors.rightMargin : anchors.leftMargin + activeWindowName.width + anchors.rightMargin + + Item { + height: main.height + + // window icon + PlasmaCore.IconItem { + id: iconItem + + anchors.left: parent.left + height: parent.height + + source: plasmoid.configuration.noWindowIcon + visible: plasmoid.configuration.showWindowIcon + } + + // window title + PlasmaComponents.Label { + id: activeWindowName + + anchors.left: parent.left + anchors.leftMargin: plasmoid.configuration.showWindowIcon ? iconItem.width + plasmoid.configuration.iconAppNameSpacing : 0 + anchors.top: parent.top + anchors.bottom: parent.bottom + height: parent.height + text: updateActiveWindowInfo() + wrapMode: Text.NoWrap + elide: Text.ElideNone + font.weight: plasmoid.configuration.boldFontWeight ? Font.Bold : theme.defaultFont.weight + } + } + } + + function fineTuning(title) { + + var replacements = plasmoid.configuration.titleReplacements; + + replacements = replacements.replace(/\n/g, ";"); + replacements = replacements.replace(/;;/g, ";"); + replacements = replacements.replace(/; | ;/g, ";"); + replacements = replacements.replace(/, | ,/g, ","); + + var appReplacements = replacements.split(";"); + + for (var iReplacement = 0; iReplacement < appReplacements.length; iReplacement++){ + + if (appReplacements[iReplacement].length > 0) { + + appReplacements[iReplacement] = appReplacements[iReplacement].replace(/"/g, ""); + + var repText = appReplacements[iReplacement].split(","); + + var regEx = new RegExp(repText[0], "ig"); //case insensitive + title = title.replace(regEx,repText[1]); + } + + } + return title; + } + + MouseArea { + anchors.fill: parent + + acceptedButtons: Qt.LeftButton | Qt.MiddleButton + + onClicked: { + if (mouse.button == Qt.MiddleButton) { + toggleClose() + } + } + + onDoubleClicked: { + // if (mouse.button == Qt.LeftButton) { + // toggleMinimized() + // } + if (mouse.button == Qt.LeftButton) { + toggleMaximized() + } + } + + hoverEnabled: true + + onEntered: { + mouseHover = true + } + + onExited: { + mouseHover = false + } + + PlasmaCore.ToolTipArea { + + anchors.fill: parent + + active: tooltipText !== '' + interactive: true + location: plasmoid.location + + mainItem: Row { + + spacing: 0 + + Layout.minimumWidth: fullText.width + units.largeSpacing + Layout.minimumHeight: childrenRect.height + Layout.maximumWidth: Layout.minimumWidth + Layout.maximumHeight: Layout.minimumHeight + + Item { + width: units.largeSpacing / 2 + height: 2 + } + + PlasmaComponents.Label { + id: fullText + text: tooltipText + } + } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.activeApplication/metadata.desktop b/kde/plasma/plasmoids/org.kde.activeApplication/metadata.desktop new file mode 100644 index 00000000..f4a52767 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.activeApplication/metadata.desktop @@ -0,0 +1,27 @@ +[Desktop Entry] +Name=Active application +Name[ca]=Applicació activa +Name[ca@valencia]=Applicació activa +Name[en_GB]=Active application +Name[es]=Aplicación activa +Name[x-test]=xxActive applicationxx +Comment=Plasmoid that shows the active application name. +Comment[ca]=Plasmoide que mostra el nom de l'aplicació activa. +Comment[ca@valencia]=Plasmoide que mostra el nom de l'aplicació activa. +Comment[en_GB]=Plasmoid that shows the active application name. +Comment[es]=Plasmoide que muestra el título de la aplicación activa. +Comment[x-test]=xxPlasmoid that shows the active application name.xx +Type=Service +X-KDE-ParentApp= +X-KDE-PluginInfo-Author=avlas +X-KDE-PluginInfo-Email=jsardid@gmail.com +X-KDE-PluginInfo-License=GPL2 +X-KDE-PluginInfo-Name=org.kde.activeApplication +X-KDE-PluginInfo-Version=1.1 +X-KDE-PluginInfo-Website= +X-KDE-ServiceTypes=Plasma/Applet +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml +X-Plasma-RemoteLocation= +X-KDE-PluginInfo-Category=Windows and Tasks +Icon=applications-other diff --git a/kde/plasma/plasmoids/org.kde.latte.separator/CHANGELOG.md b/kde/plasma/plasmoids/org.kde.latte.separator/CHANGELOG.md new file mode 100644 index 00000000..aca424cf --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.latte.separator/CHANGELOG.md @@ -0,0 +1,14 @@ +### CHANGELOG + +#### Version 0.1.2 + +* improve default values + +#### Version 0.1.1 + +* fix startup warning + +#### Version 0.1 + +* option for thickness margins +* option for length margins diff --git a/kde/plasma/plasmoids/org.kde.latte.separator/LICENSE b/kde/plasma/plasmoids/org.kde.latte.separator/LICENSE new file mode 100644 index 00000000..d159169d --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.latte.separator/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/kde/plasma/plasmoids/org.kde.latte.separator/README.md b/kde/plasma/plasmoids/org.kde.latte.separator/README.md new file mode 100644 index 00000000..6ae0ff35 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.latte.separator/README.md @@ -0,0 +1,21 @@ +# Latte Separator + +This is a Plasma 5 applet that acts as a separator between applets. This plasmoid is coming from [Latte land](https://phabricator.kde.org/source/latte-dock/repository/master/) but it can also support Plasma panels. + +

+
+Latte Separators between window icon, title and application menu +

+ +

+
+Appearance Settings +

+ +# Requires + +- Plasma >= 5.8 + +# Install + +This is a QML applet and as such it can be easily installed from Plasma 5 Widgets Explorer or alternative you can execute `plasmapkg2 -i .` in the root directory of the applet. diff --git a/kde/plasma/plasmoids/org.kde.latte.separator/contents/config/config.qml b/kde/plasma/plasmoids/org.kde.latte.separator/contents/config/config.qml new file mode 100644 index 00000000..4b47a2c9 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.latte.separator/contents/config/config.qml @@ -0,0 +1,31 @@ +/* +* Copyright 2017 Smith AR +* Michail Vourlakos +* +* This file is part of Latte-Dock +* +* Latte-Dock is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License, or (at your option) any later version. +* +* Latte-Dock is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +import QtQuick 2.0 + +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n("Appearance") + icon: "preferences-desktop-display-color" + source: "ConfigAppearance.qml" + } +} diff --git a/kde/plasma/plasmoids/org.kde.latte.separator/contents/config/main.xml b/kde/plasma/plasmoids/org.kde.latte.separator/contents/config/main.xml new file mode 100644 index 00000000..6a4fafba --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.latte.separator/contents/config/main.xml @@ -0,0 +1,27 @@ + + + + + + + + 3 + + + + 2 + + + + + + + + + 0 + + + diff --git a/kde/plasma/plasmoids/org.kde.latte.separator/contents/ui/ConfigAppearance.qml b/kde/plasma/plasmoids/org.kde.latte.separator/contents/ui/ConfigAppearance.qml new file mode 100644 index 00000000..b7b38197 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.latte.separator/contents/ui/ConfigAppearance.qml @@ -0,0 +1,75 @@ +/* +* Copyright 2019 Michail Vourlakos +* +* This file is part of Latte-Dock +* +* Latte-Dock is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License, or (at your option) any later version. +* +* Latte-Dock is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 +import QtGraphicalEffects 1.0 + +import org.kde.plasma.core 2.0 as PlasmaCore + +Item { + id: root + + property alias cfg_lengthMargin: lengthMargin.value + property alias cfg_thickMargin: thickMargin.value + + // used from the ui + readonly property real centerFactor: 0.3 + readonly property int minimumWidth: 220 + + ColumnLayout { + spacing: units.largeSpacing + Layout.fillWidth: true + + GridLayout{ + columns: 2 + Label { + Layout.minimumWidth: Math.max(centerFactor * root.width, minimumWidth) + text: i18n("Length margin:") + horizontalAlignment: Text.AlignRight + } + + SpinBox{ + id: lengthMargin + + minimumValue: 1 + maximumValue: 64 + stepSize: 1 + suffix: " " + i18nc("pixels","px.") + } + + Label { + Layout.minimumWidth: Math.max(centerFactor * root.width, minimumWidth) + text: i18n("Thickness margin:") + horizontalAlignment: Text.AlignRight + } + + SpinBox{ + id: thickMargin + + minimumValue: 0 + maximumValue: 64 + stepSize: 1 + suffix: " " + i18nc("pixels","px.") + } + } + + } +} diff --git a/kde/plasma/plasmoids/org.kde.latte.separator/contents/ui/main.qml b/kde/plasma/plasmoids/org.kde.latte.separator/contents/ui/main.qml new file mode 100644 index 00000000..ad1cae61 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.latte.separator/contents/ui/main.qml @@ -0,0 +1,93 @@ +/* + * Copyright 2019 Michail Vourlakos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +import QtQuick 2.4 +import QtQuick.Layouts 1.0 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.extras 2.0 as PlasmaExtras +Item { + id: root + readonly property bool horizontal: plasmoid.formFactor === PlasmaCore.Types.Horizontal + readonly property bool planar: plasmoid.formFactor === PlasmaCore.Types.Planar + + Layout.fillWidth: horizontal ? false : true + Layout.fillHeight: horizontal ? true : false + + Layout.minimumWidth: horizontal ? length : -1 + Layout.preferredWidth: Layout.minimumWidth + Layout.maximumWidth: Layout.minimumWidth + + Layout.minimumHeight: !horizontal ? length : -1 + Layout.preferredHeight: Layout.minimumHeight + Layout.maximumHeight: Layout.minimumHeight + + Plasmoid.preferredRepresentation: plasmoid.fullRepresentation + Plasmoid.backgroundHints: planar ? PlasmaCore.Types.StandardBackground : PlasmaCore.Types.NoBackground + + readonly property int length: latteBridge && latteBridge.inEditMode ? Math.max(10, totalLength) : Math.max(1, totalLength) + readonly property int totalLength: 2*plasmoid.configuration.lengthMargin + + readonly property int fullThickness: { + if (!parent) { + return 36; + } + + return plasmoid.formFactor === PlasmaCore.Types.Vertical ? parent.width : parent.height + } + readonly property int thickness: (latteBridge ? latteBridge.iconSize - (2*thickMargin) : fullThickness - (2*thickMargin)) + + readonly property int thickMargin: plasmoid.configuration.thickMargin + readonly property int lengthMargn: plasmoid.configuration.lengthMargin + + function increaseLength() { + plasmoid.configuration.lengthMargin = plasmoid.configuration.lengthMargin + 4; + } + + function decreaseLength() { + plasmoid.configuration.lengthMargin = Math.max(0,plasmoid.configuration.lengthMargin - 4); + } + + //BEGIN Latte Dock Communicator + property QtObject latteBridge: null // current Latte v0.9 API + + onLatteBridgeChanged: { + if (latteBridge) { + latteBridge.actions.setProperty(plasmoid.id, "latteSideColoringEnabled", false); + } + } + //END Latte Dock Communicator + //BEGIN Latte based properties + readonly property bool enforceLattePalette: latteBridge && latteBridge.applyPalette && latteBridge.palette + readonly property bool latteInEditMode: latteBridge && latteBridge.inEditMode + //END Latte based properties + + Rectangle { + id: sep + anchors.centerIn: parent + + width: horizontal ? 1 : thickness + height: !horizontal ? 1 : thickness + + color: enforceLattePalette ? latteBridge.palette.textColor : theme.textColor + opacity: 0.4 + visible: !planar + } +} diff --git a/kde/plasma/plasmoids/org.kde.latte.separator/metadata.desktop b/kde/plasma/plasmoids/org.kde.latte.separator/metadata.desktop new file mode 100644 index 00000000..e4d0c60a --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.latte.separator/metadata.desktop @@ -0,0 +1,21 @@ +[Desktop Entry] +Name=Latte Separator +Comment=For all your separation tasks + +Encoding=UTF-8 +Icon=filename-divider +Keywords=separator +Type=Service + +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml + +X-KDE-PluginInfo-Author=Michail Vourlakos +X-KDE-PluginInfo-Category=Utilities +X-KDE-PluginInfo-Email=mvourlakos@gmail.com +X-KDE-PluginInfo-License=GPLv2 +X-KDE-PluginInfo-Name=org.kde.latte.separator +X-KDE-PluginInfo-Version=0.1.2 +X-KDE-PluginInfo-Website=https://github.com/psifidotos/applet-latte-separator +X-KDE-ServiceTypes=Plasma/Applet + diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/config/config.qml b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/config/config.qml new file mode 100644 index 00000000..a91d9fc8 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/config/config.qml @@ -0,0 +1,20 @@ +import QtQuick 2.2 +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n("General") + icon: 'preferences-desktop-settings' + source: 'config/configGeneral.qml' + } + ConfigCategory { + name: i18n("Network") + icon: 'network-card' //'network-wired' + source: 'config/configNetwork.qml' + } + // ConfigCategory { + // name: i18n('Tooltip') + // icon: 'dialog-information' //'preferences-desktop-locale' //'configure' + // source: 'config/configToolTip.qml' + // } +} diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/config/main.xml b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/config/main.xml new file mode 100644 index 00000000..41b7ef6f --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/config/main.xml @@ -0,0 +1,129 @@ + + + + + + + true + + + auto + + + false + + + ᐁ ᐃ + + + true + + + true + + + bits + + + false + + + 1 + + + 500 + + + false + + + binary + + + 1 + + + 0 + + + 0 + + + false + + + false + + + true + + + /s + + + true + + + true + + + true + + + true + + + 3 + + + 1 + + + 1 + + + + + + + + + + + + diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/locale/zh_CN/LC_MESSAGES/plasma_applet_org.kde.nsw_dbus.mo b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/locale/zh_CN/LC_MESSAGES/plasma_applet_org.kde.nsw_dbus.mo new file mode 100644 index 00000000..9c9414ab Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/locale/zh_CN/LC_MESSAGES/plasma_applet_org.kde.nsw_dbus.mo differ diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/CompactRepresentation.qml b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/CompactRepresentation.qml new file mode 100644 index 00000000..d1e68566 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/CompactRepresentation.qml @@ -0,0 +1,991 @@ +/* + * Copyright 2023 LeeVD thoth360@hotmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + // useful: + // Run widget: + // plasmoidviewer -a org.kde.nbm_wip -l topedge -f horizontal + // serialised settings: + // home/user/.config/plasmoidviewer-appletsrc + +import QtQuick 2.15 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.0 as PlasmaCore +//import org.kde.plasma.components 3.0 as PlasmaComponents // used in tooltip section +//import org.kde.plasma.extras 2.0 as PlasmaExtras // used in tooltip section + + + +Item { + id: itemParent + anchors.fill: parent + + property double marginFactor: 0.2 + + // PRIMARY UI INTERFACE DATA VARIABLES + property double downSpeed: 0 + property double upSpeed: 0 + + property bool singleLine: { + if (!showSeparately) { + return true + } + switch (speedLayout) { + case 'row': return true // SIDE BY SIDE + case 'column': return false // ONE ABOVE OTHER + default: return height / 2 * fontSizeScale < theme.smallestFont.pixelSize && plasmoid.formFactor !== PlasmaCore.Types.Vertical + } + } + + property double marginWidth: speedTextMetrics.font.pixelSize * marginFactor + property double iconWidth: showIcons ? iconTextMetrics.width + marginWidth : 0 + property double doubleIconWidth: showIcons ? (doubleIconTextMetrics.width + marginWidth) : 0 + property double speedWidth: speedTextMetrics.width + 2*marginWidth + property double unitWidth: showUnits ? unitTextMetrics.width + marginWidth : 0 + + //property double toolTipWidth: showTooltip ? TextMetrics2 : 0 + + + property double aspectRatio: { + if (showSeparately) { + if (singleLine) { + return (2*iconWidth + 2*speedWidth + 2*unitWidth + marginWidth) * fontSizeScale / speedTextMetrics.height + } else { + return (iconWidth + speedWidth + unitWidth) * fontSizeScale / (2*speedTextMetrics.height) + } + } else { + return (doubleIconWidth + speedWidth + unitWidth) * fontSizeScale / speedTextMetrics.height + } + } + + property double fontHeightRatio: speedTextMetrics.font.pixelSize / speedTextMetrics.height + + property double offset: { + if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { + return (width - height * aspectRatio) / 2 + } else { + return 0 + } + } + + property bool boolUnits: { + if (speedUnits !== 'bits') return false; + else return true; + } + + property double getBinDec: { + if (binaryDecimal === 'binary') return 1024; // binary + else return 1000; // decimal + } + + Layout.minimumWidth: { + if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { + return 0 + } else if (plasmoid.formFactor === PlasmaCore.Types.Horizontal) { + return Math.ceil(height * aspectRatio) + } else { + return Math.ceil(height * aspectRatio) + } + } + Layout.minimumHeight: { + if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { + return Math.ceil(width / aspectRatio * fontSizeScale * fontSizeScale) + } else if (plasmoid.formFactor === PlasmaCore.Types.Horizontal) { + return 0 + } else { + return Math.ceil(theme.smallestFont.pixelSize / fontSizeScale) + } + } + + Layout.preferredWidth: Layout.minimumWidth + Layout.preferredHeight: Layout.minimumHeight + + TextMetrics { + id: iconTextMetrics + text: iconStyle(1) + font.pixelSize: 64 + } + + TextMetrics { + id: doubleIconTextMetrics + text: iconStyle(2) + font.pixelSize: 64 + } + + TextMetrics { + id: speedTextMetrics + text: getDecimalPlace() //'1000.0' + font.pixelSize: 64 + } + + TextMetrics { + id: unitTextMetrics + text: { + if (speedUnits === 'bits') { + return shortUnits ? 'm' : 'Mib/s' + } else { + return shortUnits ? 'M' : 'MiB/s' + } + } + font.pixelSize: 64 + } + + Item { + id: offsetItem + width: offset + height: parent.height + x: 0 + y: 0 + } + + // USED FOR TESTING UI + // Rectangle{ + // id: rec_t1 + // height: dataShown('t1', 'height') + // width: dataShown('t1', 'width') + // anchors.left: dataShown('t1', 'anchorL') + // anchors.leftMargin: dataShown('t1', 'anchorLMargin') + // y: dataShown('t1', 'y') + // visible: true //dataShown('t1', 'visible') + // color: "red" + // } + // Rectangle{ + // id: rec_t2 + // height: dataShown('t2', 'height') + // width: dataShown('t2', 'width') + // anchors.left: dataShown('t2', 'anchorL') + // anchors.leftMargin: dataShown('t2', 'anchorLMargin') + // y: dataShown('t2', 'y') + // visible: true //dataShown('t2', 'visible') + // color: "blue" + // } + // Rectangle{ + // id: rec_t3 + // height: dataShown('t3', 'height') + // width: dataShown('t3', 'width') + // anchors.left: dataShown('t3', 'anchorL') + // anchors.leftMargin: dataShown('t3', 'anchorLMargin') + // y: dataShown('t3', 'y') + // visible: true //dataShown('t3', 'visible') + // color: "green" + // } + + // Rectangle{ + // id: rec_b1 + // height: dataShown('b1', 'height') + // width: dataShown('b1', 'width') + // anchors.left: dataShown('b1', 'anchorL') + // anchors.leftMargin: dataShown('b1', 'anchorLMargin') + // y: dataShown('b1', 'y') + // visible: true //dataShown('b1', 'visible') + // color: "dark blue" + // } + // Rectangle{ + // id: rec_b2 + // height: dataShown('b2', 'height') + // width: dataShown('b2', 'width') + // anchors.left: dataShown('b2', 'anchorL') + // anchors.leftMargin: dataShown('b2', 'anchorLMargin') + // y: dataShown('b2', 'y') + // visible: true //dataShown('b2', 'visible') + // color: "purple" + // } + // Rectangle{ + // id: rec_b3 + // height: dataShown('b3', 'height') + // width: dataShown('b3', 'width') + // anchors.left: dataShown('b3', 'anchorL') + // anchors.leftMargin: dataShown('b3', 'anchorLMargin') + // y: dataShown('b3', 'y') + // visible: true //dataShown('b3', 'visible') + // color: "pink" + // } + + Text { + id: t1 //topIcon + height: dataShown('t1', 'height') + width: dataShown('t1', 'width') + verticalAlignment: dataShown('t1', 'vertiAlign') + horizontalAlignment:dataShown('t1', 'horizAlign') + anchors.left: dataShown('t1', 'anchorL') + anchors.leftMargin: dataShown('t1', 'anchorLMargin') + y: dataShown('t1', 'y') + font.pixelSize: dataShown('t1', 'fontPixSize') + renderType: dataShown('t1', 'renderType') + text: dataShown('t1', 'text') + color: dataShown('t1', 'color') + visible: dataShown('t1', 'visible') + bottomPadding: dataShown('t1', 'padding') //-10.0 + } + + Text { + id: t2 //topText + height: dataShown('t2', 'height') + width: dataShown('t2', 'width') + verticalAlignment: dataShown('t2', 'vertiAlign') + horizontalAlignment:dataShown('t2', 'horizAlign') + anchors.left: dataShown('t2', 'anchorL') + anchors.leftMargin: dataShown('t2', 'anchorLMargin') + y: dataShown('t2', 'y') + font.pixelSize: dataShown('t2', 'fontPixSize') + renderType: dataShown('t2', 'renderType') + text: dataShown('t2', 'text') + color: dataShown('t2', 'color') + visible: dataShown('t2', 'visible') + bottomPadding: dataShown('t2', 'padding') //-10.0 + } + + Text { + id: t3 //topUnitText + height: dataShown('t3', 'height') + width: dataShown('t3', 'width') + verticalAlignment: dataShown('t3', 'vertiAlign') + horizontalAlignment:dataShown('t3', 'horizAlign') + anchors.left: dataShown('t3', 'anchorL') + anchors.leftMargin: dataShown('t3', 'anchorLMargin') + y: dataShown('t3', 'y') + font.pixelSize: dataShown('t3', 'fontPixSize') + renderType: dataShown('t3', 'renderType') + text: dataShown('t3', 'text') + color: dataShown('t3', 'color') + visible: dataShown('t3', 'visible') + bottomPadding: dataShown('t3', 'padding') //-10.0 + } + + Text { + id: b1 //bottomIcon + height: dataShown('b1', 'height') + width: dataShown('b1', 'width') + verticalAlignment: dataShown('b1', 'vertiAlign') + horizontalAlignment:dataShown('b1', 'horizAlign') + anchors.left: dataShown('b1', 'anchorL') + anchors.leftMargin: dataShown('b1', 'anchorLMargin') + y: dataShown('b1', 'y') + font.pixelSize: dataShown('b1', 'fontPixSize') + renderType: dataShown('b1', 'renderType') + text: dataShown('b1', 'text') + color: dataShown('b1', 'color') + visible: dataShown('b1', 'visible') + topPadding: dataShown('b1', 'padding') //-10.0 + //bottomPadding: 30.0 + //topPadding: -10.0 + } + + Text { + id: b2 //bottomText + height: dataShown('b2', 'height') + width: dataShown('b2', 'width') + verticalAlignment: dataShown('b2', 'vertiAlign') + horizontalAlignment:dataShown('b2', 'horizAlign') + anchors.left: dataShown('b2', 'anchorL') + anchors.leftMargin: dataShown('b2', 'anchorLMargin') + y: dataShown('b2', 'y') + font.pixelSize: dataShown('b2', 'fontPixSize') + renderType: dataShown('b2', 'renderType') + text: dataShown('b2', 'text') + color: dataShown('b2', 'color') + visible: dataShown('b2', 'visible') + topPadding: dataShown('b2', 'padding') //-10.0 + } + + Text { + id: b3 //bottomUnitText + height: dataShown('b3', 'height') + width: dataShown('b3', 'width') + verticalAlignment: dataShown('b3', 'vertiAlign') + horizontalAlignment:dataShown('b3', 'horizAlign') + anchors.left: dataShown('b3', 'anchorL') + anchors.leftMargin: dataShown('b3', 'anchorLMargin') + y: dataShown('b3', 'y') + font.pixelSize: dataShown('b3', 'fontPixSize') + renderType: dataShown('b3', 'renderType') + text: dataShown('b3', 'text') + color: dataShown('b3', 'color') + visible: dataShown('b3', 'visible') + topPadding: dataShown('b3', 'padding') //-10.0 + } + + + PlasmaCore.ToolTipArea { + anchors.fill: parent + interactive: true + mainText: i18n("Network Bandwidth Monitor") + subText: i18n("DBUS Data Source") + icon: 'network-connect' + } + + + function dataShown(caller, properties){ + var height = singleLine ? itemParent.height : itemParent.height / 2 + var fontPixelSize = height * fontHeightRatio * fontSizeScale + + if (iconPosition === true) { // true = icons on right + // DIFFERENT VARIABLES WITH ICONS ON RIGHT + switch (properties) { + case 'width': + var a = (showSeparately ? 1 : 2) * iconTextMetrics.width / iconTextMetrics.height * height * fontSizeScale + var b = speedTextMetrics.width / speedTextMetrics.height * height * fontSizeScale + var c = unitTextMetrics.width / unitTextMetrics.height * height * fontSizeScale + var d = iconTextMetrics.width / iconTextMetrics.height * height * fontSizeScale + switch (caller) { + case 't1': return b //a + case 't2': return c //b + case 't3': return a //c + case 'b1': return b //d + case 'b2': return c //b + case 'b3': return d //c + } + case 'horizAlign': + switch (caller) { + // left : text in t2 & b2 | right : text in t1 & b1 | left Alt : see left + case 't1': return Text.AlignRight + case 't2': return Text.AlignLeft + case 't3': return Text.AlignHCenter //Text.AlignVCenter + case 'b1': return Text.AlignRight + case 'b2': return Text.AlignLeft + case 'b3': return Text.AlignHCenter //Text.AlignVCenter + } + case 'anchorL': + switch (caller) { + case 't1': return offsetItem.right + case 't2': return t1.right + case 't3': return showUnits ? t2.right : t1.right + case 'b1': return anchorLfunction() //(singleLine && showIcons) ? t3.right : (singleLine ? t2.right : offsetItem.right) //showIcon + case 'b2': return b1.right + case 'b3': return showUnits ? b2.right : b1.right + } + case 'fontPixSize': + switch (caller) { + case 't1': return Math.round(height * fontHeightRatio * fontSizeScale ) // needs to return int not float + case 't2': return Math.round(height * fontHeightRatio * sufixSize ) + case 't3': return Math.round(height * fontHeightRatio * iconSize); + case 'b1': return Math.round(height * fontHeightRatio * fontSizeScale ) + case 'b2': return Math.round(height * fontHeightRatio * sufixSize ) + case 'b3': return Math.round(height * fontHeightRatio * iconSize) + } + case 'text': + switch (caller) { + case 't1': return speedDisplay('number', showSeparately ? (swapDownUp ? upSpeed : downSpeed) : downSpeed + upSpeed) + case 't2': return speedDisplay('suffix', showSeparately ? (swapDownUp ? upSpeed : downSpeed) : downSpeed + upSpeed) + case 't3': return showSeparately ? (swapDownUp ? iconStyle(0) : iconStyle(1)) : iconStyle(2) + case 'b1': return speedDisplay('number', swapDownUp ? downSpeed : upSpeed) + case 'b2': return speedDisplay('suffix', swapDownUp ? downSpeed : upSpeed) + case 'b3': return swapDownUp ? iconStyle(1) : iconStyle(0) + } + case 'visible': + return setUiVisible(caller) + } + } else { // false = icons on left [default] + // DIFFERENT VARIABLES WITH ICONS ON LEFT + switch (properties) { + case 'width': + var leftUpIconWidth = (showSeparately ? 1 : 2) * iconTextMetrics.width / iconTextMetrics.height * height * fontSizeScale + var leftTextWidth = speedTextMetrics.width / speedTextMetrics.height * height * fontSizeScale + var leftUnitWidth = unitTextMetrics.width / unitTextMetrics.height * height * fontSizeScale + var leftDownIconWidth = iconTextMetrics.width / iconTextMetrics.height * height * fontSizeScale + switch (caller) { + case 't1': return leftUpIconWidth // icon + case 't2': return leftTextWidth // text + case 't3': return leftUnitWidth // unit + case 'b1': return leftDownIconWidth // icon + case 'b2': return leftTextWidth // text + case 'b3': return leftUnitWidth // unit + } + case 'horizAlign': + switch (caller) { + // left : text in t2 & b2 | right : text in t1 & b1 | left Alt : see left + case 't1': return Text.AlignHCenter //Text.AlignVCenter + case 't2': return Text.AlignRight + case 't3': return Text.AlignLeft + case 'b1': return Text.AlignHCenter //Text.AlignVCenter + case 'b2': return Text.AlignRight + case 'b3': return Text.AlignLeft + } + case 'anchorL': + switch (caller) { + case 't1': return offsetItem.right + case 't2': return showIcons ? t1.right : offsetItem.right + case 't3': return t2.right + + case 'b1': return (singleLine && showUnits) ? t3.right : (singleLine ? t2.right : offsetItem.right) + case 'b2': return showIcons ? b1.right : ((singleLine && showUnits) ? t3.right : (singleLine ? t2.right : offsetItem.right)) + case 'b3': return b2.right + } + case 'fontPixSize': + switch (caller) { + case 't1': return Math.round(height * fontHeightRatio * iconSize) // needs to return int not float + case 't2': return Math.round(height * fontHeightRatio * fontSizeScale ) + case 't3': return Math.round(height * fontHeightRatio * sufixSize ) + case 'b1': return Math.round(height * fontHeightRatio * iconSize) + case 'b2': return Math.round(height * fontHeightRatio * fontSizeScale ) + case 'b3': return Math.round(height * fontHeightRatio * sufixSize ) + } + case 'text': + switch (caller) { + case 't1': return showSeparately ? (swapDownUp ? iconStyle(0) : iconStyle(1)) : iconStyle(2) + case 't2': return speedDisplay('number', showSeparately ? (swapDownUp ? upSpeed : downSpeed) : downSpeed + upSpeed) //speedDisplay(section, value) + case 't3': return speedDisplay('suffix', showSeparately ? (swapDownUp ? upSpeed : downSpeed) : downSpeed + upSpeed) + case 'b1': return swapDownUp ? iconStyle(1) : iconStyle(0) + case 'b2': return speedDisplay('number', swapDownUp ? downSpeed : upSpeed) + case 'b3': return speedDisplay('suffix', swapDownUp ? downSpeed : upSpeed) + } + case 'visible': + return setUiVisible(caller) + } + } + // SAME VARIABLES WITH ICONS EITHER SIDE + switch (properties) { + case 'height': return singleLine ? itemParent.parent.height : itemParent.parent.height / 2 + case 'vertiAlign': //return Text.AlignVCenter Text.AlignTop + switch (caller) { + case 't1': return Text.AlignVCenter //Text.AlignBottom + case 't2': return Text.AlignVCenter //Text.AlignBottom + case 't3': return Text.AlignVCenter //Text.AlignBottom + case 'b1': return Text.AlignVCenter //Text.AlignTop + case 'b2': return Text.AlignVCenter //Text.AlignTop + case 'b3': return Text.AlignVCenter //Text.AlignTop + } + case 'anchorLMargin': return fontPixelSize * marginFactor + case 'y': + switch (caller) { + case 't1': return 0 + case 't2': return 0 + case 't3': return 0 + case 'b1': return singleLine ? 0 : itemParent.height / 2 + case 'b2': return singleLine ? 0 : itemParent.height / 2 + case 'b3': return singleLine ? 0 : itemParent.height / 2 + } + case 'renderType': return Text.NativeRendering + case 'color': return theme.textColor + case 'padding': return layoutPadding + } + } + + + function setUiVisible(caller) { + // UI ELEMENTS VISIBLE BASED ON hideInactive + + if (hideInactive === true) { + if (downSpeed === 0 && upSpeed === 0) { + t1.visible = false + t2.visible = false + t3.visible = false + b1.visible = false + b2.visible = false + b3.visible = false + } else { + t1.visible = iconPosition ? true : showIcons + t2.visible = iconPosition ? showUnits : true + t3.visible = iconPosition ? showIcons : showUnits + b1.visible = iconPosition ? showSeparately : showSeparately && showIcons + b2.visible = iconPosition ? showSeparately && showUnits : showSeparately + b3.visible = iconPosition ? showSeparately && showIcons : showSeparately && showUnits + } + } else { + // UI ELEMENTS VISIBLE BASED ON iconPosition + t1.visible = iconPosition ? true : showIcons + t2.visible = iconPosition ? showUnits : true + t3.visible = iconPosition ? showIcons : showUnits + b1.visible = iconPosition ? showSeparately : showSeparately && showIcons + b2.visible = iconPosition ? showSeparately && showUnits : showSeparately + b3.visible = iconPosition ? showSeparately && showIcons : showSeparately && showUnits + } + switch (caller) { + case 't1': return iconPosition ? true : showIcons + case 't2': return iconPosition ? showUnits : true + case 't3': return iconPosition ? showIcons : showUnits + case 'b1': return iconPosition ? showSeparately : showSeparately && showIcons + case 'b2': return iconPosition ? showSeparately && showUnits : showSeparately + case 'b3': return iconPosition ? showSeparately && showIcons : showSeparately && showUnits + } + } + + + function anchorLfunction() { + switch (singleLine) { + case false : // one above other + return offsetItem.right + + case true : // side by side + switch (showUnits) { + case false : + if (showIcons === false) return t1.right + else return t3.right + + case true : + if (showIcons === false) return t2.right + else return t3.right + } + } + } + + + function iconStyle(a) { + + var iconArray = [] + + iconArray = iconType.replace(' ', ',').split(",") + + switch(a) { + case 0: return iconArray[1] + case 1: return iconArray[0] + case 2: return iconArray[1] + iconArray[0] + } + } + + + function getDecimalPlace() { + return Number.parseFloat('1000').toFixed( decimalPlace ); + } + + + function customRound(number) { + var decimalPart = number - Math.floor(number); + if (decimalPart >= 0.445) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + + + function speedDisplay(section, value) { + // data communication 1 kilobit = 1000 bits, while in data storage 1 Kilobyte = 1024 Bytes + var m = getBinDec // binary 1024 | decimal 1000 + var dec = decimalPlace // # of decimal places + // BIT CONVERSION TO HIGHER PREFIXES + var kil = m; // One K is 1024 b/B 1024 1000 + var meg = m * m; // One M is 1024 Kb/B 1048576 1000000 + var gig = m * m * m; // One G is 1024 Mb/B 1073741824 1000000000 + var ter = m * m * m * m; // One T is 1024 Gb/B 1099511627776 1000000000000 + // NEW THRESHOLD : 4 DIGITS ALLOWED + const fourb = 10000; + const fourk = 10000000; + const fourm = 10000000000; + const fourg = 10000000000000; + const fourt = 10000000000000000; + + var result; + var digitNum = value.toString().length; + + if (section === 'number') { + + if (roundedNumber === 3) { + + if (value < kil) { + result = decimalFilter0 ? value.toFixed(dec) : value; // result = '' if less than a Kx + } else if (value < meg) { + result = decimalFilter1 ? (value / kil).toFixed(dec) : customRound(value / kil); // return Kx if less than a Mx + } else if (value < gig) { + result = decimalFilter2 ? (value / meg).toFixed(dec) : customRound(value / meg); // return Mx if less than a Gx + } else if (value < ter) { + result = decimalFilter3 ? (value / gig).toFixed(dec) : customRound(value / gig); // result = Gx if less than a Gx + } else { + result = decimalFilter3 ? (value / ter).toFixed(dec) : customRound(value / ter); // result = Tx if less than a Tx + } + + } else { + + // roundedNumber SET TO 4 [ EX. BITS= 1211648 RESULT= 1183.25 Kb NOT 1.16 Mb ] + if (value < fourb) { + result = decimalFilter0 ? value.toFixed(dec) : value; // return '' if less than a Kx + } else if (value < fourk) { + result = decimalFilter1 ? (value / kil).toFixed(dec) : customRound(value / kil); // return Kx if less than a Mx + } else if (value < fourm) { + result = decimalFilter2 ? (value / meg).toFixed(dec) : customRound(value / meg); // return Mx if less than a Gx + } else if (value < fourg) { + result = decimalFilter3 ? (value / gig).toFixed(dec) : customRound(value / gig); // return Gx if less than a Tx + } else { + result = decimalFilter3 ? (value / ter).toFixed(dec) : customRound(value / ter); // return Gx if less than a Tx + } + } + + } else if (section === 'suffix') { + + if (roundedNumber === 3) { + if (value < kil) { + result = shortUnits ? (boolUnits ? 'b' : 'B') : suffix('b') + } else if (value < meg) { + result = shortUnits ? (boolUnits ? 'k' : 'K') : suffix('k') + } else if (value < gig) { + result = shortUnits ? 'M' : suffix('M') + } else if (value < ter) { + result = shortUnits ? 'G' : suffix('G') + } else { + result = shortUnits ? 'T' : suffix('T') + } + + } else { + + // roundedNumber SET TO 4 [ EX. BITS= 1211648 RESULT= 1183.25 Kb NOT 1.16 Mb ] RETURN Kb NOT Mb + if (value < fourb) { + result = shortUnits ? (boolUnits ? 'b' : 'B') : suffix('b') + } else if (value < fourk) { + result = shortUnits ? (boolUnits ? 'k' : 'K') : suffix('k') + } else if (value < fourm) { + result = shortUnits ? 'M' : suffix('M') + } else if (value < fourg) { + result = shortUnits ? 'G' : suffix('G') + } else { + result = shortUnits ? 'T' : suffix('T') + } + } + } + //console.log("value:", value, " result:", result, " digitNum:", digitNum, " roundedNumber:", roundedNumber); + return result + } + + + function suffix(unit) { // NEW SOLUTION TO SUFFIX + // https://en-academic.com/dic.nsf/enwiki/8315069#Kibibit_per_second + //! BINARY: DECIMAL: + //! Kibibit = 1024 bits | Kilobit = 1000 bits + //! Kibibyte = 1024 bytes | Kilobyte = 1000 bytes + //! Kib/s Mib/s | kb/s Mb/s + //! KiB/s MiB/s | KB/s MB/s + + // APPEND BINARY OR DECIMAL UNIT PREFIX + if (binaryDecimal === 'binary') { + if (unit !== 'b') { + if (unit === 'k') { unit = 'K' } + unit += 'i' + } + } + // CONVERT OR APPEND BIT OR BYTE UNIT PREFIX + if (speedUnits === 'bits') { + if (unit !== 'b') { unit += 'b' } + + } else { + if (unit === 'b') { unit = 'B' } + else { unit += 'B' } + } + // APPEND PER SECOND PREFIX + if (showSeconds === true) { + unit += secondsPrefix + } + return unit + } + + //################## SERIALISATION FIX ########################### + + function netSourceEncode(value) { + return JSON.stringify(value) + } + + function netSourceDecode(value) { + try { + return JSON.parse(value) + } catch (E) { + return [] + } + } + + //##################################################### + + //2nd + function addSources() { + + var count = 0; + var checkedCount = 0 + var sensors = []; + var netPath = [] + + sensorList = []; + sensors = dbusData.allSensors("network/"); + + //console.log("sensors: from CR " + sensors) + // qml: Network-sensors: + // network/all, + // network/all/download, + // network/all/downloadBits, + // network/all/totalDownload + // network/all/totalUpload, + // network/all/upload, + // network/all/uploadBits, + // network/wlp2s0, + // network/wlp2s0/download, + // network/wlp2s0/downloadBits, + // network/wlp2s0/ipv4address, + // network/wlp2s0/ipv4dns, + // network/wlp2s0/ipv4gateway, + // network/wlp2s0/ipv4subnet, + // network/wlp2s0/ipv4withPrefixLength, + // network/wlp2s0/ipv6address, + // network/wlp2s0/ipv6dns, + // network/wlp2s0/ipv6gateway, + // network/wlp2s0/ipv6subnet, + // network/wlp2s0/ipv6withPrefixLength, + // network/wlp2s0/network, <<< here + // network/wlp2s0/signal, + // network/wlp2s0/totalDownload, + // network/wlp2s0/totalUpload, + // network/wlp2s0/upload, + // network/wlp2s0/uploadBits, + + //var duplicateCheck = {} + + for (var idx = 0; idx < sensors.length; idx++) { + + if (sensors[idx].endsWith("/network")) { + + netPath = { path:sensors[idx].replace("/network", ""), + name:dbusData.stringData(sensors[idx]), + index:idx, + checked:true } + + netInterfaces[count] = netPath // ADD INTERFACE ARRAY DATA TO MULTI DEM ARRAY + count += 1; + } + } + // COMPARE EXISTING INTERFACE SETTINGS WITH DISCOVERED INTERFACES + // IF USER SETS AN INTERFACE TO NOT BE MONITORED, STORED SETTINGS WILL + // HAVE IT AS CHECKED:FALSE. ADD THIS CHANGE TO netInterfaces ARRAY. + // IF A NEW INTERFACE IS DISCOVERED, IT WILL BE ADDED / PUSHED TO THE SETTINGS STORE. + + //var pcn = plasmoid.configuration.netSources + var pcn = netSourceDecode(plasmoid.configuration.netSources) + //console.log("PCN: "+netSourceEncode(pcn)) + + var ni = netInterfaces + //console.log("NI: "+netSourceEncode(ni)) + + for (var i = 0; i < pcn.length; i++) { // LOOP THROUGH FIRST STORED SETTINGS ARRAY + + for (var ii = 0; ii < ni.length; ii++) { // LOOP THROUGH SECOND netInterfaces ARRAY + + if (pcn[i].path === ni[ii].path) { // PATHS MATCH - NOW COMPARE 'CHECKED' + + if (pcn[i].checked !== ni[ii].checked) { // DIFFERENT CHECKED MARK, PCN HAS BEEN UPDATED. MAKE NI SAME AS PCN + //netInterfaces[ii].checked = pcn[i].checked + ni[ii].checked = pcn[i].checked + } + } + // console.log("netInterfaces: PATH: " + netInterfaces[ii].path + + // ", NAME: " + netInterfaces[ii].name + + // ", INDEX: " + netInterfaces[ii].index + + // ", CHECKED: " + netInterfaces[ii].checked) + } + } + + plasmoid.configuration.netSources = netSourceEncode(ni) //netInterfaces) // PUSH FOUND INTERFACES TO STORED SETTINGS + //pcn = plasmoid.configuration.netSources // REFRESH DATA IN VARIABLE + //pcn = netSourceEncode(plasmoid.configuration.netSources) // REFRESH DATA IN VARIABLE + //console.log("PCN2:"+netSourceEncode(pcn)) + //console.log("NI2: "+netSourceEncode(ni)) + + netDataBits = []; // RESET ARRAYS + netDataByte = []; + netDataTotal = []; + + for (var i = 0; i < ni.length; i++) { // LOOP THROUGH FIRST STORED SETTINGS ARRAY + if (ni[i].checked === true) { + + sensorList.push(ni[i].path + "/downloadBits", // CREATE ARRAY TO SUBSCRIBE TO AND POLL FROM DBUS + ni[i].path + "/uploadBits", + ni[i].path + "/download", + ni[i].path + "/upload", + ni[i].path + "/totalDownload", + ni[i].path + "/totalUpload", + ni[i].path + "/signal") + + // INITIALIZE AND SET GLOBAL VARIABLES BASED ON CHECKED:TRUE INTERFACES + netDataBits[checkedCount] = { down: 0, up: 0 }; + netDataByte[checkedCount] = { down: 0, up: 0 }; + netDataTotal[checkedCount] = { down: 0, up: 0 }; + + checkedCount += 1 + } + } + netDataAccumulator = { down: 0, up: 0 }; + //console.log(sensorList) + dbusData.subscribe(sensorList); + //numberOfNets = count; + numCheckedNets = checkedCount + ready = true; + } + + + Connections { + target: plasmoid.configuration + function onNetSourcesChanged() { // TRIGGERED WHEN INTERFACE CHECKED CHANGED IN SETTINGS + dbusData.unsubscribe(sensorList) + if ( !ready ) return + else addSources() + } + } + + + Connections { + target: sysMonitor + + function onStatsUpd(pathKeys, values) { + // TRIGGERED EVERY 500 MILLISECONDS + + //console.log("CR-onStatsUpd: "+ pathKeys + " || "+ values) + // qml: CR-onStatsUpd: network/wlp2s0/download,network/wlp2s0/upload || 334,128 + // qml: CR-onStatsUpd: network/wlp2s0/downloadBits,network/wlp2s0/totalDownload,network/wlp2s0/uploadBits,network/wlp2s0/totalUpload || 0,49913032,0,169202 + + var sensorPathKey; // PATH AND KEY OF DBUS FOUND INTERFACE VALUE + var configPath; // PATH OF INTERFACE IN SETTINGS / CONFIG + var slot = 0 + var ni = netInterfaces //plasmoid.configuration.netSources + + if ( !ready ) return; + + for (var i = 0; i < ni.length; i++) { // LOOP SETTINGS INTERFACE AND GRAB PATH OF CHECKED:TRUE + + if (ni[i].checked === true) { + configPath = ni[i].path + }else{ + continue // SKIP SETTINGS INTERFACE THAT ISNT CHECKED:TRUE + } + + for ( var ii = 0; ii < pathKeys.length; ii++ ) { // LOOP DBUS SENSOR PATH & KEYS + + sensorPathKey = pathKeys[ii]; + + if (sensorPathKey.indexOf(configPath) == 0) { + + if (sensorPathKey == configPath + "/download") { // DOWNLOAD IN BYTES + netDataByte[slot].down = values[ii] + } + if (sensorPathKey == configPath + "/downloadBits") { // DOWNLOAD IN BITS + netDataBits[slot].down = values[ii] + } + if (sensorPathKey == configPath + "/totalDownload") { // TOTAL DOWNLOAD IN BYTES: + netDataTotal[slot].down = values[ii] + } + if (sensorPathKey == configPath + "/upload") { // UPLOAD IN BYTES + netDataByte[slot].up = values[ii] + } + if (sensorPathKey == configPath + "/uploadBits") { // UPLOAD IN BITS + netDataBits[slot].up = values[ii] + } + if (sensorPathKey == configPath + "/totalUpload") { // TOTAL UPLOAD IN BYTES: + netDataTotal[slot].up = values[ii] + } + } + } + slot += 1 + } + if (accumulator) { // ACCUMULATOR SWITCHED ON + activateAccumulator() + } + } + + + function onUpdateUi() { + // THIS FUNCTION IS TRIGGERED BY updateInterval + setNetData() + + setUiVisible('') + } + + + function setNetData() { + // THIS FUNCTION IS TRIGGERED BY updateInterval + + if (numCheckedNets == 0) { // NO NETWORKS ENABLED|CHECKED [undefined fix] + downSpeed = 0 + upSpeed = 0 + + } else { // ONE OR MORE NETWORKS ENABLED|CHECKED + + if (accumulator !== 0) { // ACCUMULATOR IS EITHER 1 OR 2 + var values = getAccumulatorData() + downSpeed = values[0] + upSpeed = values[1] + return // EXIT FUNCTION + } + var values = multiNetAddition() // ADD VALUES FOR MULTIPLE ACTIVE NETWORKS + downSpeed = values[0] + upSpeed = values[1] + } + } + + + function multiNetAddition(){ + // IF MULTIPLE INTERFACES ARE CHECKED, DATA COLLECTED FROM EACH NEEDS TO BE ADDED TOGETHER AND DISPLAYED + + var downloaded = 0 + var uploaded = 0 + + if (speedUnits === 'bits') { // BITS + for (var i = 0; i < netDataBits.length; i++) { + downloaded += netDataBits[i].down + uploaded += netDataBits[i].up + } + } else { // BYTES + for (var i = 0; i < netDataByte.length; i++) { + downloaded += netDataByte[i].down + uploaded += netDataByte[i].up + } + } + return [ downloaded, uploaded ] + } + + + function getAccumulatorData() { + + var downloaded = 0 + var uploaded = 0 + + if (accumulator === 2) { // ACCUMULATOR ON [ ACCUMULATED ] + downloaded = netDataAccumulator.down + uploaded = netDataAccumulator.up + + } else if (accumulator === 1) { // ACCUMULATOR ON [ AVERAGE ] + downloaded = getAverage(netDataAccumulator.down) + uploaded = getAverage(netDataAccumulator.up) + } + + netDataAccumulator.down = 0 // RESET ACCUMULATOR DATA FOR NEXT COUNT + netDataAccumulator.up = 0 + accumulatorCounter = 0 // RESET ACCUMULATOR COUNTER, USED TO TRIGGER updateInterval AT THE CORRECT TIME + + return [ downloaded, uploaded ] + } + + + function activateAccumulator() { + // IF ACTIVATED, WILL TRIGGER EVERY 500 MILLISECONDS + + var values = multiNetAddition() + var countx = updateInterval / 500 // GET NUMBER OF TICKS FOR COUNTER + + if (accumulatorCounter < countx) { + netDataAccumulator.down += values[0] + netDataAccumulator.up += values[1] + } + accumulatorCounter += 1 + } + + + function getAverage(value) { + var seconds = updateInterval / 1000 + + return value * 0.5 / seconds + } + } + + Component.onCompleted: { + addSources(); + } + + Component.onDestruction: { + dbusData.unsubscribe(sensorList); + } +} diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/DbusData.qml b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/DbusData.qml new file mode 100644 index 00000000..844e53bd --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/DbusData.qml @@ -0,0 +1,4 @@ +import DbusModel 1.0 + +Dbus { +} diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/config/configGeneral.qml b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/config/configGeneral.qml new file mode 100644 index 00000000..38947023 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/config/configGeneral.qml @@ -0,0 +1,2969 @@ +/* + * Copyright 2023 LeeVD + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.0 + +Item { + property alias cfg_showSeparately: showSeparately.checked + property string cfg_speedLayout: speedLayout + property bool cfg_swapDownUp: false + property string cfg_iconType: iconType + property bool cfg_iconPosition: iconPosition // true = right | false = left + property alias cfg_showIcons: showIcons.checked + property alias cfg_showUnits: showUnits.checked + property string cfg_speedUnits: 'bits' + property alias cfg_shortUnits: shortUnits.checked + property double cfg_fontSize: fontSize + property double cfg_updateInterval: updateInterval + property string cfg_binaryDecimal: 'binary' + property double cfg_decimalPlace: decimalPlace + property int cfg_layoutPadding: layoutPadding + property int cfg_accumulator: accumulator + property alias cfg_hideInactive: hideInactive.checked + property bool cfg_hideZone: hideZone + property alias cfg_showSeconds: showSeconds.checked + property string cfg_secondsPrefix: '/s' + property alias cfg_decimalFilter0: decimalFilter0.checked + property alias cfg_decimalFilter1: decimalFilter1.checked + property alias cfg_decimalFilter2: decimalFilter2.checked + property alias cfg_decimalFilter3: decimalFilter3.checked + property int cfg_roundedNumber: roundedNumber + property double cfg_iconSize: iconSize + property double cfg_sufixSize: sufixSize + + property int spacerA: 8 + property int spacerB: 30 + + id: main + //________ COLUMN WIDTH ________ + TextMetrics { + id: titleTextMetrics + text: "Show 'per seconds' suffix: " + //font.pixelSize: 64 + } + //________ COLUMN WIDTH ________ + TextMetrics { + id: labelTextMetrics + text: " 10 pixel closer " + //font.pixelSize: 64 + } + //________ TOOLTIP ANIMATIONS ________ + NumberAnimation { + id: heightAnimation + target: null //rootRec + property: "height" + duration: 100 + onStopped: { + // target contains reference to rec | rootRec# + var buttonObject = target.children[0].children[1] // GET infoButton Object + var buttonState = buttonObject.state // GET infoButton state + if (buttonState === true) { // infoButton#.MouseArea.state + + opacityAnimation.target = target.children[2].children[0] // target infoText# + opacityAnimation.to = 1; // open infoText# tooltip + opacityAnimation.start() // start Animation + } + } + } + OpacityAnimator { + id: opacityAnimation + target: null //infoText + duration: 200 + onStopped: { + // target contains reference infoText# + var buttonObject = target.parent.parent.children[0].children[1] // GET infoButton Object + var buttonState = buttonObject.state // GET infoButton state + + if (buttonState === false) { // infoButton#.MouseArea.state + + heightAnimation.target = target.parent.parent // target rootRec# + heightAnimation.to = infoButton.height // close infoText# tooltip + heightAnimation.start() // start Animation + } + } + } + + + //________ ANIMATION CALLER ________ + function toggleTooltip(rec) { // SEND ENTIRE ROW OBJECT TO ANIMATION FUNCTION + + var rec_infoButton = rec.children[0] // GET rec infoButton MouseArea Object (MEMORY ADDRESS IDENTIFIER) + var rec_infoText = rec.children[2].children[0] // GET rec infoText Object (MEMORY ADDRESS IDENTIFIER) + var rec_state = rec_infoButton.children[1].state // GET rec infoButton MouseArea state toggle + + if (rec_state === true) { // OPEN NEW TOOLTIP + + var heightAnimationTo = rec_infoButton.height + rec_infoText.contentHeight + (rec_infoText.padding * 2) + + heightAnimation.target = rec // target rootRec or rec in this instance + heightAnimation.to = heightAnimationTo + heightAnimation.start() + + rec_infoButton.opacity = 1.0 + rec.border.width = 0.5 + + } else { // CLOSE NEW TOOLTIP + + opacityAnimation.target = rec_infoText // TARGET infoText FROM THE rec OBJECT + opacityAnimation.to = 0 + opacityAnimation.start() + + rec_infoButton.opacity = 0.5 + rec.border.width = 0 + } + } + + + Rectangle { + + id: rootRec + width: parent.width + height: 40//infoButton.height + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + //property bool state: false + id: infoButton + icon.name: 'kt-info-widget' + implicitWidth: infoButton.height + anchors.right: parent.right + opacity: 0.5 + + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton.opacity = 1 + onExited: state ? infoButton.opacity = 1 : infoButton.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec) + } + } + } + + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA + anchors.verticalCenter: infoButton.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Layout:") + } + } + Column { + RowLayout { + id: testing + function paddingFix(caller) { + // row + if (caller == 'row'){ + cfg_layoutPadding = 0 // RESET PADDING TO DEFAULT + paddingLabel.color = "grey" // SET 'Default pixels' FONT COLOR TO GREY + paddingDOWN.enabled = false // SET BOTH BUTTONS TO DISABLED + paddingUP.enabled = false + } else { + paddingLabel.color = theme.textColor + if (paddingUP.enabled === false && paddingDOWN.enabled === false ) { // IF BOTH BUTTONS DISABLED, CAME FROM 'row' LAYOUT + paddingUP.enabled = true + paddingDOWN.enabled = true + } + } + } + RadioButton { + id: speedLayout_rb0 + Layout.rightMargin: 20 // PADDING RIGHT + checked: plasmoid.configuration.speedLayout === 'auto' + text: i18n("Automatic") + onReleased: {cfg_speedLayout = 'auto' + testing.paddingFix('auto')} + } + RadioButton { + id: speedLayout_rb1 + Layout.rightMargin: 20 // PADDING RIGHT + checked: plasmoid.configuration.speedLayout === 'column' + text: i18n("Vertical") + onReleased: {cfg_speedLayout = 'column' // ONE ABOVE OTHER + testing.paddingFix('column')} + } + RadioButton { + id: speedLayout_rb2 + checked: plasmoid.configuration.speedLayout === 'row' + text: i18n("Horizontal") + onReleased: {cfg_speedLayout = 'row' // SIDE BY SIDE + testing.paddingFix('row')} + } + + } + } + } + } + Grid { + + property alias nText: infoText + // NEW TOOLTIP INFORMATION + anchors.top: gA.bottom + Text { + id: infoText + opacity: 0 + padding: 10 + width: rootRec.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + text: "" + + "" + + "" + + "" + + "" + + "" + + "
" + i18n("Automatic") + ": " + i18n("Should automatically adjust to size available in taskbar.") +"
" + i18n("Vertical") + ": " + i18n("Upload and Download will be stacked on top of each other:") + "
" + i18n("Horizontal") + ": " + i18n("Upload and Download will be aligned side by side:") + "
" + } + } + } + //############################################################################################### + // Rectangle { + // id: spacer + // height: 20 + // width: 20 + // anchors.top: rootRec.bottom + // color: "transparent" + // } + //############################################################################################### + Rectangle { + + id: rootRec2 + width: parent.width + height: infoButton2.height + anchors.top: rootRec.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton2 + icon.name: 'kt-info-widget' + implicitWidth: infoButton2.height + anchors.right: parent.right + opacity: 0.5 + + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton2.opacity = 1 + onExited: state ? infoButton2.opacity = 1 : infoButton2.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec2) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA2 + anchors.verticalCenter: infoButton2.verticalCenter + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Display order:") + } + } + Column { + RowLayout { + RadioButton { + Layout.rightMargin: 20 // PADDING RIGHT + checked: plasmoid.configuration.swapDownUp === true + text: i18n("Upload speed first") + onReleased: cfg_swapDownUp = true + } + RadioButton { + checked: plasmoid.configuration.swapDownUp === false + text: i18n("Download speed first") + onReleased: cfg_swapDownUp = false + } + } + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA2.bottom + Text { + id: infoText2 + opacity: 0 + padding: 10 + width: rootRec2.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + text: "" + + "" + + "" + + "" + + "
" + i18n("Upload speed first") + ": " + i18n("Upload data on the top in Vertical layout or left in Horizontal.") + "
" + i18n("Download speed first") + ": " + i18n("Download data on the top in Vertical layout or left in Horizontal.") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec3 + width: parent.width + height: infoButton3.height + anchors.top: rootRec2.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton3 + icon.name: 'kt-info-widget' + implicitWidth: infoButton3.height + anchors.right: parent.right + opacity: 0.5 + + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton3.opacity = 1 + onExited: state ? infoButton3.opacity = 1 : infoButton3.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec3) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA3 + anchors.verticalCenter: infoButton3.verticalCenter + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Show speeds separately:") + } + } + Column { + CheckBox { + id: showSeparately + checked: true + } + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA3.bottom + Text { + id: infoText3 + opacity: 0 + padding: 10 + width: rootRec3.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + text: "" + + "" + + "" + + "" + + "
" + i18n("Checked") + ": " + i18n("The Upload and Download data will be displayed separately either stacked or side by side.") + "
" + i18n("Unchecked") + ": " + i18n("The Upload and Download data will be combined both in data calculation and display. Only one row of data will be shown combining both data measurements with a matching icon.") + "
" + } + } + } + + //####################################################################################################### + Rectangle { + id: rootRec5 + width: parent.width + height: infoButton5.height + anchors.top: rootRec3.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton5 + icon.name: 'kt-info-widget' + implicitWidth: infoButton5.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton5.opacity = 1 + onExited: state ? infoButton5.opacity = 1 : infoButton5.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec5) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA5 + anchors.verticalCenter: infoButton5.verticalCenter + + Row { + //spacing: 10 + Rectangle { // USED FOR LABEL ALIGNMENT - NOT SURE WHY HAVING BELOW BUTTONS CAUSED 'anchors.verticalCenter: infoButtonX.verticalCenter' NOT TO WORK WITH LABEL. + id: recAlign5 + height: infoButton5.height + width: 0 + color: "transparent" + } + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + anchors.verticalCenter: recAlign5.verticalCenter + Label { + width: titleTextMetrics.width + text: i18n("Update interval:") + } + } + Column { + //#################################################### + RowLayout { + id: intervalRow + + property var buttonPressed + + function setInterval(){ + + var s + if (buttonPressed.text === "▲") { + intervalUP.enabled == true + cfg_updateInterval += 500 + s = 5000 + + if (cfg_updateInterval === s) { + intervalUP.enabled = false + intervalButtonTimer.stop() + } else { + intervalDOWN.enabled = true + } + } + if (buttonPressed.text === "▼") { + intervalDOWN.enabled == true + cfg_updateInterval -= 500 + s = 500 + + if (cfg_updateInterval === s) { + intervalDOWN.enabled = false + intervalButtonTimer.stop() + + } else { + intervalUP.enabled = true + } + } + } + Rectangle { + width: labelTextMetrics.width + height: intervalLabel.height + color: "transparent" + Label { + id: intervalLabel + text: { + if (cfg_updateInterval===1000) return i18n("%1 second", (cfg_updateInterval / 1000)) + else return i18n("%1 seconds", (cfg_updateInterval / 1000)) + } + } + } + Rectangle { + width: (intervalUP.x - intervalDOWN.x) + (intervalDOWN.width + 2) + height: intervalDOWN.height + 2 + color: "transparent" + border.color: "dark grey" + border.width: 0.5 + radius: 4 + RowLayout { + //id: buttonB + Button { + id: intervalDOWN + text: "▼" + implicitWidth: intervalDOWN.height + Layout.margins: 1 //buttonMargin + enabled: cfg_updateInterval != 500 + onPressAndHold: { + intervalRow.buttonPressed = intervalDOWN + intervalButtonTimer.start() + } + onReleased: { + intervalRow.buttonPressed = intervalDOWN + intervalRow.setInterval() + intervalButtonTimer.stop() + } + } + Button { + id: intervalUP + text: "▲" + implicitWidth: intervalUP.height + Layout.margins: 1 //buttonMargin + enabled: cfg_updateInterval != 5000 + onPressAndHold: { + intervalRow.buttonPressed = intervalUP + intervalButtonTimer.start() + } + onReleased: { + intervalRow.buttonPressed = intervalUP + intervalRow.setInterval() + intervalButtonTimer.stop() + } + } + Timer { + id: intervalButtonTimer + interval: 200 // repeat every 200 milliseconds + running: false + repeat: true + onTriggered: intervalRow.setInterval() + } + } + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA5.bottom + Text { + id: infoText5 + opacity: 0 + padding: 10 + width: rootRec4.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + text: "" + + "" + + "" + + "" + + "" + + "
" + i18n("Summary") + ": " + i18n("Controls the time interval new network data is displayed in the widget.") + "
" + i18n("Adjustments are in 0.5 second increments.") + "
: " + i18n("Increase the time interval, maximum 5 seconds.") + "
: " + i18n("Decrease the time interval, minimum 0.5 seconds.") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec6 + width: parent.width + height: infoButton6.height + anchors.top: rootRec5.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton6 + icon.name: 'kt-info-widget' + implicitWidth: infoButton6.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton6.opacity = 1 + onExited: state ? infoButton6.opacity = 1 : infoButton6.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec6) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA6 + anchors.verticalCenter: infoButton6.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Interval data relay:") + } + } + Column { + //#################################################### + RowLayout { + id: accumRow + function setEnabled() { + if (cfg_updateInterval > 500) { + return true + } else { + rbAccum.checked = true + cfg_accumulator = 0 + return false + } + } + RadioButton { + id: rbAccum + Layout.rightMargin: 20 // PADDING RIGHT + enabled: accumRow.setEnabled() + checked: plasmoid.configuration.accumulator === 0 + text: i18n("Current") + onReleased: cfg_accumulator = 0 + } + RadioButton { + Layout.rightMargin: 20 // PADDING RIGHT + checked: plasmoid.configuration.accumulator === 1 + enabled: accumRow.setEnabled() + text: i18n("Average") + onReleased: cfg_accumulator = 1 + } + RadioButton { + checked: plasmoid.configuration.accumulator === 2 + enabled: accumRow.setEnabled() + text: i18n("Accumulated") + onReleased: cfg_accumulator = 2 + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA6.bottom + Text { + id: infoText6 + opacity: 0 + padding: 10 + width: rootRec6.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "
" + i18n("This option becomes usable when 'Update interval' is above 0.5 seconds.") + "

" + + "" + + "" + + "" + + "" + + "
" + i18n("Current") + ": " + + i18n("Shows the amount of used network speed at the interval set in 'Update interval'. \ +For example, if 'Update interval' is 4 seconds, at every 4th second the display will only show the amount of speed traversing at that point (statistical value for the past 0.5 seconds, this is the minimum resolution of the data source) in time. \ +The display will not refresh for the following 4 seconds.") + + "
" + i18n("Average") + ": " + + i18n("The mathematically correct way to calculate the network speed over time. \ +This setting will return the network speed averaged over the period specified in 'Update interval'. \ +Using the per second prefix ('/s' or 'ps') is correct with this option.") + + "
" + i18n("Accumulated") + ": " + + i18n("Returns the accumulated network traffic over the specified time period. \ +For example, if 'Update interval' is set to 4 seconds, at every 4th second you will be presented with the sum total of network traffic over the time period selected. \ +Using the per second prefix ('/s' or 'ps') with this option is not technically correct but the choice is yours.") + + "
" + } + } + } + + //####################################################################################################### + Rectangle { + id: rootRec7 + width: parent.width + height: infoButton7.height + anchors.top: rootRec6.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton7 + icon.name: 'kt-info-widget' + implicitWidth: infoButton7.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton7.opacity = 1 + onExited: state ? infoButton7.opacity = 1 : infoButton7.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec7) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA7 + anchors.verticalCenter: infoButton7.verticalCenter + + Row { + id: rr + //spacing: 10 + Rectangle { // USED FOR LABEL ALIGNMENT - NOT SURE WHY HAVING BELOW BUTTONS CAUSED 'anchors.verticalCenter: infoButtonX.verticalCenter' NOT TO WORK WITH LABEL. + id: recAlign7 + height: infoButton7.height + width: 0 + color: "transparent" + } + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + anchors.verticalCenter: recAlign7.verticalCenter + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Layout Padding:") + } + } + Column { + //#################################################### + RowLayout { + id: paddingRow + + property var buttonPressed + + function setPadding() { + + var s + if (buttonPressed.text === "▲") { + paddingUP.enabled == true + cfg_layoutPadding -= 1 + s = -20 + + if (cfg_layoutPadding === s) { + paddingUP.enabled = false + paddingButtonTimer.stop() + } else { + paddingDOWN.enabled = true + } + } + if (buttonPressed.text === "▼") { + paddingDOWN.enabled == true + cfg_layoutPadding += 1 + s = 20 + + if (cfg_layoutPadding === s) { + paddingDOWN.enabled = false + paddingButtonTimer.stop() + } else { + paddingUP.enabled = true + } + } + } + function paddingText() { // MATH -i * -1 = +i + if (cfg_layoutPadding === 0) { + return i18n("Default pixels") + // NEGATIVE NUMBER = MOVE LAYOUT CLOSER + } else if (Math.sign(cfg_layoutPadding) === -1) { //Math.sign returns '-1' if number is a negative + if (cfg_layoutPadding === -1) return i18n("%1 pixel closer", (cfg_layoutPadding * -1)) + return i18n("%1 pixels closer", (cfg_layoutPadding * -1)) + // POSITIVE NUMBER = MOVE LAYOUT APART + } else { + if (cfg_layoutPadding === 1) return i18n("%1 pixel apart", cfg_layoutPadding) + return i18n("%1 pixels apart", cfg_layoutPadding) + } + } + Rectangle { + width: labelTextMetrics.width + height: paddingLabel.height + color: "transparent" + Label { + id: paddingLabel + text: paddingRow.paddingText() + } + } + Rectangle { + width: (paddingUP.x - paddingDOWN.x) + (paddingDOWN.width + 2) + height: paddingDOWN.height + 2 + color: "transparent" + border.color: "dark grey" + border.width: 0.5 + radius: 4 + RowLayout { + id:paddingRow2 + Button { + id: paddingDOWN + text: "▼" + implicitWidth: paddingDOWN.height + Layout.margins: 1 //buttonMargin + enabled: cfg_layoutPadding != 20 + onPressAndHold: { + paddingRow.buttonPressed = paddingDOWN + paddingButtonTimer.start() + } + onReleased: { + paddingRow.buttonPressed = paddingDOWN + paddingRow.setPadding() + paddingButtonTimer.stop() + } + } + Button { + id: paddingUP + text: "▲" + implicitWidth: paddingUP.height + Layout.margins: 1 //buttonMargin + enabled: cfg_layoutPadding != -20 + onPressAndHold: { + paddingRow.buttonPressed = paddingUP + paddingButtonTimer.start() + } + onReleased: { + paddingRow.buttonPressed = paddingUP + paddingRow.setPadding() + paddingButtonTimer.stop() + } + } + Timer { + id: paddingButtonTimer + interval: 200 // repeat every 200 milliseconds + running: false + repeat: true + onTriggered: paddingRow.setPadding() + } + } + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA7.bottom + Text { + id: infoText7 + opacity: 0 + padding: 10 + width: rootRec7.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "" + + "" + + "
: " + i18n("Move the upload and download data rows closer together, maximum 20 pixels closer.") + "
: " + i18n("Increase the distance between upload and download data rows, maximum 20 pixels apart.") + "
" + + i18n("* Function disabled in 'Horizontal' layout mode.") + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec8 + width: parent.width + height: infoButton8.height + anchors.top: rootRec7.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton8 + icon.name: 'kt-info-widget' + implicitWidth: infoButton8.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton8.opacity = 1 + onExited: state ? infoButton8.opacity = 1 : infoButton8.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec8) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA8 + anchors.verticalCenter: infoButton8.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Hide when inactive:") + } + } + Column { + //#################################################### + CheckBox { + id: hideInactive + checked: !cfg_hideZone + onCheckedChanged: { + cfg_hideZone = !hideInactive.checked + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA8.bottom + Text { + id: infoText8 + opacity: 0 + padding: 10 + width: rootRec8.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "" + + "
" + i18n("Checked") + ": " + i18n("Hides the display when '0' traffic is reported. Displays will become visible again when traffic starts to flow.") + "
" + i18n("Unchecked") + ": " + i18n("Shows the display even when no traffic is traversing the network interfaces.") + "
" + } + } + } + //####################################################################################################### + MenuSeparator { + id: separator1 + padding: 0 + topPadding: 20 + bottomPadding: 20 + contentItem: Rectangle { + implicitWidth: parent.parent.width + implicitHeight: 1 + color: "light grey" + } + anchors.top: rootRec8.bottom + } + //####################################################################################################### + // -- SIZE -- + + Rectangle { + id: rootRec4 + width: parent.width + height: infoButton4.height + 8 + anchors.top: separator1.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton4 + icon.name: 'kt-info-widget' + implicitWidth: infoButton4.height + anchors.right: parent.right + opacity: 0.5 + + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton4.opacity = 1 + onExited: state ? infoButton4.opacity = 1 : infoButton4.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec4) + } + } + } + Grid { // TITLE | CHOICE BUTTONS GO HERE + id: gA4 + anchors.verticalCenter: infoButton4.verticalCenter + + Row { + //spacing: 10 + Rectangle { // USED FOR LABEL ALIGNMENT - NOT SURE WHY HAVING BELOW BUTTONS CAUSED 'anchors.verticalCenter: recAlign4.verticalCenter' NOT TO WORK WITH LABEL. + id: recAlign4 + height: infoButton4.height + width: 0 + color: "transparent" + } + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + anchors.verticalCenter: recAlign4.verticalCenter + Label { + width: titleTextMetrics.width + text: i18n("Numbers font size:") + } + } + Column { + //#################################################### + RowLayout { + id: fontSizeRow + + property var buttonPressed; + property var t: 2; + property var f: 0.5; + + function disableButton() { + if (cfg_fontSize === f) { + fontSizeDOWN.enabled = false; + } else { + fontSizeDOWN.enabled = true; + } + if (cfg_fontSize === t) { + fontSizeUP.enabled = false; + } else { + fontSizeUP.enabled = true; + } + } + function setFontSize() { + if (buttonPressed.text === "▲") { // BUTTONS + cfg_fontSize += 0.01; + } else if (buttonPressed.text === "▼") { + cfg_fontSize -= 0.01; + } + fontSizeSlider.value = cfg_fontSize + disableButton() + } + + function setFontSizeSlider() { // SLIDER + var sliderVal + sliderVal = buttonPressed.value.toFixed(2) + if (sliderVal !== cfg_fontSize) { + cfg_fontSize = sliderVal + } + disableButton() + } + + Rectangle { + width: labelTextMetrics.width + height: textLabel.height + color: "transparent" + Label { + id: textLabel + text: (cfg_fontSize * 100).toFixed(0) + " %" + } + } + + Rectangle { + width: (fontSizeUP.x - fontSizeDOWN.x) + (fontSizeDOWN.width + 2) + height: fontSizeDOWN.height + 2 + color: "transparent" + border.color: "dark grey" + border.width: 0.5 + radius: 4 + RowLayout { + Button { + id: fontSizeDOWN + text: "▼" + implicitWidth: fontSizeDOWN.height + Layout.margins: 1 //buttonMargin + enabled: cfg_fontSize != fontSizeRow.f + onReleased: { + fontSizeRow.buttonPressed = fontSizeDOWN + fontSizeRow.setFontSize() + } + } + Button { + id: fontSizeUP + text: "▲" + implicitWidth: fontSizeUP.height + Layout.margins: 1 //buttonMargin + enabled: cfg_fontSize != fontSizeRow.t + onReleased: { + fontSizeRow.buttonPressed = fontSizeUP + fontSizeRow.setFontSize() + } + } + Slider { + id: fontSizeSlider + implicitWidth: 140 + from: fontSizeRow.f + value: cfg_fontSize + to: fontSizeRow.t + onValueChanged: { + fontSizeRow.buttonPressed = fontSizeSlider + fontSizeRow.setFontSizeSlider() + } + } + } + } + } + //################################################## + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA4.bottom + Text { + id: infoText4 + opacity: 0 + padding: 10 + width: rootRec4.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + text: "" + + "" + + "" + + "
: " + i18n("Increase font size of the numbers in the display, maximum 200%.") + "
: " + i18n("Decrease font size of the numbers in the display, minimum 50%") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec45 + width: parent.width + height: infoButton45.height + 8 + anchors.top: rootRec4.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton45 + icon.name: 'kt-info-widget' + implicitWidth: infoButton45.height + anchors.right: parent.right + opacity: 0.5 + + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton45.opacity = 1 + onExited: state ? infoButton45.opacity = 1 : infoButton45.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec45) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA45 + anchors.verticalCenter: infoButton45.verticalCenter + + Row { + //spacing: 10 + Rectangle { // USED FOR LABEL ALIGNMENT - NOT SURE WHY HAVING BELOW BUTTONS CAUSED 'anchors.verticalCenter: recAlign4.verticalCenter' NOT TO WORK WITH LABEL. + id: recAlign45 + height: infoButton45.height + width: 0 + color: "transparent" + } + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + anchors.verticalCenter: recAlign45.verticalCenter + Label { + width: titleTextMetrics.width + text: i18n("Icon size:") + } + } + Column { + //#################################################### + RowLayout { + id: iconSizeRow + + property var buttonPressed; + property var t: 2; + property var f: 0.5; + + function disableButton() { + if (cfg_iconSize === f) { + iconSizeDOWN.enabled = false; + } else { + iconSizeDOWN.enabled = true; + } + if (cfg_iconSize === t) { + iconSizeUP.enabled = false; + } else { + iconSizeUP.enabled = true; + } + } + function seticonSize() { + if (buttonPressed.text === "▲") { // BUTTONS + cfg_iconSize += 0.01; + } else if (buttonPressed.text === "▼") { + cfg_iconSize -= 0.01; + } + iconSizeSlider.value = cfg_iconSize + disableButton() + } + + function seticonSizeSlider() { // SLIDER + var sliderVal + sliderVal = buttonPressed.value.toFixed(2) + if (sliderVal !== cfg_iconSize) { + cfg_iconSize = sliderVal + } + disableButton() + } + + Rectangle { + width: labelTextMetrics.width + height: iconSizeLabel.height + color: "transparent" + Label { + id: iconSizeLabel + text: (cfg_iconSize * 100).toFixed(0) + " %" + } + } + + Rectangle { + width: (iconSizeUP.x - iconSizeDOWN.x) + (iconSizeDOWN.width + 2) + height: iconSizeDOWN.height + 2 + color: "transparent" + border.color: "dark grey" + border.width: 0.5 + radius: 4 + RowLayout { + Button { + id: iconSizeDOWN + text: "▼" + implicitWidth: iconSizeDOWN.height + Layout.margins: 1 //buttonMargin + enabled: cfg_iconSize != iconSizeRow.f + onReleased: { + iconSizeRow.buttonPressed = iconSizeDOWN + iconSizeRow.seticonSize() + } + } + Button { + id: iconSizeUP + text: "▲" + implicitWidth: iconSizeUP.height + Layout.margins: 1 //buttonMargin + enabled: cfg_iconSize != iconSizeRow.t + onReleased: { + iconSizeRow.buttonPressed = iconSizeUP + iconSizeRow.seticonSize() + } + } + Slider { + id: iconSizeSlider + implicitWidth: 140 + from: iconSizeRow.f + value: cfg_iconSize + to: iconSizeRow.t + onValueChanged: { + iconSizeRow.buttonPressed = iconSizeSlider + iconSizeRow.seticonSizeSlider() + } + } + } + } + } + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA45.bottom + Text { + id: infoText45 + opacity: 0 + padding: 10 + width: rootRec45.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + text: "" + + "" + + "" + + "
: " + i18n("Increase speed icon size, maximum 200%.") + "
: " + i18n("Decrease speed icon size, minimum 50%") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec46 + width: parent.width + height: infoButton46.height + 8 + anchors.top: rootRec45.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton46 + icon.name: 'kt-info-widget' + implicitWidth: infoButton46.height + anchors.right: parent.right + opacity: 0.5 + + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton46.opacity = 1 + onExited: state ? infoButton46.opacity = 1 : infoButton46.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec46) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA46 + anchors.verticalCenter: infoButton46.verticalCenter + + Row { + //spacing: 10 + Rectangle { // USED FOR LABEL ALIGNMENT - NOT SURE WHY HAVING BELOW BUTTONS CAUSED 'anchors.verticalCenter: recAlign4.verticalCenter' NOT TO WORK WITH LABEL. + id: recAlign46 + height: infoButton46.height + width: 0 + color: "transparent" + } + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + anchors.verticalCenter: recAlign46.verticalCenter + Label { + width: titleTextMetrics.width + text: i18n("Prefix/Suffix size:") + } + } + Column { + //#################################################### + RowLayout { + id: sufixSizeRow + + property var buttonPressed; + property var t: 2; + property var f: 0.5; + + function disableButton() { + if (cfg_sufixSize === f) { + sufixSizeDOWN.enabled = false; + } else { + sufixSizeDOWN.enabled = true; + } + if (cfg_sufixSize === t) { + sufixSizeUP.enabled = false; + } else { + sufixSizeUP.enabled = true; + } + } + function setsufixSize() { + if (buttonPressed.text === "▲") { // BUTTONS + cfg_sufixSize += 0.01; + } else if (buttonPressed.text === "▼") { + cfg_sufixSize -= 0.01; + } + sufixSizeSlider.value = cfg_sufixSize + disableButton() + } + + function setsufixSizeSlider() { // SLIDER + var sliderVal + sliderVal = buttonPressed.value.toFixed(2) + if (sliderVal !== cfg_sufixSize) { + cfg_sufixSize = sliderVal + } + disableButton() + } + + Rectangle { + width: labelTextMetrics.width + height: sufixSizeLabel.height + color: "transparent" + Label { + id: sufixSizeLabel + text: (cfg_sufixSize * 100).toFixed(0) + " %" + } + } + + Rectangle { + width: (sufixSizeUP.x - sufixSizeDOWN.x) + (sufixSizeDOWN.width + 2) + height: sufixSizeDOWN.height + 2 + color: "transparent" + border.color: "dark grey" + border.width: 0.5 + radius: 4 + RowLayout { + Button { + id: sufixSizeDOWN + text: "▼" + implicitWidth: sufixSizeDOWN.height + Layout.margins: 1 //buttonMargin + enabled: cfg_sufixSize != sufixSizeRow.f + onReleased: { + sufixSizeRow.buttonPressed = sufixSizeDOWN + sufixSizeRow.setsufixSize() + } + } + Button { + id: sufixSizeUP + text: "▲" + implicitWidth: sufixSizeUP.height + Layout.margins: 1 //buttonMargin + enabled: cfg_sufixSize != sufixSizeRow.t + onReleased: { + sufixSizeRow.buttonPressed = sufixSizeUP + sufixSizeRow.setsufixSize() + } + } + Slider { + id: sufixSizeSlider + implicitWidth: 140 + from: sufixSizeRow.f + value: cfg_sufixSize + to: sufixSizeRow.t + onValueChanged: { + sufixSizeRow.buttonPressed = sufixSizeSlider + sufixSizeRow.setsufixSizeSlider() + } + } + } + } + } + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA46.bottom + Text { + id: infoText46 + opacity: 0 + padding: 10 + width: rootRec46.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + text: "" + + "" + + "" + + "
: " + i18n("Increase speed prefix/suffix font size, maximum 200%.") + "
: " + i18n("Decrease speed prefix/suffix font size, minimum 50%") + "
" + } + } + } + + //####################################################################################################### + MenuSeparator { + id: separator11 + padding: 0 + topPadding: 20 + bottomPadding: 20 + contentItem: Rectangle { + implicitWidth: parent.parent.width + implicitHeight: 1 + color: "light grey" + } + anchors.top: rootRec46.bottom + } + //####################################################################################################### + Rectangle { + id: rootRec9 + width: parent.width + height: infoButton9.height + //anchors.top: rootRec8.bottom + anchors.top: separator11.bottom + //anchors.topMargin: spacerB + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton9 + icon.name: 'kt-info-widget' + implicitWidth: infoButton9.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton9.opacity = 1 + onExited: state ? infoButton9.opacity = 1 : infoButton9.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec9) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA9 + anchors.verticalCenter: infoButton9.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Show speed units:") + } + } + Column { + //#################################################### + CheckBox { + id: showUnits + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA9.bottom + Text { + id: infoText9 + opacity: 0 + padding: 10 + width: rootRec9.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "" + + "
" + i18n("Checked") + ": " + i18n("Hides the trailing suffix for the bits (b, kib, Mib Gib) or bytes (B, KB, MB, GB).") + "
" + i18n("Unchecked") + ": " + i18n("Shows the suffixes for bits or bytes.") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec10 + width: parent.width + height: infoButton10.height + anchors.top: rootRec9.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton10 + icon.name: 'kt-info-widget' + implicitWidth: infoButton10.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton10.opacity = 1 + onExited: state ? infoButton10.opacity = 1 : infoButton10.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec10) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA10 + anchors.verticalCenter: infoButton10.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Speed units:") + } + } + Column { + //#################################################### + RowLayout { + RadioButton { + Layout.rightMargin: 20 // PADDING RIGHT + checked: plasmoid.configuration.speedUnits === 'bits' + text: i18n("Bits") + onReleased: cfg_speedUnits = 'bits' + } + RadioButton { + checked: plasmoid.configuration.speedUnits === 'bytes' + text: i18n("Bytes") + onReleased: cfg_speedUnits = 'bytes' + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA10.bottom + Text { + id: infoText10 + opacity: 0 + padding: 10 + width: rootRec10.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "" + + "
" + i18n("Bits") + ": " + i18n("Displays data throughput based on bit units. The default option, bits are normally used to measure a data transfer.") + "
" + i18n("Bytes") + ": " + i18n("Displays data throughput based on byte units. Second option as bytes can be used to measure an amount of data, normally storage data.") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec11 + width: parent.width + height: infoButton11.height + anchors.top: rootRec10.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton11 + icon.name: 'kt-info-widget' + implicitWidth: infoButton11.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton11.opacity = 1 + onExited: state ? infoButton11.opacity = 1 : infoButton11.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec11) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA11 + anchors.verticalCenter: infoButton11.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Shorten speed units:") + } + } + Column { + //#################################################### + CheckBox { + id: shortUnits + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA11.bottom + Text { + id: infoText11 + opacity: 0 + padding: 10 + width: rootRec11.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "" + + "
" + i18n("Checked") + ": " + i18n("Will only use a single character to represent the bits or bytes suffix, for example kb = k, Mb = M etc. Per second units will also not be displayed.") + "
" + i18n("Unchecked") + ": " + i18n("The complete suffix will be displayed including the per second unit.") + "
" + } + } + } + //####################################################################################################### + MenuSeparator { + id: separator2 + padding: 0 + topPadding: 20 + bottomPadding: 20 + contentItem: Rectangle { + implicitWidth: parent.parent.width + implicitHeight: 1 + color: "light grey" + } + anchors.top: rootRec11.bottom + } + //####################################################################################################### + Rectangle { + id: rootRec12 + width: parent.width + height: infoButton12.height + anchors.top: separator2.bottom + //anchors.top: rootRec11.bottom + //anchors.topMargin: spacerB + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton12 + icon.name: 'kt-info-widget' + implicitWidth: infoButton12.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton12.opacity = 1 + onExited: state ? infoButton12.opacity = 1 : infoButton12.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec12) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA12 + anchors.verticalCenter: infoButton12.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Show 'per seconds' suffix:") + } + } + Column { + //#################################################### + CheckBox { + id: showSeconds + } + // DISABLE THE SECONDS PREFIX OPTIONS IF CHECKBOX NOT CHECKED + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA12.bottom + Text { + id: infoText12 + opacity: 0 + padding: 10 + width: rootRec12.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "" + + "" + + "" + + "
" + i18n("Checked") + ": " + i18n("Appends the per second suffix to the trailing measurement unit.") + "
" + i18n("* This option is technically correct when used in conjunction with 'Interval data relay' choice other than 'Accumulated'.") + "
" + i18n("Unchecked") + ": " + i18n("Removes the per second suffix ('/s' or 'ps') from the trailing bit or byte measurement unit.") + "
" + i18n("* This option is technically correct when used in conjunction with 'Interval data relay' choice of 'Accumulated'.") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec13 + width: parent.width + height: infoButton13.height + anchors.top: rootRec12.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton13 + icon.name: 'kt-info-widget' + implicitWidth: infoButton13.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton13.opacity = 1 + onExited: state ? infoButton13.opacity = 1 : infoButton13.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec13) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA13 + anchors.verticalCenter: infoButton13.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Per Seconds prefix:") + } + } + Column { + //#################################################### + RowLayout { + RadioButton { + Layout.rightMargin: 20 // PADDING RIGHT + enabled: cfg_showSeconds + checked: plasmoid.configuration.secondsPrefix === '/s' + text: i18n("/s") + onReleased: cfg_secondsPrefix = '/s' + } + RadioButton { + enabled: cfg_showSeconds + checked: plasmoid.configuration.secondsPrefix === 'ps' + text: i18n("ps") + onReleased: cfg_secondsPrefix = 'ps' + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA13.bottom + Text { + id: infoText13 + opacity: 0 + padding: 10 + width: rootRec13.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "" + + "
" + i18n("Choose between a per second unit of '/s' or 'ps'.") + "
" + i18n("Example, measuring in bits: Kib/s or Kibps, measuring in bytes: KB/s or KBps.") + "
" + } + } + } + //####################################################################################################### + MenuSeparator { + id: separator3 + padding: 0 + topPadding: 20 + bottomPadding: 20 + contentItem: Rectangle { + implicitWidth: parent.parent.width + implicitHeight: 1 + color: "light grey" + } + anchors.top: rootRec13.bottom + } + //####################################################################################################### + Rectangle { + id: rootRec14 + width: parent.width + height: infoButton14.height + anchors.top: separator3.bottom + //anchors.topMargin: spacerB + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton14 + icon.name: 'kt-info-widget' + implicitWidth: infoButton14.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton14.opacity = 1 + onExited: state ? infoButton14.opacity = 1 : infoButton14.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec14) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA14 + anchors.verticalCenter: infoButton14.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Show speed icons:") + } + } + Column { + //#################################################### + CheckBox { + id: showIcons + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA14.bottom + Text { + id: infoText14 + opacity: 0 + padding: 10 + width: rootRec14.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "" + + "
" + i18n("Checked") + ": " + i18n("Displays the Download or Upload icons in the widget.") + "
" + i18n("Unchecked") + ": " + i18n("Hides the Download or Upload icons in the widget.") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec15 + width: parent.width + height: infoButton15.height + anchors.top: rootRec14.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton15 + icon.name: 'kt-info-widget' + implicitWidth: infoButton15.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton15.opacity = 1 + onExited: state ? infoButton15.opacity = 1 : infoButton15.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec15) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA15 + anchors.verticalCenter: infoButton15.verticalCenter + + Row { + //spacing: 10 + Rectangle { // USED FOR LABEL ALIGNMENT - NOT SURE WHY HAVING BELOW BUTTONS CAUSED 'anchors.verticalCenter: infoButtonX.verticalCenter' NOT TO WORK WITH LABEL. + id: recAlign15 + height: infoButton15.height + width: 0 + color: "transparent" + } + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + anchors.verticalCenter: recAlign15.verticalCenter + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Icon Style:") + } + } + Column { + //#################################################### + ComboBox { + // ICONS FROM HACK FONT AND NATO SAN + id: iconType + textRole: 'text' + model: [ + { text: 'ᐁ ᐃ' }, + { text: '▽ △' }, + { text: '▼ ▲' }, + { text: '⮟ ⮝' }, + { text: '⩔ ⩓' }, + { text: '🢗 🢕' }, + { text: '⋁ ⋀' }, + { text: '◥ ◢' }, + { text: 'D: U:' }, + { text: '🠇 🠅' }, + { text: '🠋 🠉' }, + { text: '🡇 🡅' }, + { text: '🡫 🡩' }, + { text: '⮋ ⮉' }, + { text: '⇩ ⇧' }, + { text: '⮯ ⮭' }, + { text: '⥥ ⥣' } + ] + onCurrentIndexChanged: cfg_iconType = model[currentIndex]['text'] + Component.onCompleted: { + for (var i = 0; i < model.length; i++) { + if (model[i]['text'] === plasmoid.configuration.iconType) { + iconType.currentIndex = i + } + } + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA15.bottom + Text { + id: infoText15 + opacity: 0 + padding: 10 + width: rootRec15.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "
" + i18n("Choose the Upload and Download icon style to be displayed in the widget.") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec155 + width: parent.width + height: infoButton155.height + anchors.top: rootRec15.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton155 + icon.name: 'kt-info-widget' + implicitWidth: infoButton155.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton155.opacity = 1 + onExited: state ? infoButton155.opacity = 1 : infoButton155.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec155) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA155 + anchors.verticalCenter: infoButton155.verticalCenter + + Row { + //spacing: 10 + Rectangle { // USED FOR LABEL ALIGNMENT - NOT SURE WHY HAVING BELOW BUTTONS CAUSED 'anchors.verticalCenter: infoButtonX.verticalCenter' NOT TO WORK WITH LABEL. + id: recAlign155 + height: infoButton155.height + width: 0 + color: "transparent" + } + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + anchors.verticalCenter: recAlign155.verticalCenter + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Custom Icon Style:") + } + } + Column { + //#################################################### + Row { + id: custIconRow + function getCustIcons() { + cfg_iconType = custIconDown.text + " " + custIconUp.text + } + CheckBox { + id: custIcon + onCheckedChanged: { + custIconDown.enabled = custIcon.checked + custIconUp.enabled = custIcon.checked + iconType.enabled = !iconType.enabled // Disable Icon ComboBox + } + } + TextField { + id: custIconDown + placeholderText: "Receive" + enabled: custIcon.checked + width: 100 + onTextChanged: { + custIconRow.getCustIcons() + if (text.length > 10) { + text = text.substring(0, 10); // Limit to 10 characters + } + } + } + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + TextField { + id: custIconUp + placeholderText: "Transmit" + enabled: custIcon.checked + width: 100 + onTextChanged: { + custIconRow.getCustIcons() + if (text.length > 10) { + text = text.substring(0, 10); // Limit to 10 characters + } + } + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA155.bottom + Text { + id: infoText155 + opacity: 0 + padding: 10 + width: rootRec155.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "
" + i18n("Input your custom font icons or text of choice. Each text field is limited to 10 characters.") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec16 + width: parent.width + height: infoButton16.height + anchors.top: rootRec155.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton16 + icon.name: 'kt-info-widget' + implicitWidth: infoButton16.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton16.opacity = 1 + onExited: state ? infoButton16.opacity = 1 : infoButton16.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec16) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA16 + anchors.verticalCenter: infoButton16.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Icon position:") + } + } + Column { + //#################################################### + RowLayout { + RadioButton { + Layout.rightMargin: 20 // PADDING RIGHT + checked: plasmoid.configuration.iconPosition === false + text: i18n("Left") + onReleased: cfg_iconPosition = false + } + RadioButton { + checked: plasmoid.configuration.iconPosition === true + text: i18n("Right") + onReleased: cfg_iconPosition = true + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA16.bottom + Text { + id: infoText16 + opacity: 0 + padding: 10 + width: rootRec16.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "
" + i18n("Choose to have the Upload and Download icons to the left or the right of the speed data.") + "
" + } + } + } + + //####################################################################################################### + MenuSeparator { + id: separator4 + padding: 0 + topPadding: 20 + bottomPadding: 20 + contentItem: Rectangle { + implicitWidth: parent.parent.width + implicitHeight: 1 + color: "light grey" + } + anchors.top: rootRec16.bottom + } + //####################################################################################################### + + Rectangle { + id: rootRec17 + width: parent.width + height: infoButton17.height + anchors.top: separator4.bottom + //anchors.topMargin: spacerB + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton17 + icon.name: 'kt-info-widget' + implicitWidth: infoButton17.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton17.opacity = 1 + onExited: state ? infoButton17.opacity = 1 : infoButton17.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec17) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA17 + anchors.verticalCenter: infoButton17.verticalCenter + + Row { + //spacing: 10 + Rectangle { // USED FOR LABEL ALIGNMENT - NOT SURE WHY HAVING BELOW BUTTONS CAUSED 'anchors.verticalCenter: infoButtonX.verticalCenter' NOT TO WORK WITH LABEL. + id: recAlign17 + height: infoButton17.height + width: 0 + color: "transparent" + } + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + anchors.verticalCenter: recAlign17.verticalCenter + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Numbers:") + } + } + Column { + //#################################################### + RowLayout { + RadioButton { + Layout.rightMargin: 20 // PADDING RIGHT + checked: plasmoid.configuration.binaryDecimal === 'binary' + text: i18n("Binary (1024 - 2^10)") + onReleased: cfg_binaryDecimal = 'binary' + } + RadioButton { + checked: plasmoid.configuration.binaryDecimal === 'decimal' + text: i18n("Metric (1000 - 10^3)") + onReleased: cfg_binaryDecimal = 'decimal' + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA17.bottom + Text { + id: infoText17 + opacity: 0 + padding: 10 + width: rootRec17.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + text: "" + + + "" + + "
" + + i18n("In computing, binary 1024 and decimal 1000 are two different ways of measuring units of digital information.") + + "

" + + i18n("Decimal 1000 is based on the metric system, which is based on powers of 10. In this system, each unit is 10 times larger than the previous unit. \ +For example, 1 kilometer is 1000 meters, 1 megabyte is 1000 kilobytes, and so on.") + + "

" + + "

" + + i18n("Binary 1024 is based on the binary system, which is based on powers of 2. In this system, each unit is twice as large as the previous unit. \ +For example, 1 kilobyte is 1024 bytes, 1 megabyte is 1024 kilobytes, and so on.") + + "

" + + "

" + + i18n("The reason why binary 1024 is used in computing is because computers store and process data in binary (0s and 1s), and it is convenient to use units that are based on powers of 2. \ +However, for some purposes, such as networking, decimal 1000 units are used instead.") + + "

" + + "

" + + i18n("To avoid confusion, it is important to clearly specify which unit system is being used, and to use the correct prefix (e.g., kilo, mega) for the unit. \ +The prefixes 'kibi,' 'mebi,' 'gibi,' etc. have been introduced to refer to binary 1024 units, while the prefixes 'kilo,' 'mega,' 'giga,' etc. continue to refer to decimal 1000 units.") + + "

" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec18 + width: parent.width + height: infoButton18.height + anchors.top: rootRec17.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton18 + icon.name: 'kt-info-widget' + implicitWidth: infoButton18.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton18.opacity = 1 + onExited: state ? infoButton18.opacity = 1 : infoButton18.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec18) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA18 + anchors.verticalCenter: infoButton18.verticalCenter + + Row { + //spacing: 10 + Rectangle { // USED FOR LABEL ALIGNMENT - NOT SURE WHY HAVING BELOW BUTTONS CAUSED 'anchors.verticalCenter: infoButtonX.verticalCenter' NOT TO WORK WITH LABEL. + id: recAlign18 + height: infoButton18.height + width: 0 + color: "transparent" + } + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + anchors.verticalCenter: recAlign18.verticalCenter + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Decimal Place:") + } + } + Column { + //#################################################### + RowLayout { + id: decimalPlaceRow + + property var buttonPressed + + function setDecimalPlace() { // .toFixed(x); + var s + if (buttonPressed.text === "▲") { + decimalPlaceUP.enabled == true + cfg_decimalPlace += 1 + s = 3 + + if (cfg_decimalPlace === s) { + decimalPlaceUP.enabled = false + decimalPlaceButtonTimer.stop() + } else { + decimalPlaceDOWN.enabled = true + } + } + if (buttonPressed.text === "▼") { + decimalPlaceDOWN.enabled == true + cfg_decimalPlace -= 1 + s = 0 + + if (cfg_decimalPlace === s) { + decimalPlaceDOWN.enabled = false + decimalPlaceButtonTimer.stop() + } else { + decimalPlaceUP.enabled = true + } + } + } + function decimalPlaceText() { // 0.00 + var x + if (cfg_binaryDecimal === 'binary') x = 1024; + else x = 1000; + + return Number.parseFloat(x).toFixed( cfg_decimalPlace ); + } + Rectangle { + width: labelTextMetrics.width + height: decimalPlaceLabel.height + color: "transparent" + Label { + id: decimalPlaceLabel + text: decimalPlaceRow.decimalPlaceText() + } + } + Rectangle { + width: (decimalPlaceUP.x - decimalPlaceDOWN.x) + (decimalPlaceDOWN.width + 2) + height: decimalPlaceDOWN.height + 2 + color: "transparent" + border.color: "dark grey" + border.width: 0.5 + radius: 4 + RowLayout { + //id: buttonB + Button { + id: decimalPlaceDOWN + text: "▼" + implicitWidth: decimalPlaceDOWN.height + Layout.margins: 1 //buttonMargin + enabled: cfg_decimalPlace != 0 + onPressAndHold: { + decimalPlaceRow.buttonPressed = decimalPlaceDOWN + decimalPlaceButtonTimer.start() + } + onReleased: { + decimalPlaceRow.buttonPressed = decimalPlaceDOWN + decimalPlaceRow.setDecimalPlace() + decimalPlaceButtonTimer.stop() + } + } + Button { + id: decimalPlaceUP + text: "▲" + implicitWidth: decimalPlaceUP.height + Layout.margins: 1 //buttonMargin + enabled: cfg_decimalPlace != 3 + onPressAndHold: { + decimalPlaceRow.buttonPressed = decimalPlaceUP + decimalPlaceButtonTimer.start() + } + onReleased: { + decimalPlaceRow.buttonPressed = decimalPlaceUP + decimalPlaceRow.setDecimalPlace() + decimalPlaceButtonTimer.stop() + } + } + Timer { + id: decimalPlaceButtonTimer + interval: 200 // repeat every 200 milliseconds + running: false + repeat: true + onTriggered: decimalPlaceRow.setDecimalPlace() + } + } + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA18.bottom + Text { + id: infoText18 + opacity: 0 + padding: 10 + width: rootRec18.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + + text: "" + + "" + + "
" + i18n("Choose the number of decimal fraction digits to the right of the decimal point.") + "
" + } + } + } + //####################################################################################################### + Rectangle { + id: rootRec19 + width: parent.width + height: infoButton19.height + anchors.top: rootRec18.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton19 + icon.name: 'kt-info-widget' + implicitWidth: infoButton19.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton19.opacity = 1 + onExited: state ? infoButton19.opacity = 1 : infoButton19.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec19) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA19 + anchors.verticalCenter: infoButton19.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Decimal place filter:") + } + } + Column { + Row { + id: filterRow + //################################################################# + // FILTERING IS THE DEFAULT SETTING AND ALLOWS THE RECIEVED BITS TO BE + // ROUNDED TO THE LEAST POSSIBLE NUMBERS: + // EXAMPLE: 1,553,808 BITS = 1.6 Mb (ASSUMING 1 DECIMAL PLACE HAS BEEN SELECTED) + // DISABLING THE MEGA CHECKBOXES WILL ROUND THE VALUE DOWN THE THE NEAREST KILOBIT + // EXAMPLE: 1,553,808 BITS = 1554 Kb (ASSUMING 4 DIGIT ROUNDING WAS SELECTED) + + //________ CHECKBOX WIDTH ________ + TextMetrics { + id: checkBoxMetrics + text: "Bytes " + } + CheckBox { + id: decimalFilter0 + } + Label { + id: decimalFilter0Label + text: cfg_speedUnits === 'bits' ? "bits" : "Bytes" + anchors.verticalCenter: decimalFilter0.verticalCenter + width: checkBoxMetrics.width + } + CheckBox { + id: decimalFilter1 + } + Label { + id: decimalFilter1Label + text: cfg_binaryDecimal === 'binary' ? "Kibi" : "Kilo" + anchors.verticalCenter: decimalFilter0.verticalCenter + width: checkBoxMetrics.width + } + CheckBox { + id: decimalFilter2 + } + Label { + id: decimalFilter2Label + text: cfg_binaryDecimal === 'binary' ? "Mebi" : "Mega" + anchors.verticalCenter: decimalFilter0.verticalCenter + width: checkBoxMetrics.width + } + CheckBox { + id: decimalFilter3 + } + Label { + id: decimalFilter3Label + text: cfg_binaryDecimal === 'binary' ? "Gibi" : "Giga" + anchors.verticalCenter: decimalFilter0.verticalCenter + width: checkBoxMetrics.width + } + // ################################################################ + } + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA19.bottom + Text { + id: infoText19 + opacity: 0 + padding: 10 + width: rootRec19.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + text: "" + + "" + + "" + + "" + + "
" + i18n("Provides fine-grained control over decimal places and rounding in each bit / Byte zone for the data display.") + "
" + i18n("For example, if the control is turned off (decimal places disabled), data values will be shown as whole numbers in the chosen zone as per the selected rounding method (either 3 or 4 digits rounding).") + "
" + i18n("If the control is turned on (decimal places enabled), data values will be shown with the appropriate decimal places and 3 digit rounding enabled.") + "
" + } + } + + } + //####################################################################################################### + Rectangle { + id: rootRec20 + width: parent.width + height: infoButton20.height + anchors.top: rootRec19.bottom + anchors.topMargin: spacerA + color: "transparent" //"red" + border.color: "dark grey" + border.width: 0 + radius: 4 + + ToolButton { + id: infoButton20 + icon.name: 'kt-info-widget' + implicitWidth: infoButton20.height + anchors.right: parent.right + opacity: 0.5 + MouseArea { + property bool state: false + anchors.fill: parent + hoverEnabled: true + onEntered: infoButton20.opacity = 1 + onExited: state ? infoButton20.opacity = 1 : infoButton20.opacity = 0.5 + onClicked: { + state = !state + main.toggleTooltip(rootRec20) + } + } + } + Grid { + // TITLE | CHOICE BUTTONS GO HERE + id: gA20 + anchors.verticalCenter: infoButton20.verticalCenter + + Row { + //spacing: 10 + Column { + Rectangle { + height: 10 + width: spacerA + color: "transparent" //"red" + } + } + Column { + //________ LAYOUT ________ + Label { + width: titleTextMetrics.width + text: i18n("Rounded whole number:") + } + } + Column { + //#################################################### + // THIS WILL ROUND THE FIGURE DOWN TO THE NEAREST 3 OR 4 DIGIT, IF THIS ISNT POSSIBLE + // A DECIMAL PLACE WILL BE USED TO DISPLAY THE NUMBER. + // EXAMPLE: + // [3] 408,288 BITS = 408 Kb || 1,553,808 BITS = 1.6 Mb + // [4] 408,288 BITS = 408 Kb || 1,553,808 BITS = 1554 Kb + RowLayout { + id: roundedNumberRow + function enableState() { + if (cfg_decimalFilter0 && cfg_decimalFilter1 && cfg_decimalFilter2 && cfg_decimalFilter3) { + if (rb_roundedNumber1.checked === true) { + rb_roundedNumber0.checked = true + } + return false; // DISABLE + } else { + return true; // ENABLE + } + } + RadioButton { + Layout.rightMargin: 20 // PADDING RIGHT + id: rb_roundedNumber0 + checked: true + text: i18n("3") + onReleased: cfg_roundedNumber = 3 + enabled: roundedNumberRow.enableState() + } + RadioButton { + //checked: plasmoid.configuration.binaryDecimal === 'decimal' + id: rb_roundedNumber1 + text: i18n("4") + onReleased: cfg_roundedNumber = 4 + enabled: roundedNumberRow.enableState() + } + } + // ################################################################ + } + } + } + Grid { + // NEW TOOLTIP INFORMATION + anchors.top: gA20.bottom + Text { + id: infoText20 + opacity: 0 + padding: 10 + width: rootRec20.width + color: theme.textColor + textFormat: Text.RichText + wrapMode: Text.Wrap + text: "
" + i18n("This option becomes active when 'Decimal place filter' checkbox(es) are disabled.") + "

" + + "" + + "" + + "" + + "" + + "
" + i18n("Provides finer control over how the bit / Byte data is displayed and rounded.") + "
" + i18n("By default (3), the logic will round a 4-digit bit figure to a Kilobit / Kilobyte figure. For example, 3456 bits becomes 3.38 Kb.") + "
" + i18n("Selecting 4 will only round up if the digit count exceeds 4 digits. For example, 1234567 bits will become 1206 Kb (not 1.2 Mb).") + "
" + } + } + } + //####################################################################################################### + MenuSeparator { + id: separator10 + padding: 0 + topPadding: 20 + bottomPadding: 20 + contentItem: Rectangle { + implicitWidth: Math.max(200, parent.parent.width) + implicitHeight: 1 + color: "light grey" + } + anchors.top: rootRec20.bottom + } + //####################################################################################################### +} \ No newline at end of file diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/config/configNetwork.qml b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/config/configNetwork.qml new file mode 100644 index 00000000..76e595e1 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/config/configNetwork.qml @@ -0,0 +1,108 @@ +/* + * Copyright 2023 LeeVD + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.1 +//import org.kde.plasma.core 2.0 as PlasmaCore +import DbusModel 1.1 + +Item { + + property var cfg_netSources: netSources + + //################## SERIALISATION FIX ########################### + property var net: [] + + function netSourceEncode(value) { + return JSON.stringify(value) + } + + function netSourceDecode(value) { + try { + return JSON.parse(value) + } catch (E) { + return [] + } + } + + //################################################################ + + GridLayout { + columns: 3 + columnSpacing: 15 + rowSpacing: 40 + + //________ PADDING ________ + Rectangle { + Layout.column: 0 + height: 2 + Layout.minimumWidth: 10 //(parent.width / 100) * 40 + width: 5 // (parent.width / 100) * 40 + color: "transparent" + } + QtObject { + id: data + property bool loading: false + } + + ColumnLayout { + + Repeater { + model: net.length //sources + CheckBox { + text: net[index].name + checked: net[index].checked + onCheckedChanged: { + if (!data.loading) { + net[index].checked = checked + cfg_netSources = netSourceEncode(net) + cfg_netSourcesChanged(); // SETS NEW VALUES IN MAIN + } + } + } + } + // Repeater { + // model: cfg_netSources.length //sources + + // CheckBox { + // text: cfg_netSources[index].name + // checked: cfg_netSources[index].checked + // onCheckedChanged: { + // if (!data.loading) { + // cfg_netSources[index].checked = checked + // cfg_netSourcesChanged(); // SETS NEW VALUES IN MAIN + // } + // } + // } + // } + } + + ListModel { + id: sources + } + + Dbus { + id : dbus1 + } + + Component.onCompleted: { + net = netSourceDecode(cfg_netSources) + } + } +} + diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1a.png b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1a.png new file mode 100644 index 00000000..c7de6128 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1a.png differ diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1a2.png b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1a2.png new file mode 100644 index 00000000..4901d0d9 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1a2.png differ diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1b.png b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1b.png new file mode 100644 index 00000000..b0bf925c Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1b.png differ diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1b2.png b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1b2.png new file mode 100644 index 00000000..072c2936 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/1b2.png differ diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/2a.png b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/2a.png new file mode 100644 index 00000000..12891847 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/2a.png differ diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/2b.png b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/2b.png new file mode 100644 index 00000000..7a6f2f79 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/2b.png differ diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/3a.png b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/3a.png new file mode 100644 index 00000000..931130d9 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/3a.png differ diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/4a.png b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/4a.png new file mode 100644 index 00000000..1d20dc6f Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/image/4a.png differ diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/imports/DbusModel/libqmldbusmodelplugin.so b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/imports/DbusModel/libqmldbusmodelplugin.so new file mode 100644 index 00000000..2ba97f62 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/imports/DbusModel/libqmldbusmodelplugin.so differ diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/imports/DbusModel/plugins.qmltypes b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/imports/DbusModel/plugins.qmltypes new file mode 100644 index 00000000..8eab2b8d --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/imports/DbusModel/plugins.qmltypes @@ -0,0 +1,64 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + dependencies: ["QtQuick 2.0"] + Component { + file: "dbusmodel.h" + name: "DbusModel" + prototype: "QObject" + exports: ["DbusModel/Dbus 1.0"] + exportMetaObjectRevisions: [0] + Signal { + name: "newSensorData" + Parameter { name: "keys"; type: "QStringList" } + Parameter { name: "values"; type: "QVariantList" } + } + Method { + name: "allSensors" + type: "QStringList" + Parameter { name: "filter"; type: "string" } + } + Method { + name: "maxValue" + type: "double" + Parameter { name: "key"; type: "string" } + } + Method { + name: "unitValue" + type: "double" + Parameter { name: "key"; type: "string" } + } + Method { + name: "doubleData" + type: "double" + Parameter { name: "key"; type: "string" } + } + Method { + name: "stringData" + type: "string" + Parameter { name: "key"; type: "string" } + } + Method { + name: "subscribe" + Parameter { name: "args"; type: "QStringList" } + } + Method { + name: "unsubscribe" + Parameter { name: "args"; type: "QStringList" } + } + Method { + name: "execCmd" + Parameter { name: "cmd"; type: "string" } + Parameter { name: "args"; type: "QStringList" } + } + Method { + name: "newSensorData" + Parameter { name: "arg"; type: "QDBusMessage" } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/main.qml b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/main.qml new file mode 100644 index 00000000..4a3336c5 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/main.qml @@ -0,0 +1,131 @@ +/* + * Copyright 2023 LeeVD + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// USEFUL COMMANDS: +// kquitapp5 plasmashell +// kstart5 plasmashell +// plasmoidviewer -a org.kde.nsw_dbus -l topedge -f horizontal +// kstatsviewer --details --remain 'ADDRESS' example: network/wlp2s0/totalDownload [ View DBUS messages ] + +// USEFUL PROGRAMS: +// Qt QDBusViewer +// ksystemlog +// KCharSelect + +// USEFUL LOCATIONS: +// /home/USER/.config/plasma-org.kde.plasma.desktop-appletsrc +// /home/USER/.config/plasmoidviewer-appletsrc + +import QtQuick 2.2 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore + +Item { + property bool showSeparately: plasmoid.configuration.showSeparately + property string speedLayout: plasmoid.configuration.speedLayout + property bool swapDownUp: plasmoid.configuration.swapDownUp + property string iconType: plasmoid.configuration.iconType + property bool iconPosition: plasmoid.configuration.iconPosition + property bool showIcons: plasmoid.configuration.showIcons + property bool showUnits: plasmoid.configuration.showUnits + property string speedUnits: plasmoid.configuration.speedUnits + property bool shortUnits: plasmoid.configuration.shortUnits + property double fontSizeScale: plasmoid.configuration.fontSize // 100 + property double updateInterval: plasmoid.configuration.updateInterval + property string binaryDecimal: plasmoid.configuration.binaryDecimal + property double decimalPlace: plasmoid.configuration.decimalPlace + property int layoutPadding: plasmoid.configuration.layoutPadding + property int accumulator: plasmoid.configuration.accumulator + property bool hideInactive: plasmoid.configuration.hideInactive + property bool hideZone: plasmoid.configuration.hideZone + property var netSources: plasmoid.configuration.netSources + property bool showSeconds: plasmoid.configuration.showSeconds + property string secondsPrefix: plasmoid.configuration.secondsPrefix + property bool decimalFilter0: plasmoid.configuration.decimalFilter0 + property bool decimalFilter1: plasmoid.configuration.decimalFilter1 + property bool decimalFilter2: plasmoid.configuration.decimalFilter2 + property bool decimalFilter3: plasmoid.configuration.decimalFilter3 + property int roundedNumber: plasmoid.configuration.roundedNumber + property double iconSize: Plasmoid.configuration.iconSize + property double sufixSize: Plasmoid.configuration.sufixSize + + property var netInterfaces: [] + property var netPath: [] + //property var numberOfNets: 0 + property var numCheckedNets: 0 + //property var netLabels: [] + property bool ready: false + property var sensorList: [] + property var netDataBits: [] + property var netDataByte: [] + property var netDataTotal: [] + property var netDataAccumulator: [] + property var accumulatorCounter: 0 + //property var getIPInfo: [] + //property var ip: [] + //property var sm: [] + //property var gw: [] + //property var wifiSig: [] + + // FUTURE TOOLTIP + //property bool showTooltip: plasmoid.configuration.showTooltip + //property bool showNetTotals: plasmoid.configuration.showNetTotals + //property string showTotalUnits: plasmoid.configuration.showTotalUnits + //property bool showIntName: plasmoid.configuration.showIntName + //property bool showIP: plasmoid.configuration.showIP + //property bool showIPextra: plasmoid.configuration.showIPextra + //property bool showIcon: plasmoid.configuration.showIcon + //property string showIconOption: plasmoid.configuration.showIconOption + //property bool showSigStrength: plasmoid.configuration.showSigStrength + //property var keyVal: toolTipData() + + id: sysMonitor + Plasmoid.compactRepresentation: CompactRepresentation {} + Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation + + signal updateUi() + signal statsUpd(var keys, var values) + + property alias dbusData : dbusData + + DbusData { + id: dbusData + onNewSensorData: { + // NEW DBUS DATA RECEIVED EVERY 0.5 SECONDS + sysMonitor.statsUpd(keys, values) + } + } + + Timer { + interval: getTriggerInterval() //updateInterval + running: true + repeat: true + + onTriggered: { + sysMonitor.updateUi() + } + } + + function getTriggerInterval() { + if (numCheckedNets < 1) { // NO NETWORKS SELECTED + sysMonitor.updateUi() // UPDATE UI ONCE TO RESET DATA TO 0 + return 0 + } else { + return updateInterval + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/qmldir b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/qmldir new file mode 100644 index 00000000..05defa50 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/contents/ui/qmldir @@ -0,0 +1 @@ +plugin qmldbusmodelplugin ./imports/DbusModel diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/metadata.desktop b/kde/plasma/plasmoids/org.kde.nsw_dbus/metadata.desktop new file mode 100644 index 00000000..94f07f27 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/metadata.desktop @@ -0,0 +1,21 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Network Bandwidth DBUS Widget +Comment=Network bandwidth +Type=Service +X-KDE-ParentApp= +X-KDE-PluginInfo-Author=LeeVD +X-KDE-PluginInfo-Email=thoth360@hotmail.com +X-KDE-PluginInfo-License=GPL3 +X-KDE-PluginInfo-Name=org.kde.nsw_dbus +X-KDE-PluginInfo-Version=v0.4 +X-KDE-PluginInfo-Website=https://github.com/leevd +X-KDE-ServiceTypes=Plasma/Applet +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml +X-Plasma-RemoteLocation= +X-KDE-PluginInfo-Category=System Information +Icon=network-connect + +Name[zh_CN]=Network Bandwidth DBUS Widget +Comment[zh_CN]=网络速度 diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/ReadMe.md b/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/ReadMe.md new file mode 100644 index 00000000..13ef6111 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/ReadMe.md @@ -0,0 +1,24 @@ +## New Translations + +1. Fill out [`template.pot`](template.pot) with your translations then open a [new issue](https://github.com/leevd/issues/new), name the file `spanish.txt`, attach the txt file to the issue (drag and drop). + +Or if you know how to make a pull request + +1. Copy the `template.pot` file and name it your locale's code (Eg: `en`/`de`/`fr`) with the extension `.po`. Then fill out all the `msgstr ""`. + +## Scripts + +* `bash ./merge` will parse the `i18n()` calls in the `*.qml` files and write it to the `template.pot` file. Then it will merge any changes into the `*.po` language files. +* `bash ./build` will convert the `*.po` files to it's binary `*.mo` version and move it to `contents/locale/...` which will bundle the translations in the `*.plasmoid` without needing the user to manually install them. + +## Links + +* i18n scripts from: https://github.com/Zren/plasma-applet-lib/tree/master/package/translate +* https://zren.github.io/kde/docs/widget/#translations-i18n + +## Status + +| Locale | Lines | % Done| +|----------|---------|-------| +| Template | 95 | | +| zh_CN | 95/95 | 100% | diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/build.sh b/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/build.sh new file mode 100755 index 00000000..a064576e --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/build.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# Version: 6 + +# This script will convert the *.po files to *.mo files, rebuilding the package/contents/locale folder. +# Feature discussion: https://phabricator.kde.org/D5209 +# Eg: contents/locale/fr_CA/LC_MESSAGES/plasma_applet_org.kde.plasma.eventcalendar.mo + +DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` +plasmoidName=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Name"` +website=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Website"` +bugAddress="$website" +packageRoot=".." # Root of translatable sources +projectName="plasma_applet_${plasmoidName}" # project name + +#--- +if [ -z "$plasmoidName" ]; then + echo "[build] Error: Couldn't read plasmoidName." + exit +fi + +if [ -z "$(which msgfmt)" ]; then + echo "[build] Error: msgfmt command not found. Need to install gettext" + echo "[build] Running 'sudo apt install gettext'" + sudo apt install gettext + echo "[build] gettext installation should be finished. Going back to installing translations." +fi + +#--- +echo "[build] Compiling messages" + +catalogs=`find . -name '*.po' | sort` +for cat in $catalogs; do + echo "$cat" + catLocale=`basename ${cat%.*}` + msgfmt -o "${catLocale}.mo" "$cat" + + installPath="$DIR/../contents/locale/${catLocale}/LC_MESSAGES/${projectName}.mo" + + echo "[build] Install to ${installPath}" + mkdir -p "$(dirname "$installPath")" + mv "${catLocale}.mo" "${installPath}" +done + +echo "[build] Done building messages" + +if [ "$1" = "--restartplasma" ]; then + echo "[build] Restarting plasmashell" + killall plasmashell + kstart5 plasmashell + echo "[build] Done restarting plasmashell" +else + echo "[build] (re)install the plasmoid and restart plasmashell to test." +fi \ No newline at end of file diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/merge.sh b/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/merge.sh new file mode 100755 index 00000000..a377ef05 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/merge.sh @@ -0,0 +1,240 @@ +#!/bin/bash +# Version: 22 + +# https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems +# https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems/Outside_KDE_repositories +# https://invent.kde.org/sysadmin/l10n-scripty/-/blob/master/extract-messages.sh + +DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` +plasmoidName=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Name"` +widgetName="${plasmoidName##*.}" # Strip namespace +website=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Website"` +bugAddress="$website" +packageRoot=".." # Root of translatable sources +projectName="plasma_applet_${plasmoidName}" # project name + +#--- +if [ -z "$plasmoidName" ]; then + echo "[merge] Error: Couldn't read plasmoidName." + exit +fi + +if [ -z "$(which xgettext)" ]; then + echo "[merge] Error: xgettext command not found. Need to install gettext" + echo "[merge] Running 'sudo apt install gettext'" + sudo apt install gettext + echo "[merge] gettext installation should be finished. Going back to merging translations." +fi + +#--- +echo "[merge] Extracting messages" +potArgs="--from-code=UTF-8 --width=200 --add-location=file" + +# Note: xgettext v0.20.1 (Kubuntu 20.04) and below will attempt to translate Icon, +# so we need to specify Name, GenericName, Comment, and Keywords. +# https://github.com/Zren/plasma-applet-lib/issues/1 +# https://savannah.gnu.org/support/?108887 +find "${packageRoot}" -name '*.desktop' | sort > "${DIR}/infiles.list" +xgettext \ + ${potArgs} \ + --files-from="${DIR}/infiles.list" \ + --language=Desktop \ + -k -kName -kGenericName -kComment -kKeywords \ + -D "${packageRoot}" \ + -D "${DIR}" \ + -o "template.pot.new" \ + || \ + { echo "[merge] error while calling xgettext. aborting."; exit 1; } + +sed -i 's/"Content-Type: text\/plain; charset=CHARSET\\n"/"Content-Type: text\/plain; charset=UTF-8\\n"/' "template.pot.new" + +# See Ki18n's extract-messages.sh for a full example: +# https://invent.kde.org/sysadmin/l10n-scripty/-/blob/master/extract-messages.sh#L25 +# The -kN_ and -kaliasLocale keywords are mentioned in the Outside_KDE_repositories wiki. +# We don't need -kN_ since we don't use intltool-extract but might as well keep it. +# I have no idea what -kaliasLocale is used for. Googling aliasLocale found only listed kde1 code. +# We don't need to parse -ki18nd since that'll extract messages from other domains. +find "${packageRoot}" -name '*.cpp' -o -name '*.h' -o -name '*.c' -o -name '*.qml' -o -name '*.js' | sort > "${DIR}/infiles.list" +xgettext \ + ${potArgs} \ + --files-from="${DIR}/infiles.list" \ + -C --kde \ + -k \ + -ci18n \ + -ki18n:1 -ki18nc:1c,2 -ki18np:1,2 -ki18ncp:1c,2,3 \ + -kki18n:1 -kki18nc:1c,2 -kki18np:1,2 -kki18ncp:1c,2,3 \ + -kxi18n:1 -kxi18nc:1c,2 -kxi18np:1,2 -kxi18ncp:1c,2,3 \ + -kkxi18n:1 -kkxi18nc:1c,2 -kkxi18np:1,2 -kkxi18ncp:1c,2,3 \ + -kI18N_NOOP:1 -kI18NC_NOOP:1c,2 \ + -kI18N_NOOP2:1c,2 -kI18N_NOOP2_NOSTRIP:1c,2 \ + -ktr2i18n:1 -ktr2xi18n:1 \ + -kN_:1 \ + -kaliasLocale \ + --package-name="${widgetName}" \ + --msgid-bugs-address="${bugAddress}" \ + -D "${packageRoot}" \ + -D "${DIR}" \ + --join-existing \ + -o "template.pot.new" \ + || \ + { echo "[merge] error while calling xgettext. aborting."; exit 1; } + +sed -i 's/# SOME DESCRIPTIVE TITLE./'"# Translation of ${widgetName} in LANGUAGE"'/' "template.pot.new" +sed -i 's/# Copyright (C) YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/'"# Copyright (C) $(date +%Y)"'/' "template.pot.new" + +if [ -f "template.pot" ]; then + newPotDate=`grep "POT-Creation-Date:" template.pot.new | sed 's/.\{3\}$//'` + oldPotDate=`grep "POT-Creation-Date:" template.pot | sed 's/.\{3\}$//'` + sed -i 's/'"${newPotDate}"'/'"${oldPotDate}"'/' "template.pot.new" + changes=`diff "template.pot" "template.pot.new"` + if [ ! -z "$changes" ]; then + # There's been changes + sed -i 's/'"${oldPotDate}"'/'"${newPotDate}"'/' "template.pot.new" + mv "template.pot.new" "template.pot" + + addedKeys=`echo "$changes" | grep "> msgid" | cut -c 9- | sort` + removedKeys=`echo "$changes" | grep "< msgid" | cut -c 9- | sort` + echo "" + echo "Added Keys:" + echo "$addedKeys" + echo "" + echo "Removed Keys:" + echo "$removedKeys" + echo "" + + else + # No changes + rm "template.pot.new" + fi +else + # template.pot didn't already exist + mv "template.pot.new" "template.pot" +fi + +potMessageCount=`expr $(grep -Pzo 'msgstr ""\n(\n|$)' "template.pot" | grep -c 'msgstr ""')` +echo "| Locale | Lines | % Done|" > "./Status.md" +echo "|----------|---------|-------|" >> "./Status.md" +entryFormat="| %-8s | %7s | %5s |" +templateLine=`perl -e "printf(\"$entryFormat\", \"Template\", \"${potMessageCount}\", \"\")"` +echo "$templateLine" >> "./Status.md" + +rm "${DIR}/infiles.list" +echo "[merge] Done extracting messages" + +#--- +echo "[merge] Merging messages" +catalogs=`find . -name '*.po' | sort` +for cat in $catalogs; do + echo "[merge] $cat" + catLocale=`basename ${cat%.*}` + + widthArg="" + catUsesGenerator=`grep "X-Generator:" "$cat"` + if [ -z "$catUsesGenerator" ]; then + widthArg="--width=400" + fi + + compendiumArg="" + if [ ! -z "$COMPENDIUM_DIR" ]; then + langCode=`basename "${cat%.*}"` + compendiumPath=`realpath "$COMPENDIUM_DIR/compendium-${langCode}.po"` + if [ -f "$compendiumPath" ]; then + echo "compendiumPath=$compendiumPath" + compendiumArg="--compendium=$compendiumPath" + fi + fi + + cp "$cat" "$cat.new" + sed -i 's/"Content-Type: text\/plain; charset=CHARSET\\n"/"Content-Type: text\/plain; charset=UTF-8\\n"/' "$cat.new" + + msgmerge \ + ${widthArg} \ + --add-location=file \ + --no-fuzzy-matching \ + ${compendiumArg} \ + -o "$cat.new" \ + "$cat.new" "${DIR}/template.pot" + + sed -i 's/# SOME DESCRIPTIVE TITLE./'"# Translation of ${widgetName} in ${catLocale}"'/' "$cat.new" + sed -i 's/# Translation of '"${widgetName}"' in LANGUAGE/'"# Translation of ${widgetName} in ${catLocale}"'/' "$cat.new" + sed -i 's/# Copyright (C) YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/'"# Copyright (C) $(date +%Y)"'/' "$cat.new" + + poEmptyMessageCount=`expr $(grep -Pzo 'msgstr ""\n(\n|$)' "$cat.new" | grep -c 'msgstr ""')` + poMessagesDoneCount=`expr $potMessageCount - $poEmptyMessageCount` + poCompletion=`perl -e "printf(\"%d\", $poMessagesDoneCount * 100 / $potMessageCount)"` + poLine=`perl -e "printf(\"$entryFormat\", \"$catLocale\", \"${poMessagesDoneCount}/${potMessageCount}\", \"${poCompletion}%\")"` + echo "$poLine" >> "./Status.md" + + # mv "$cat" "$cat.old" + mv "$cat.new" "$cat" +done +echo "[merge] Done merging messages" + +#--- +echo "[merge] Updating .desktop file" + +# Generate LINGUAS for msgfmt +if [ -f "$DIR/LINGUAS" ]; then + rm "$DIR/LINGUAS" +fi +touch "$DIR/LINGUAS" +for cat in $catalogs; do + catLocale=`basename ${cat%.*}` + echo "${catLocale}" >> "$DIR/LINGUAS" +done + +cp -f "$DIR/../metadata.desktop" "$DIR/template.desktop" +sed -i '/^Name\[/ d; /^GenericName\[/ d; /^Comment\[/ d; /^Keywords\[/ d' "$DIR/template.desktop" + +msgfmt \ + --desktop \ + --template="$DIR/template.desktop" \ + -d "$DIR/" \ + -o "$DIR/new.desktop" + +# Delete empty msgid messages that used the po header +if [ ! -z "$(grep '^Name=$' "$DIR/new.desktop")" ]; then + echo "[merge] Name in metadata.desktop is empty!" + sed -i '/^Name\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^GenericName=$' "$DIR/new.desktop")" ]; then + echo "[merge] GenericName in metadata.desktop is empty!" + sed -i '/^GenericName\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^Comment=$' "$DIR/new.desktop")" ]; then + echo "[merge] Comment in metadata.desktop is empty!" + sed -i '/^Comment\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^Keywords=$' "$DIR/new.desktop")" ]; then + echo "[merge] Keywords in metadata.desktop is empty!" + sed -i '/^Keywords\[/ d' "$DIR/new.desktop" +fi + +# Place translations at the bottom of the desktop file. +translatedLines=`cat "$DIR/new.desktop" | grep "]="` +if [ ! -z "${translatedLines}" ]; then + sed -i '/^Name\[/ d; /^GenericName\[/ d; /^Comment\[/ d; /^Keywords\[/ d' "$DIR/new.desktop" + if [ "$(tail -c 2 "$DIR/new.desktop" | wc -l)" != "2" ]; then + # Does not end with 2 empty lines, so add an empty line. + echo "" >> "$DIR/new.desktop" + fi + echo "${translatedLines}" >> "$DIR/new.desktop" +fi + +# Cleanup +mv "$DIR/new.desktop" "$DIR/../metadata.desktop" +rm "$DIR/template.desktop" +rm "$DIR/LINGUAS" + +#--- +# Populate ReadMe.md +echo "[merge] Updating translate/ReadMe.md" +sed -i -E 's`share\/plasma\/plasmoids\/(.+)\/translate`share/plasma/plasmoids/'"${plasmoidName}"'/translate`' ./ReadMe.md +if [[ "$website" == *"github.com"* ]]; then + sed -i -E 's`\[new issue\]\(https:\/\/github\.com\/(.+)\/(.+)\/issues\/new\)`[new issue]('"${website}"'/issues/new)`' ./ReadMe.md +fi +sed -i '/^|/ d' ./ReadMe.md # Remove status table from ReadMe +cat ./Status.md >> ./ReadMe.md +rm ./Status.md + +echo "[merge] Done" \ No newline at end of file diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/template.pot b/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/template.pot new file mode 100644 index 00000000..9e142d3d --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/template.pot @@ -0,0 +1,505 @@ +# Translation of nsw_dbus in LANGUAGE +# Copyright (C) 2023 +# This file is distributed under the same license as the nsw_dbus package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: nsw_dbus\n" +"Report-Msgid-Bugs-To: https://github.com/leevd\n" +"POT-Creation-Date: 2023-03-29 23:28+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Network Bandwidth DBUS Widget" +msgstr "" + +#: ../metadata.desktop +msgid "Network bandwidth" +msgstr "" + +#: ../contents/config/config.qml +#, kde-format +msgid "General" +msgstr "" + +#: ../contents/config/config.qml +#, kde-format +msgid "Network" +msgstr "" + +#: ../contents/ui/CompactRepresentation.qml +#, kde-format +msgid "Network Bandwidth Monitor" +msgstr "" + +#: ../contents/ui/CompactRepresentation.qml +#, kde-format +msgid "DBUS Data Source" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "i" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Layout:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Automatic" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Vertical" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Horizontal" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Should automatically adjust to size available in taskbar." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Upload and Download will be stacked on top of each other:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Upload and Download will be aligned side by side:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Display order:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Upload speed first" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Download speed first" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Upload data on the top in Vertical layout or left in Horizontal." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Download data on the top in Vertical layout or left in Horizontal." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Show speeds separately:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Checked" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "The Upload and Download data will be displayed separately either stacked or side by side." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Unchecked" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "The Upload and Download data will be combined both in data calculation and display. Only one row of data will be shown combining both data measurements with a matching icon." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Font size:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Increase font size, maximum 200%." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Decrease font size, minimum 50%" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Update interval:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 second" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 seconds" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Summary" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Controls the time interval new network data is displayed in the widget." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Adjustments are in 0.5 second increments." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Increase the time interval, maximum 5 seconds." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Decrease the time interval, minimum 0.5 seconds." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Interval data relay:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Current" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Average" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Accumulated" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "This option becomes usable when 'Update interval' is above 0.5 seconds." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "" +"Shows the amount of used network speed at the interval set in 'Update interval'. For example, if 'Update interval' is 4 seconds, at every 4th second the display will only show the amount of speed " +"traversing at that point (statistical value for the past 0.5 seconds, this is the minimum resolution of the data source) in time. The display will not refresh for the following 4 seconds." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "" +"The mathematically correct way to calculate the network speed over time. This setting will return the network speed averaged over the period specified in 'Update interval'. Using the per second " +"prefix ('/s' or 'ps') is correct with this option." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "" +"Returns the accumulated network traffic over the specified time period. For example, if 'Update interval' is set to 4 seconds, at every 4th second you will be presented with the sum total of " +"network traffic over the time period selected. Using the per second prefix ('/s' or 'ps') with this option is not technically correct but the choice is yours." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Layout Padding:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Default pixels" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 pixel closer" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 pixels closer" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 pixel apart" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 pixels apart" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Move the upload and download data rows closer together, maximum 20 pixels closer." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Increase the distance between upload and download data rows, maximum 20 pixels apart." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "* Function disabled in 'Horizontal' layout mode." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Hide when inactive:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Hides the display when '0' traffic is reported. Displays will become visible again when traffic starts to flow." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Shows the display even when no traffic is traversing the network interfaces." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Show speed units:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Hides the trailing suffix for the bits (b, kib, Mib Gib) or bytes (B, KB, MB, GB)." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Shows the suffixes for bits or bytes." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Speed units:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Bits" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Bytes" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Displays data throughput based on bit units. The default option, bits are normally used to measure a data transfer." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Displays data throughput based on byte units. Second option as bytes can be used to measure an amount of data, normally storage data." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Shorten speed units:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Will only use a single character to represent the bits or bytes suffix, for example kb = k, Mb = M etc. Per second units will also not be displayed." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "The complete suffix will be displayed including the per second unit." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Show 'per seconds' suffix:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Appends the per second suffix to the trailing measurement unit." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "* This option is technically correct when used in conjunction with 'Interval data relay' choice other than 'Accumulated'." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Removes the per second suffix ('/s' or 'ps') from the trailing bit or byte measurement unit." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "* This option is technically correct when used in conjunction with 'Interval data relay' choice of 'Accumulated'." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Per Seconds prefix:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "/s" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "ps" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Choose between a per second unit of '/s' or 'ps'." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Example, measuring in bits: Kib/s or Kibps, measuring in bytes: KB/s or KBps." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Show speed icons:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Displays the Download or Upload icons in the widget." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Hides the Download or Upload icons in the widget." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Icon Style:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Choose the Upload and Download icon style to be displayed in the widget." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Icon position:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Left" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Right" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Choose to have the Upload and Download icons to the left or the right of the speed data." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Numbers:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Binary (1024)" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Metric (1000)" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "In computing, binary 1024 and decimal 1000 are two different ways of measuring units of digital information." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "" +"Decimal 1000 is based on the metric system, which is based on powers of 10. In this system, each unit is 10 times larger than the previous unit. For example, 1 kilometer is 1000 meters, 1 megabyte " +"is 1000 kilobytes, and so on." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "" +"Binary 1024 is based on the binary system, which is based on powers of 2. In this system, each unit is twice as large as the previous unit. For example, 1 kilobyte is 1024 bytes, 1 megabyte is 1024 " +"kilobytes, and so on." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "" +"The reason why binary 1024 is used in computing is because computers store and process data in binary (0s and 1s), and it is convenient to use units that are based on powers of 2. However, for some " +"purposes, such as networking, decimal 1000 units are used instead." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "" +"To avoid confusion, it is important to clearly specify which unit system is being used, and to use the correct prefix (e.g., kilo, mega) for the unit. The prefixes 'kibi,' 'mebi,' 'gibi,' etc. have " +"been introduced to refer to binary 1024 units, while the prefixes 'kilo,' 'mega,' 'giga,' etc. continue to refer to decimal 1000 units." +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Decimal Place:" +msgstr "" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Choose the number of decimal fraction digits to the right of the decimal point." +msgstr "" diff --git a/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/zh_CN.po b/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/zh_CN.po new file mode 100644 index 00000000..f51c7619 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.nsw_dbus/translate/zh_CN.po @@ -0,0 +1,499 @@ +# Translation of nsw_dbus in zh_CN +# Copyright (C) 2023 +# This file is distributed under the same license as the nsw_dbus package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: nsw_dbus\n" +"Report-Msgid-Bugs-To: https://github.com/leevd\n" +"POT-Creation-Date: 2023-03-29 23:28+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Network Bandwidth DBUS Widget" +msgstr "Network Bandwidth DBUS Widget" + +#: ../metadata.desktop +msgid "Network bandwidth" +msgstr "网络速度" + +#: ../contents/config/config.qml +#, kde-format +msgid "General" +msgstr "常规" + +#: ../contents/config/config.qml +#, kde-format +msgid "Network" +msgstr "网络" + +#: ../contents/ui/CompactRepresentation.qml +#, kde-format +msgid "Network Bandwidth Monitor" +msgstr "网络带宽监视器" + +#: ../contents/ui/CompactRepresentation.qml +#, kde-format +msgid "DBUS Data Source" +msgstr "DBUS数据源" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "i" +msgstr "i" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Layout:" +msgstr "布局" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Automatic" +msgstr "自动布局" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Vertical" +msgstr "垂直布局" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Horizontal" +msgstr "水平布局" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Should automatically adjust to size available in taskbar." +msgstr "自动调整为任务栏中可用的大小。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Upload and Download will be stacked on top of each other:" +msgstr "上下叠放上传速度和下载速度:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Upload and Download will be aligned side by side:" +msgstr "并排显示上传速度和下载速度:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Display order:" +msgstr "显示顺序:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Upload speed first" +msgstr "上传速度在前" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Download speed first" +msgstr "下载速度在前" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Upload data on the top in Vertical layout or left in Horizontal." +msgstr "上传速度显示在垂直布局的顶部,或水平布局的左侧。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Download data on the top in Vertical layout or left in Horizontal." +msgstr "下载速度显示在垂直布局的顶部,或水平布局的左侧。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Show speeds separately:" +msgstr "分别显示上传下载速度:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Checked" +msgstr "选中" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "The Upload and Download data will be displayed separately either stacked or side by side." +msgstr "上传和下载速度将单独显示" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Unchecked" +msgstr "取消选中" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "The Upload and Download data will be combined both in data calculation and display. Only one row of data will be shown combining both data measurements with a matching icon." +msgstr "上传和下载速度相加后显示,仅占用一行空间。同时显示上传和下载的图标。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Font size:" +msgstr "字体大小:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Increase font size, maximum 200%." +msgstr "增大字体,最大 200%。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Decrease font size, minimum 50%" +msgstr "缩小字体,最小 50%。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Update interval:" +msgstr "更新间隔:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 second" +msgstr "%1 秒" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 seconds" +msgstr "%1 秒" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Summary" +msgstr "简要说明" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Controls the time interval new network data is displayed in the widget." +msgstr "控制网络速度显示的更新间隔。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Adjustments are in 0.5 second increments." +msgstr "调整步进为 0.5 秒。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Increase the time interval, maximum 5 seconds." +msgstr "增加时间间隔,最大 5 秒。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Decrease the time interval, minimum 0.5 seconds." +msgstr "减少时间间隔,最小 0.5 秒。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Interval data relay:" +msgstr "更新间隔的计算方式:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Current" +msgstr "当前值" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Average" +msgstr "平均值" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Accumulated" +msgstr "累加值" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "This option becomes usable when 'Update interval' is above 0.5 seconds." +msgstr "当 “更新间隔” 大于 0.5 秒时,此选项可用。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Shows the amount of used network speed at the interval set in 'Update interval'. For example, if 'Update interval' is 4 seconds, at every 4th second the display will only show the amount of speed traversing at that point (statistical value for the past 0.5 seconds, this is the minimum resolution of the data source) in time. The display will not refresh for the following 4 seconds." +msgstr "以 “更新间隔” 设置的频率显示当前(实际上是过去 0.5 秒内,因为这是数据源的最小分辨率)的网络速度。例如 “更新间隔” 为 4 秒,则每隔 4 秒显示一次过去 0.5 秒内的网络速度。在接下来的 4 秒内,显示不会刷新。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "The mathematically correct way to calculate the network speed over time. This setting will return the network speed averaged over the period specified in 'Update interval'. Using the per second prefix ('/s' or 'ps') is correct with this option." +msgstr "计算随时间变化的网络速度的数学上正确方法。此设置将显示 “更新间隔” 中指定时间段内的平均网络速度。使用此选项时,启用 “每秒” 后缀( “/s” 或 “ps” )是正确的。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Returns the accumulated network traffic over the specified time period. For example, if 'Update interval' is set to 4 seconds, at every 4th second you will be presented with the sum total of network traffic over the time period selected. Using the per second prefix ('/s' or 'ps') with this option is not technically correct but the choice is yours." +msgstr "返回 “更新间隔” 内累计的网络流量。例如, “更新间隔” 设置为 4 秒,则每隔 4 秒您将看到间隔内的网络流量总和。使用此选项时,启用 “每秒” 后缀( “/s” 或 “ps” )在技术上是不正确的,但选择权在你。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Layout Padding:" +msgstr "布局对齐:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Default pixels" +msgstr "默认设置" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 pixel closer" +msgstr "减小 %1 像素间距" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 pixels closer" +msgstr "减小 %1 像素间距" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 pixel apart" +msgstr "增加 %1 像素间距" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "%1 pixels apart" +msgstr "增加 %1 像素间距" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Move the upload and download data rows closer together, maximum 20 pixels closer." +msgstr "缩小上传和下载速度之间的间距,最多 20 个像素。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Increase the distance between upload and download data rows, maximum 20 pixels apart." +msgstr "增加上传和下载速度之间的间距,最多 20 个像素。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "* Function disabled in 'Horizontal' layout mode." +msgstr "* 功能在“水平”布局模式下被禁用。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Hide when inactive:" +msgstr "不活动时隐藏:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Hides the display when '0' traffic is reported. Displays will become visible again when traffic starts to flow." +msgstr "流量为 “0” 时隐藏显示。反之会恢复显示。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Shows the display even when no traffic is traversing the network interfaces." +msgstr "即使没有流量通过网络接口也显示。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Show speed units:" +msgstr "显示速度单位:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Hides the trailing suffix for the bits (b, kib, Mib Gib) or bytes (B, KB, MB, GB)." +msgstr "隐藏 bits(b、kib、Mib Gib)或 bytes(B、KB、MB、GB)的尾随后缀。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Shows the suffixes for bits or bytes." +msgstr "显示 bits 或 bytes 的后缀。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Speed units:" +msgstr "速度单位:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Bits" +msgstr "Bits" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Bytes" +msgstr "Bytes" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Displays data throughput based on bit units. The default option, bits are normally used to measure a data transfer." +msgstr "以 bit 为单位显示数据吞吐量。默认选项,bit 通常用于测量数据传输。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Displays data throughput based on byte units. Second option as bytes can be used to measure an amount of data, normally storage data." +msgstr "以 bit 为单位显示数据吞吐量。第二种选择,因为 bytes 可以用来衡量数据量,通常是存储的数据大小" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Shorten speed units:" +msgstr "更短的速度单位格式:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Will only use a single character to represent the bits or bytes suffix, for example kb = k, Mb = M etc. Per second units will also not be displayed." +msgstr "只用单个字符来表示 bits 或 bytes后缀,例如 Kb 显示为 K、Mb 显示为 M 等。每秒的单位也不会显示。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "The complete suffix will be displayed including the per second unit." +msgstr "将显示完整的后缀,包括每秒单位。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Show 'per seconds' suffix:" +msgstr "显示单位后缀" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Appends the per second suffix to the trailing measurement unit." +msgstr "保留单位后的 “每秒” 后缀" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "* This option is technically correct when used in conjunction with 'Interval data relay' choice other than 'Accumulated'." +msgstr "* 当与 “更新间隔的计算方式” 中 “累加值” 以外的选项一起使用时,在技术上是正确的。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Removes the per second suffix ('/s' or 'ps') from the trailing bit or byte measurement unit." +msgstr "从测量单位中删除 “每秒” 后缀( “/s” 或 “ps” )。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "* This option is technically correct when used in conjunction with 'Interval data relay' choice of 'Accumulated'." +msgstr "* 当与 “更新间隔的计算方式” 中的 “累加值” 选项一起使用时,在技术上是正确的。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Per Seconds prefix:" +msgstr "单位后缀" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "/s" +msgstr "/s" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "ps" +msgstr "ps" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Choose between a per second unit of '/s' or 'ps'." +msgstr "在每秒单位 “/s” 或 “ps” 之间进行选择" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Example, measuring in bits: Kib/s or Kibps, measuring in bytes: KB/s or KBps." +msgstr "例如,以 bit 为单位时:Kib/s 或 Kibps;以 byte 为单位时:KB/s 或 KBps。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Show speed icons:" +msgstr "显示速度类型图标:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Displays the Download or Upload icons in the widget." +msgstr "显示下载或上传图标。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Hides the Download or Upload icons in the widget." +msgstr "隐藏下载或上传图标。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Icon Style:" +msgstr "图标风格:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Choose the Upload and Download icon style to be displayed in the widget." +msgstr "选择上传和下载图标样式。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Icon position:" +msgstr "图标位置:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Left" +msgstr "左" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Right" +msgstr "右" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Choose to have the Upload and Download icons to the left or the right of the speed data." +msgstr "将上传和下载图标置于速度数据的左侧或右侧。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Numbers:" +msgstr "数值进位:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Binary (1024)" +msgstr "二进制(1024)" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Metric (1000)" +msgstr "公制(1000)" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "In computing, binary 1024 and decimal 1000 are two different ways of measuring units of digital information." +msgstr "在计算机中,二进制 1024 和十进制 1000 是两种不同的数字信息计量单位。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Decimal 1000 is based on the metric system, which is based on powers of 10. In this system, each unit is 10 times larger than the previous unit. For example, 1 kilometer is 1000 meters, 1 megabyte is 1000 kilobytes, and so on." +msgstr "十进制的 1000 是基于公制的,公制是基于 10 的幂。在这个系统中,每个单位都比前一个单位大 1000 倍。例如,1 公里是 1000 米,1 megabyte 是 1000 bytes,等等。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Binary 1024 is based on the binary system, which is based on powers of 2. In this system, each unit is twice as large as the previous unit. For example, 1 kilobyte is 1024 bytes, 1 megabyte is 1024 kilobytes, and so on." +msgstr "二进制 1024 是基于二进制的系统,它是基于 2 的幂。在这个系统中,每个单位都是前一个单位的 2^10 倍。例如,1 kilobyte 是 1024 bytes,1 megabyte 是 1024 kilobytes,依此类推。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "The reason why binary 1024 is used in computing is because computers store and process data in binary (0s and 1s), and it is convenient to use units that are based on powers of 2. However, for some purposes, such as networking, decimal 1000 units are used instead." +msgstr "之所以在计算机中使用二进制 1024 是因为计算机以二进制(0 和 1)存储和处理数据,使用基于 2 的幂的单位很方便。但是,出于某些目的,例如网络,则改为使用十进制的 1000 为单位。" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "To avoid confusion, it is important to clearly specify which unit system is being used, and to use the correct prefix (e.g., kilo, mega) for the unit. The prefixes 'kibi,' 'mebi,' 'gibi,' etc. have been introduced to refer to binary 1024 units, while the prefixes 'kilo,' 'mega,' 'giga,' etc. continue to refer to decimal 1000 units." +msgstr "为避免混淆,重要的是要清楚地指定正在使用的单位系统,并为单位使用正确的前缀(例如 kilo、mega)。因此引入前缀 “kibi”、 “mebi”、 “gibi” 等来表示二进制 1024 单位,而前缀 “kilo”、 “mega”、 “giga” 等继续表示十进制 1000 单位." + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Decimal Place:" +msgstr "保留小数点:" + +#: ../contents/ui/config/configGeneral.qml +#, kde-format +msgid "Choose the number of decimal fraction digits to the right of the decimal point." +msgstr "选择小数点右边保留的小数位数。" + +#, kde-format +#~ msgid "Move the upload and download data rows closer together, maximum 10 pixels closer." +#~ msgstr "缩小上传和下载速度之间的间距,最多 10 个像素。" + +#, kde-format +#~ msgid "Increase the distance between upload and download data rows, maximum 10 pixels apart." +#~ msgstr "增加上传和下载速度之间的间距,最多 10 个像素。" diff --git a/kde/plasma/plasmoids/org.kde.plasma.christmastree/LICENSE b/kde/plasma/plasmoids/org.kde.plasma.christmastree/LICENSE new file mode 100644 index 00000000..8000a6fa --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.christmastree/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random + Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/config/config.qml b/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/config/config.qml new file mode 100644 index 00000000..1f2b8ae3 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/config/config.qml @@ -0,0 +1,10 @@ +import QtQuick 2.2 +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n('Appearance') + icon: 'preferences-desktop-color' + source: 'config/ConfigAppearance.qml' + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/config/main.xml b/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/config/main.xml new file mode 100644 index 00000000..57f3e216 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/config/main.xml @@ -0,0 +1,14 @@ + + + + + + + 1 + + + + diff --git a/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/ui/christmas_tree.gif b/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/ui/christmas_tree.gif new file mode 100755 index 00000000..654a2390 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/ui/christmas_tree.gif differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/ui/config/ConfigAppearance.qml b/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/ui/config/ConfigAppearance.qml new file mode 100644 index 00000000..c78ccf8e --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/ui/config/ConfigAppearance.qml @@ -0,0 +1,33 @@ +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.4 + +Item { + property alias cfg_scaleValue: scaleValue.value + + + GridLayout { + columns: 2 + columnSpacing: 50; rowSpacing: 3 + Layout.fillWidth: true + anchors.right: parent.right + anchors.left: parent.left + + Label { + Layout.row: 0 + Layout.column: 1 + text: i18n("Scale:") + } + Slider { + Layout.row: 1 + Layout.column: 1 + id: scaleValue + stepSize: 0.1 + minimumValue: 0.2 + maximumValue: 4.0 + Layout.fillWidth: true + Layout.alignment: Qt.AlignRight + } + } +} + diff --git a/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/ui/main.qml b/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/ui/main.qml new file mode 100644 index 00000000..2aa176a9 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.christmastree/contents/ui/main.qml @@ -0,0 +1,41 @@ +/* + Copyright 2019 Alexey Varfolomeev + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This plasmoid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this plasmoid. If not, see . +*/ + +import QtQuick 2.0 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.plasmoid 2.0 + +Item { + id: main + anchors.fill: parent + Plasmoid.backgroundHints: "NoBackground"; + Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation + property string scaleValue: Plasmoid.configuration.scaleValue + + Image { + width: animation.width; height: animation.height + transform: Scale { xScale: scaleValue; yScale: scaleValue } + AnimatedImage { id: animation; source: "christmas_tree.gif" } + + } + +} + diff --git a/kde/plasma/plasmoids/org.kde.plasma.christmastree/metadata.desktop b/kde/plasma/plasmoids/org.kde.plasma.christmastree/metadata.desktop new file mode 100644 index 00000000..d9649963 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.christmastree/metadata.desktop @@ -0,0 +1,21 @@ +[Desktop Entry] +Name=Christmas Tree +Comment=Animated Christmas Tree on your Plasma 5 Desktop +Icon=rating + +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml +X-Plasma-DefaultSize=140,140 + +X-KDE-PluginInfo-Author=Alexey Varfolomeev +X-KDE-PluginInfo-Email=varlesh@gmail.com +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category=Other +X-KDE-PluginInfo-Name=org.kde.plasma.christmastree +X-KDE-PluginInfo-Version=0.2 + +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-ServiceTypes=Plasma/Applet,Plasma/PopupApplet +Type=Service diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/code/tools.js b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/code/tools.js new file mode 100644 index 00000000..ffc44d3d --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/code/tools.js @@ -0,0 +1,231 @@ +/*************************************************************************** + * Copyright (C) 2013 by Aurélien Gâteau * + * Copyright (C) 2013-2015 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +.pragma library + +function fillActionMenu(i18n, actionMenu, actionList, favoriteModel, favoriteId) { + // Accessing actionList can be a costly operation, so we don't + // access it until we need the menu. + + var actions = createFavoriteActions(i18n, favoriteModel, favoriteId); + + if (actions) { + if (actionList && actionList.length > 0) { + var separator = { "type": "separator" }; + actionList.unshift(separator); + // actionList = actions.concat(actionList); // this crashes Qt O.o + actionList.unshift.apply(actionList, actions); + } else { + actionList = actions; + } + } + + actionMenu.actionList = actionList; +} + +function createFavoriteActions(i18n, favoriteModel, favoriteId) { + if (favoriteModel === null || !favoriteModel.enabled || favoriteId == null) { + return null; + } + + if ("initForClient" in favoriteModel) { + var activities = favoriteModel.activities.runningActivities; + + if (activities.length <= 1) { + var action = {}; + + if (favoriteModel.isFavorite(favoriteId)) { + action.text = i18n("Remove from Favorites"); + action.icon = "list-remove"; + action.actionId = "_kicker_favorite_remove"; + } else if (favoriteModel.maxFavorites == -1 || favoriteModel.count < favoriteModel.maxFavorites) { + action.text = i18n("Add to Favorites"); + action.icon = "bookmark-new"; + action.actionId = "_kicker_favorite_add"; + } else { + return null; + } + + action.actionArgument = { favoriteModel: favoriteModel, favoriteId: favoriteId }; + + return [action]; + + } else { + var actions = []; + + var linkedActivities = favoriteModel.linkedActivitiesFor(favoriteId); + + // Adding the item to link/unlink to all activities + + var linkedToAllActivities = + !(linkedActivities.indexOf(":global") === -1); + + actions.push({ + text : i18n("On All Activities"), + checkable : true, + + actionId : linkedToAllActivities ? + "_kicker_favorite_remove_from_activity" : + "_kicker_favorite_set_to_activity", + checked : linkedToAllActivities, + + actionArgument : { + favoriteModel: favoriteModel, + favoriteId: favoriteId, + favoriteActivity: "" + } + }); + + + // Adding items for each activity separately + + var addActivityItem = function(activityId, activityName) { + var linkedToThisActivity = + !(linkedActivities.indexOf(activityId) === -1); + + actions.push({ + text : activityName, + checkable : true, + checked : linkedToThisActivity && !linkedToAllActivities, + + actionId : + // If we are on all activities, and the user clicks just one + // specific activity, unlink from everything else + linkedToAllActivities ? "_kicker_favorite_set_to_activity" : + + // If we are linked to the current activity, just unlink from + // that single one + linkedToThisActivity ? "_kicker_favorite_remove_from_activity" : + + // Otherwise, link to this activity, but do not unlink from + // other ones + "_kicker_favorite_add_to_activity", + + actionArgument : { + favoriteModel : favoriteModel, + favoriteId : favoriteId, + favoriteActivity : activityId + } + }); + }; + + // Adding the item to link/unlink to the current activity + + addActivityItem(favoriteModel.activities.currentActivity, i18n("On The Current Activity")); + + actions.push({ + type: "separator", + actionId: "_kicker_favorite_separator" + }); + + // Adding the items for each activity + + activities.forEach(function(activityId) { + addActivityItem(activityId, favoriteModel.activityNameForId(activityId)); + }); + + return [{ + text : i18n("Show In Favorites"), + icon : "favorite", + subActions : actions + }]; + } + } else { + var action = {}; + + if (favoriteModel.isFavorite(favoriteId)) { + action.text = i18n("Remove from Favorites"); + action.icon = "list-remove"; + action.actionId = "_kicker_favorite_remove"; + } else if (favoriteModel.maxFavorites == -1 || favoriteModel.count < favoriteModel.maxFavorites) { + action.text = i18n("Add to Favorites"); + action.icon = "bookmark-new"; + action.actionId = "_kicker_favorite_add"; + } else { + return null; + } + + action.actionArgument = { favoriteModel: favoriteModel, favoriteId: favoriteId }; + + return [action]; + } +} + +function triggerAction(plasmoid, model, index, actionId, actionArgument) { + function startsWith(txt, needle) { + return txt.substr(0, needle.length) === needle; + } + + if (startsWith(actionId, "_kicker_favorite_")) { + handleFavoriteAction(actionId, actionArgument); + return; + } + + var closeRequested = model.trigger(index, actionId, actionArgument); + + if (closeRequested) { + plasmoid.expanded = false; + + return true; + } + + return false; +} + +function handleFavoriteAction(actionId, actionArgument) { + var favoriteId = actionArgument.favoriteId; + var favoriteModel = actionArgument.favoriteModel; + + console.log(actionId); + + if (favoriteModel === null || favoriteId == null) { + return null; + } + + if ("initForClient" in favoriteModel) { + if (actionId == "_kicker_favorite_remove") { + console.log("Removing from all activities"); + favoriteModel.removeFavoriteFrom(favoriteId, ":any"); + + } else if (actionId == "_kicker_favorite_add") { + console.log("Adding to global activity"); + favoriteModel.addFavoriteTo(favoriteId, ":global"); + + } else if (actionId == "_kicker_favorite_remove_from_activity") { + console.log("Removing from a specific activity"); + favoriteModel.removeFavoriteFrom(favoriteId, actionArgument.favoriteActivity); + + } else if (actionId == "_kicker_favorite_add_to_activity") { + console.log("Adding to another activity"); + favoriteModel.addFavoriteTo(favoriteId, actionArgument.favoriteActivity); + + } else if (actionId == "_kicker_favorite_set_to_activity") { + console.log("Removing the item from the favourites, and re-adding it just to be on a specific activity"); + favoriteModel.setFavoriteOn(favoriteId, actionArgument.favoriteActivity); + + } + } else { + if (actionId == "_kicker_favorite_remove") { + favoriteModel.removeFavorite(favoriteId); + } else if (actionId == "_kicker_favorite_add") { + favoriteModel.addFavorite(favoriteId); + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/config/config.qml b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/config/config.qml new file mode 100644 index 00000000..51d62c03 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/config/config.qml @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2014 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.0 + +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n("General") + icon: "kde" + source: "ConfigGeneral.qml" + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/config/main.xml b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/config/main.xml new file mode 100644 index 00000000..89938785 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/config/main.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + Center + + + + start-here-kde + + + false + + + + + + + true + + + + 0 + + + false + + + + 6 + + + + 4 + + + + preferred://browser,kontact.desktop,systemsettings.desktop,org.kde.dolphin.desktop,ktp-contactlist.desktop,org.kde.kate.desktop + + + logout,lock-screen,reboot,shutdown + + + + + + + true + + + true + + + bookmarks,baloosearch + + + true + + + + true + + + + muon-discover --application + + + true + + + false + + + + false + + + + true + + + diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/fr/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/fr/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo new file mode 100644 index 00000000..2a7afff3 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/fr/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/ko/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/ko/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo new file mode 100644 index 00000000..d6767a50 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/ko/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/nl/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/nl/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo new file mode 100644 index 00000000..3407f0a1 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/nl/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/pl/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/pl/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo new file mode 100644 index 00000000..6cfe3a31 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/pl/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/pt_BR/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/pt_BR/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo new file mode 100644 index 00000000..20eb7030 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/pt_BR/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/ru/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/ru/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo new file mode 100644 index 00000000..5928c476 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/ru/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/template/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/template/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo new file mode 100644 index 00000000..442541d1 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/template/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/tr/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/tr/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo new file mode 100644 index 00000000..06201682 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/locale/tr/LC_MESSAGES/plasma_applet_org.kde.plasma.dittomenu.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ActionMenu.qml b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ActionMenu.qml new file mode 100644 index 00000000..5109aef6 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ActionMenu.qml @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (C) 2013 by Aurélien Gâteau * + * Copyright (C) 2014-2015 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.0 + +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item { + id: root + + property QtObject menu + property Item visualParent + property variant actionList + property bool opened: menu ? (menu.status != PlasmaComponents.DialogStatus.Closed) : false + + signal actionClicked(string actionId, variant actionArgument) + signal closed + + onActionListChanged: refreshMenu(); + + onOpenedChanged: { + if (!opened) { + closed(); + } + } + + function open(x, y) { + if (!actionList) { + return; + } + + if (x && y) { + menu.open(x, y); + } else { + menu.open(); + } + } + + function refreshMenu() { + if (menu) { + menu.destroy(); + } + + if (!actionList) { + return; + } + + menu = contextMenuComponent.createObject(root); + + fillMenu(menu, actionList); + } + + function fillMenu(menu, items) { + items.forEach(function(actionItem) { + if (actionItem.subActions) { + // This is a menu + var submenuItem = contextSubmenuItemComponent.createObject( + menu, { "actionItem" : actionItem }); + + fillMenu(submenuItem.submenu, actionItem.subActions); + + } else { + var item = contextMenuItemComponent.createObject( + menu, + { + "actionItem": actionItem, + } + ); + } + }); + + } + + Component { + id: contextMenuComponent + + PlasmaComponents.ContextMenu { + visualParent: root.visualParent + } + } + + Component { + id: contextSubmenuItemComponent + + PlasmaComponents.MenuItem { + id: submenuItem + + property variant actionItem + + text: actionItem.text ? actionItem.text : "" + icon: actionItem.icon ? actionItem.icon : null + + property variant submenu : submenu_ + + PlasmaComponents.ContextMenu { + id: submenu_ + visualParent: submenuItem.action + } + } + } + + Component { + id: contextMenuItemComponent + + PlasmaComponents.MenuItem { + property variant actionItem + + text : actionItem.text ? actionItem.text : "" + enabled : actionItem.type != "title" && ("enabled" in actionItem ? actionItem.enabled : true) + separator : actionItem.type == "separator" + section : actionItem.type == "title" + icon : actionItem.icon ? actionItem.icon : null + checkable : actionItem.checkable ? actionItem.checkable : false + checked : actionItem.checked ? actionItem.checked : false + + onClicked: { + actionClicked(actionItem.actionId, actionItem.actionArgument); + } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/CompactRepresentation.qml b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/CompactRepresentation.qml new file mode 100644 index 00000000..eae3665f --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/CompactRepresentation.qml @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (C) 2013-2014 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Layouts 1.1 + +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore + +Item { + id: root + + readonly property var screenGeometry: plasmoid.screenGeometry + readonly property bool inPanel: (plasmoid.location == PlasmaCore.Types.TopEdge + || plasmoid.location == PlasmaCore.Types.RightEdge + || plasmoid.location == PlasmaCore.Types.BottomEdge + || plasmoid.location == PlasmaCore.Types.LeftEdge) + readonly property bool vertical: (plasmoid.formFactor == PlasmaCore.Types.Vertical) + readonly property bool useCustomButtonImage: (plasmoid.configuration.useCustomButtonImage + && plasmoid.configuration.customButtonImage.length != 0) + property QtObject dashWindow: null + + Plasmoid.status: dashWindow && dashWindow.visible ? PlasmaCore.Types.RequiresAttentionStatus : PlasmaCore.Types.PassiveStatus + + onWidthChanged: updateSizeHints() + onHeightChanged: updateSizeHints() + + function updateSizeHints() { + if (useCustomButtonImage) { + if (vertical) { + var scaledHeight = Math.floor(parent.width * (buttonIcon.implicitHeight / buttonIcon.implicitWidth)); + root.Layout.minimumHeight = scaledHeight; + root.Layout.maximumHeight = scaledHeight; + root.Layout.minimumWidth = PlasmaCore.Units.iconSizes.small; + root.Layout.maximumWidth = inPanel ? PlasmaCore.Units.iconSizeHints.panel : -1; + } else { + var scaledWidth = Math.floor(parent.height * (buttonIcon.implicitWidth / buttonIcon.implicitHeight)); + root.Layout.minimumWidth = scaledWidth; + root.Layout.maximumWidth = scaledWidth; + root.Layout.minimumHeight = PlasmaCore.Units.iconSizes.small; + root.Layout.maximumHeight = inPanel ? PlasmaCore.Units.iconSizeHints.panel : -1; + } + } else { + root.Layout.minimumWidth = PlasmaCore.Units.iconSizes.small; + root.Layout.maximumWidth = inPanel ? PlasmaCore.Units.iconSizeHints.panel : -1; + root.Layout.minimumHeight = PlasmaCore.Units.iconSizes.small + root.Layout.maximumHeight = inPanel ? PlasmaCore.Units.iconSizeHints.panel : -1; + } + } + + Connections { + target: PlasmaCore.Units.iconSizeHints + function onPanelChanged(){ updateSizeHints()} + } + + PlasmaCore.IconItem { + id: buttonIcon + + anchors.fill: parent + + readonly property double aspectRatio: (vertical ? implicitHeight / implicitWidth + : implicitWidth / implicitHeight) + + source: useCustomButtonImage ? plasmoid.configuration.customButtonImage : plasmoid.configuration.icon + + active: mouseArea.containsMouse + + smooth: true + + // A custom icon could also be rectangular. However, if a square, custom, icon is given, assume it + // to be an icon and round it to the nearest icon size again to avoid scaling artefacts. + roundToIconSize: !useCustomButtonImage || aspectRatio === 1 + + onSourceChanged: updateSizeHints() + } + + MouseArea + { + id: mouseArea + + anchors.fill: parent + + hoverEnabled: true + + onClicked: { + dashWindow.visible = !dashWindow.visible; + } + } + + Component.onCompleted: { + dashWindow = Qt.createQmlObject("MenuRepresentation {}", root); + plasmoid.activated.connect(function() { + dashWindow.visible = !dashWindow.visible; + }); + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ConfigGeneral.qml b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ConfigGeneral.qml new file mode 100644 index 00000000..35419303 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ConfigGeneral.qml @@ -0,0 +1,212 @@ +/*************************************************************************** + * Copyright (C) 2014 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.0 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons +import org.kde.draganddrop 2.0 as DragDrop + +import org.kde.kirigami 2.4 as Kirigami + + +Kirigami.FormLayout { + id: configGeneral + + + property string cfg_icon: plasmoid.configuration.icon + property bool cfg_useCustomButtonImage: plasmoid.configuration.useCustomButtonImage + property string cfg_customButtonImage: plasmoid.configuration.customButtonImage + + //property alias cfg_appNameFormat: appNameFormat.currentIndex + //property alias cfg_switchCategoriesOnHover: switchCategoriesOnHover.checked + + //property alias cfg_useExtraRunners: useExtraRunners.checked + + property alias cfg_numberColumns: numberColumns.value + property alias cfg_numberRows: numberRows.value + property alias cfg_showFavoritesFirst: showFavoritesFirst.checked + + + property alias cfg_labels2lines: labels2lines.checked + property alias cfg_displayPosition: displayPosition.currentIndex + + + RowLayout { + spacing: PlasmaCore.Units.smallSpacing + Kirigami.FormData.label: i18n("Icon:") + + + Button { + id: iconButton + Layout.minimumWidth: previewFrame.width + PlasmaCore.Units.smallSpacing * 2 + Layout.maximumWidth: Layout.minimumWidth + Layout.minimumHeight: previewFrame.height + PlasmaCore.Units.smallSpacing * 2 + Layout.maximumHeight: Layout.minimumWidth + + DragDrop.DropArea { + id: dropArea + + property bool containsAcceptableDrag: false + + anchors.fill: parent + + onDragEnter: { + // Cannot use string operations (e.g. indexOf()) on "url" basic type. + var urlString = event.mimeData.url.toString(); + + // This list is also hardcoded in KIconDialog. + var extensions = [".png", ".xpm", ".svg", ".svgz"]; + containsAcceptableDrag = urlString.indexOf("file:///") === 0 && extensions.some(function (extension) { + return urlString.indexOf(extension) === urlString.length - extension.length; // "endsWith" + }); + + if (!containsAcceptableDrag) { + event.ignore(); + } + } + onDragLeave: containsAcceptableDrag = false + + onDrop: { + if (containsAcceptableDrag) { + // Strip file:// prefix, we already verified in onDragEnter that we have only local URLs. + iconDialog.setCustomButtonImage(event.mimeData.url.toString().substr("file://".length)); + } + containsAcceptableDrag = false; + } + } + + KQuickAddons.IconDialog { + id: iconDialog + + function setCustomButtonImage(image) { + cfg_customButtonImage = image || cfg_icon || "start-here-kde" + cfg_useCustomButtonImage = true; + } + + onIconNameChanged: setCustomButtonImage(iconName); + } + + // just to provide some visual feedback, cannot have checked without checkable enabled + checkable: true + checked: dropArea.containsAcceptableDrag + onClicked: { + checked = Qt.binding(function() { // never actually allow it being checked + return iconMenu.status === PlasmaComponents.DialogStatus.Open || dropArea.containsAcceptableDrag; + }) + + iconMenu.open(0, height) + } + + PlasmaCore.FrameSvgItem { + id: previewFrame + anchors.centerIn: parent + imagePath: plasmoid.location === PlasmaCore.Types.Vertical || plasmoid.location === PlasmaCore.Types.Horizontal + ? "widgets/panel-background" : "widgets/background" + width: PlasmaCore.Units.iconSizes.large + fixedMargins.left + fixedMargins.right + height: PlasmaCore.Units.iconSizes.large + fixedMargins.top + fixedMargins.bottom + + PlasmaCore.IconItem { + anchors.centerIn: parent + width: PlasmaCore.Units.iconSizes.large + height: width + source: cfg_useCustomButtonImage ? cfg_customButtonImage : cfg_icon + } + } + } + + // QQC Menu can only be opened at cursor position, not a random one + PlasmaComponents.ContextMenu { + id: iconMenu + visualParent: iconButton + + PlasmaComponents.MenuItem { + text: i18nc("@item:inmenu Open icon chooser dialog", "Choose...") + icon: "document-open-folder" + onClicked: iconDialog.open() + } + PlasmaComponents.MenuItem { + text: i18nc("@item:inmenu Reset icon to default", "Clear Icon") + icon: "edit-clear" + onClicked: { + cfg_useCustomButtonImage = false; + } + } + } + } + + + CheckBox { + id: showFavoritesFirst + Kirigami.FormData.label: i18n("Show favorites first") + } + + ComboBox { + Kirigami.FormData.label: i18n("Menu position") + id: displayPosition + model: [ + i18n("Default"), + i18n("Center"), + i18n("Center bottom"), + ] + onActivated: cfg_displayPosition = currentIndex + } + + + CheckBox { + id: labels2lines + text: i18n("Show labels in two lines") + } + + SpinBox{ + id: numberColumns + minimumValue: 4 + maximumValue: 10 + Kirigami.FormData.label: i18n("Number of columns") + + } + + SpinBox{ + id: numberRows + minimumValue: 1 + maximumValue: 10 + Kirigami.FormData.label: i18n("Number of rows") + } + + RowLayout{ + + //Layout.fillWidth: true + Button { + text: i18n("Unhide all hidden applications") + onClicked: { + plasmoid.configuration.hiddenApplications = [""]; + unhideAllAppsPopup.text = i18n("Unhidden!"); + } + } + Label { + id: unhideAllAppsPopup + } + } + +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ItemGridDelegate.qml b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ItemGridDelegate.qml new file mode 100644 index 00000000..533f25c0 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ItemGridDelegate.qml @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (C) 2015 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.0 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +import "../code/tools.js" as Tools + +Item { + id: item + + width: GridView.view.cellWidth + height: GridView.view.cellHeight + + property bool showLabel: true + + property int itemIndex: model.index + property string favoriteId: model.favoriteId !== undefined ? model.favoriteId : "" + property url url: model.url !== undefined ? model.url : "" + property variant icon: model.decoration !== undefined ? model.decoration : "" + property var m: model + property bool hasActionList: ((model.favoriteId !== null) + || (("hasActionList" in model) && (model.hasActionList === true))) + + Accessible.role: Accessible.MenuItem + Accessible.name: model.display + + function openActionMenu(x, y) { + var actionList = hasActionList ? model.actionList : []; + Tools.fillActionMenu(i18n, actionMenu, actionList, GridView.view.model.favoritesModel, model.favoriteId); + actionMenu.visualParent = item; + actionMenu.open(x, y); + } + + function actionTriggered(actionId, actionArgument) { + var close = (Tools.triggerAction(plasmoid, GridView.view.model, model.index, actionId, actionArgument) === true); + if (close) root.toggle(); + } + + Item{ + height: iconSize + PlasmaCore.Units.gridUnit * 2 + PlasmaCore.Units.smallSpacing + width: parent.width + anchors.centerIn: parent + + PlasmaCore.IconItem { + id: icon + anchors{ + top: parent.top + horizontalCenter: parent.horizontalCenter + } + width: root.iconSize + height: width + colorGroup: PlasmaCore.Theme.ComplementaryColorGroup + animated: false + usesPlasmaTheme: item.GridView.view.usesPlasmaTheme + source: model.decoration + } + + PlasmaComponents.Label { + id: label + visible: showLabel + anchors { + top: icon.bottom + topMargin: PlasmaCore.Units.smallSpacing + horizontalCenter: parent.horizontalCenter + } + maximumLineCount: plasmoid.configuration.labels2lines ? 2 : 1 + horizontalAlignment: Text.AlignHCenter + width: parent.width - PlasmaCore.Units.largeSpacing + height: PlasmaCore.Units.gridUnit * 2 + elide: Text.ElideRight + wrapMode: Text.Wrap + color: theme.textColor + text: ("name" in model ? model.name : model.display) + } + } + PlasmaCore.ToolTipArea { + id: toolTip + property string text: model.display + anchors.fill: parent + active: root.visible && label.truncated + mainItem: toolTipDelegate + onContainsMouseChanged: item.GridView.view.itemContainsMouseChanged(containsMouse) + } + + Keys.onPressed: { + if (event.key === Qt.Key_Menu && hasActionList) { + event.accepted = true; + openActionMenu(item); + } else if ((event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) { + event.accepted = true; + if ("trigger" in GridView.view.model) { + GridView.view.model.trigger(index, "", null); + root.toggle(); + } + + itemGrid.itemActivated(index, "", null); + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ItemGridView.qml b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ItemGridView.qml new file mode 100644 index 00000000..aefb9e9f --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ItemGridView.qml @@ -0,0 +1,485 @@ +/*************************************************************************** + * Copyright (C) 2015 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.4 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtras +import org.kde.kquickcontrolsaddons 2.0 +import org.kde.draganddrop 2.0 +import QtQuick.Controls 2.12 + +FocusScope { + id: itemGrid + + signal keyNavLeft + signal keyNavRight + signal keyNavUp + signal keyNavDown + + signal itemActivated(int index, string actionId, string argument) + + property bool dragEnabled: false + property bool dropEnabled: false + property bool showLabels: true + property alias usesPlasmaTheme: gridView.usesPlasmaTheme + + property alias currentIndex: gridView.currentIndex + property alias currentItem: gridView.currentItem + property alias contentItem: gridView.contentItem + property alias count: gridView.count + property alias model: gridView.model + + property alias cellWidth: gridView.cellWidth + property alias cellHeight: gridView.cellHeight + property alias iconSize: gridView.iconSize + property alias scrollBar: scrollArea + + //<>property alias horizontalScrollBarPolicy: scrollArea.horizontalScrollBarPolicy + //<>property alias verticalScrollBarPolicy: scrollArea.verticalScrollBarPolicy + + onDropEnabledChanged: { + if (!dropEnabled && "dropPlaceHolderIndex" in model) { + model.dropPlaceHolderIndex = -1; + } + } + + onFocusChanged: { + if (!focus) { + currentIndex = -1; + } + } + + function currentRow() { + if (currentIndex == -1) { + return -1; + } + + return Math.floor(currentIndex / Math.floor(width / itemGrid.cellWidth)); + } + + function currentCol() { + if (currentIndex == -1) { + return -1; + } + + return currentIndex - (currentRow() * Math.floor(width / itemGrid.cellWidth)); + } + + function lastRow() { + var columns = Math.floor(width / itemGrid.cellWidth); + return Math.ceil(count / columns) - 1; + } + + function tryActivate(row, col) { + if (count) { + var columns = Math.floor(width / itemGrid.cellWidth); + var rows = Math.ceil(count / columns); + row = Math.min(row, rows - 1); + col = Math.min(col, columns - 1); + currentIndex = Math.min(row ? ((Math.max(1, row) * columns) + col) + : col, + count - 1); + + focus = true; + } + } + + function forceLayout() { + gridView.forceLayout(); + } + + ActionMenu { + id: actionMenu + + onActionClicked: { + visualParent.actionTriggered(actionId, actionArgument); + } + } + + DropArea { + id: dropArea + + anchors.fill: parent + + onDragMove: { + if (!itemGrid.dropEnabled || gridView.animating || !kicker.dragSource) { + return; + } + + var x = Math.max(0, event.x - (width % itemGrid.cellWidth)); + var cPos = mapToItem(gridView.contentItem, x, event.y); + var item = gridView.itemAt(cPos.x, cPos.y); + + if (item) { + if (kicker.dragSource.parent === gridView.contentItem) { + if (item !== kicker.dragSource) { + item.GridView.view.model.moveRow(dragSource.itemIndex, item.itemIndex); + } + } else if (kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model + && !itemGrid.model.isFavorite(kicker.dragSource.favoriteId)) { + var hasPlaceholder = (itemGrid.model.dropPlaceholderIndex !== -1); + + itemGrid.model.dropPlaceholderIndex = item.itemIndex; + + if (!hasPlaceholder) { + gridView.currentIndex = (item.itemIndex - 1); + } + } + } else if (kicker.dragSource.parent !== gridView.contentItem + && kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model + && !itemGrid.model.isFavorite(kicker.dragSource.favoriteId)) { + var hasPlaceholder = (itemGrid.model.dropPlaceholderIndex !== -1); + + itemGrid.model.dropPlaceholderIndex = hasPlaceholder ? itemGrid.model.count - 1 : itemGrid.model.count; + + if (!hasPlaceholder) { + gridView.currentIndex = (itemGrid.model.count - 1); + } + } else { + itemGrid.model.dropPlaceholderIndex = -1; + gridView.currentIndex = -1; + } + } + + onDragLeave: { + if ("dropPlaceholderIndex" in itemGrid.model) { + itemGrid.model.dropPlaceholderIndex = -1; + gridView.currentIndex = -1; + } + } + + onDrop: { + if (kicker.dragSource && kicker.dragSource.parent !== gridView.contentItem && kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model) { + itemGrid.model.addFavorite(kicker.dragSource.favoriteId, itemGrid.model.dropPlaceholderIndex); + gridView.currentIndex = -1; + } + } + + Timer { + id: resetAnimationDurationTimer + + interval: 120 + repeat: false + + onTriggered: { + gridView.animationDuration = interval - 20; + } + } + + //PlasmaExtras.ScrollArea + Flickable{ + id: scrollArea + + clip: true + anchors.fill: parent + boundsBehavior: Flickable.StopAtBounds + interactive: false + focus: true + + GridView { + id: gridView + width: itemGrid.width + height: itemGrid.height + + signal itemContainsMouseChanged(bool containsMouse) + + property bool usesPlasmaTheme: false + + property int iconSize: PlasmaCore.Units.iconSizes.huge + + property bool animating: false + property int animationDuration: itemGrid.dropEnabled ? resetAnimationDurationTimer.interval : 0 + + focus: true + snapMode: GridView.SnapToRow + + ScrollBar.vertical: ScrollBar { + visible: true + active: true + policy: ScrollBar.AlwaysOn; + } + + currentIndex: -1 + + move: Transition { + enabled: itemGrid.dropEnabled + + SequentialAnimation { + PropertyAction { target: gridView; property: "animating"; value: true } + + NumberAnimation { + duration: gridView.animationDuration + properties: "x, y" + easing.type: Easing.OutQuad + } + + PropertyAction { target: gridView; property: "animating"; value: false } + } + } + + moveDisplaced: Transition { + enabled: itemGrid.dropEnabled + + SequentialAnimation { + PropertyAction { target: gridView; property: "animating"; value: true } + + NumberAnimation { + duration: gridView.animationDuration + properties: "x, y" + easing.type: Easing.OutQuad + } + + PropertyAction { target: gridView; property: "animating"; value: false } + } + } + + keyNavigationWraps: false + boundsBehavior: Flickable.StopAtBounds + + delegate: ItemGridDelegate { + showLabel: itemGrid.showLabels + } + + highlight: Item { + property bool isDropPlaceHolder: "dropPlaceholderIndex" in itemGrid.model && itemGrid.currentIndex === itemGrid.model.dropPlaceholderIndex + + PlasmaComponents.Highlight { + visible: gridView.currentItem && !isDropPlaceHolder + + anchors.fill: parent + } + + PlasmaCore.FrameSvgItem { + visible: gridView.currentItem && isDropPlaceHolder + + anchors.fill: parent + + imagePath: "widgets/viewitem" + prefix: "selected" + + opacity: 0.5 + + PlasmaCore.IconItem { + anchors { + right: parent.right + rightMargin: parent.margins.right + bottom: parent.bottom + bottomMargin: parent.margins.bottom + } + + width: PlasmaCore.Units.iconSizes.smallMedium + height: width + + source: "list-add" + active: false + } + } + } + + highlightFollowsCurrentItem: true + highlightMoveDuration: 0 + + onCurrentIndexChanged: { + if (currentIndex != -1) { + hoverArea.hoverEnabled = false + focus = true; + } + } + + onCountChanged: { + animationDuration = 0; + resetAnimationDurationTimer.start(); + } + + onModelChanged: { + currentIndex = -1; + } + + Keys.onLeftPressed: { + if (itemGrid.currentCol() !== 0) { + event.accepted = true; + moveCurrentIndexLeft(); + } else { + itemGrid.keyNavLeft(); + } + } + + Keys.onRightPressed: { + var columns = Math.floor(width / cellWidth); + + if (itemGrid.currentCol() !== columns - 1 && currentIndex != count -1) { + event.accepted = true; + moveCurrentIndexRight(); + } else { + itemGrid.keyNavRight(); + } + } + + Keys.onUpPressed: { + if (itemGrid.currentRow() !== 0) { + event.accepted = true; + moveCurrentIndexUp(); + positionViewAtIndex(currentIndex, GridView.Contain); + } else { + itemGrid.keyNavUp(); + } + } + + Keys.onDownPressed: { + if (itemGrid.currentRow() < itemGrid.lastRow()) { + // Fix moveCurrentIndexDown()'s lack of proper spatial nav down + // into partial columns. + event.accepted = true; + var columns = Math.floor(width / cellWidth); + var newIndex = currentIndex + columns; + currentIndex = Math.min(newIndex, count - 1); + positionViewAtIndex(currentIndex, GridView.Contain); + } else { + itemGrid.keyNavDown(); + } + } + + onItemContainsMouseChanged: { + if (!containsMouse) { + if (!actionMenu.opened) { + gridView.currentIndex = -1; + } + + hoverArea.pressX = -1; + hoverArea.pressY = -1; + hoverArea.lastX = -1; + hoverArea.lastY = -1; + hoverArea.pressedItem = null; + hoverArea.hoverEnabled = true; + } + } + } + } + + MouseArea { + id: hoverArea + + //anchors.fill: parent + width: itemGrid.width - PlasmaCore.Units.largeSpacing + height: itemGrid.height + + + property int pressX: -1 + property int pressY: -1 + property int lastX: -1 + property int lastY: -1 + property Item pressedItem: null + + acceptedButtons: Qt.LeftButton | Qt.RightButton + + hoverEnabled: true + + function updatePositionProperties(x, y) { + // Prevent hover event synthesis in QQuickWindow interfering + // with keyboard navigation by ignoring repeated events with + // identical coordinates. As the work done here would be re- + // dundant in any case, these are safe to ignore. + if (lastX === x && lastY === y) { + return; + } + + lastX = x; + lastY = y; + + var cPos = mapToItem(gridView.contentItem, x, y); + var item = gridView.itemAt(cPos.x, cPos.y); + + if (!item) { + gridView.currentIndex = -1; + pressedItem = null; + } else { + gridView.currentIndex = item.itemIndex; + itemGrid.focus = (itemGrid.currentIndex != -1) + } + + return item; + } + + onPressed: mouse => { + mouse.accepted = true; + + updatePositionProperties(mouse.x, mouse.y); + + pressX = mouse.x; + pressY = mouse.y; + + if (mouse.button == Qt.RightButton) { + if (gridView.currentItem) { + if (gridView.currentItem.hasActionList) { + var mapped = mapToItem(gridView.currentItem, mouse.x, mouse.y); + gridView.currentItem.openActionMenu(mapped.x, mapped.y); + } + } else { + var mapped = mapToItem(rootItem, mouse.x, mouse.y); + contextMenu.open(mapped.x, mapped.y); + } + } else { + pressedItem = gridView.currentItem; + } + } + + onReleased: mouse => { + mouse.accepted = true; + updatePositionProperties(mouse.x, mouse.y); + + if (gridView.currentItem && gridView.currentItem == pressedItem) { + if ("trigger" in gridView.model) { + gridView.model.trigger(pressedItem.itemIndex, "", null); + root.toggle(); + } + + itemGrid.itemActivated(pressedItem.itemIndex, "", null); + } else if (!dragHelper.dragging && !pressedItem && mouse.button == Qt.LeftButton) { + root.toggle(); + } + + pressX = -1; + pressY = -1; + pressedItem = null; + } + + onPositionChanged: mouse => { + var item = pressedItem? pressedItem : updatePositionProperties(mouse.x, mouse.y); + + if (gridView.currentIndex != -1) { + if (itemGrid.dragEnabled && pressX != -1 && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { + if ("pluginName" in item.m) { + dragHelper.startDrag(kicker, item.url, item.icon, + "text/x-plasmoidservicename", item.m.pluginName); + } else { + dragHelper.startDrag(kicker, item.url, item.icon); + } + + kicker.dragSource = item; + + pressX = -1; + pressY = -1; + } + } + } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ItemMultiGridView.qml b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ItemMultiGridView.qml new file mode 100644 index 00000000..7bbeb3c1 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/ItemMultiGridView.qml @@ -0,0 +1,210 @@ +/*************************************************************************** + * Copyright (C) 2015 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.4 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.extras 2.0 as PlasmaExtras + +import org.kde.plasma.private.kicker 0.1 as Kicker + +PlasmaExtras.ScrollArea { + id: itemMultiGrid + + //anchors { + // top: parent.top + //} + anchors.fill: parent + + //width: parent.width + + implicitHeight: itemColumn.implicitHeight + + signal keyNavLeft(int subGridIndex) + signal keyNavRight(int subGridIndex) + signal keyNavUp() + signal keyNavDown() + + property bool grabFocus: false + + property alias model: repeater.model + property alias count: repeater.count + + property int aCellHeight + property int aCellWidth + + verticalScrollBarPolicy: Qt.ScrollBarAsNeeded + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + flickableItem.flickableDirection: Flickable.VerticalFlick + + onFocusChanged: { + if (!focus) { + for (var i = 0; i < repeater.count; i++) { + subGridAt(i).focus = false; + } + } + } + + function subGridAt(index) { + return repeater.itemAt(index).itemGrid; + } + + function tryActivate(row, col) { // FIXME TODO: Cleanup messy algo. + if (flickableItem.contentY > 0) { + row = 0; + } + + var target = null; + var rows = 0; + + for (var i = 0; i < repeater.count; i++) { + var grid = subGridAt(i); + + if (rows <= row) { + target = grid; + rows += grid.lastRow() + 2; // Header counts as one. + } else { + break; + } + } + + if (target) { + rows -= (target.lastRow() + 2); + target.tryActivate(row - rows, col); + } + } + + Column { + id: itemColumn + + width: itemMultiGrid.width //- PlasmaCore.Units.gridUnit + + Repeater { + id: repeater + + delegate: Item { + width: itemColumn.width + //height: gridViewLabel.height + gridView.height + (index == repeater.count - 1 ? 0 : PlasmaCore.Units.smallSpacing) + height: gridView.height + //visible: gridView.count > 0 + + property Item itemGrid: gridView + + + + MouseArea { + width: parent.width + height: parent.height + onClicked: root.toggle() + } + + ItemGridView { + id: gridView + + anchors { + top: parent.top + } + + width: parent.width + height: Math.ceil(count / plasmoid.configuration.numberColumns) * root.cellSize + cellWidth: root.cellSize + cellHeight: root.cellSize + iconSize: root.iconSize + //<> verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + model: repeater.model.modelForRow(index) + + onFocusChanged: { + if (focus) { + itemMultiGrid.focus = true; + } + } + + onCountChanged: { + if (itemMultiGrid.grabFocus && index == 0 && count > 0) { + currentIndex = 0; + focus = true; + } + } + + onCurrentItemChanged: { + if (!currentItem) { + return; + } + + if (index == 0 && currentRow() === 0) { + itemMultiGrid.flickableItem.contentY = 0; + return; + } + + var y = currentItem.y; + y = contentItem.mapToItem(itemMultiGrid.flickableItem.contentItem, 0, y).y; + + if (y < itemMultiGrid.flickableItem.contentY) { + itemMultiGrid.flickableItem.contentY = y; + } else { + y += root.cellSize; + y -= itemMultiGrid.flickableItem.contentY; + y -= itemMultiGrid.viewport.height; + + if (y > 0) { + itemMultiGrid.flickableItem.contentY += y; + } + } + } + + onKeyNavLeft: { + itemMultiGrid.keyNavLeft(index); + } + + onKeyNavRight: { + itemMultiGrid.keyNavRight(index); + } + + onKeyNavUp: { + if (index > 0) { + var prevGrid = subGridAt(index - 1); + prevGrid.tryActivate(prevGrid.lastRow(), currentCol()); + } else { + itemMultiGrid.keyNavUp(); + } + } + + onKeyNavDown: { + if (index < repeater.count - 1) { + subGridAt(index + 1).tryActivate(0, currentCol()); + } else { + itemMultiGrid.keyNavDown(); + } + } + } + + // HACK: Steal wheel events from the nested grid view and forward them to + // the ScrollView's internal WheelArea. + Kicker.WheelInterceptor { + anchors.fill: gridView + z: 1 + + destination: findWheelArea(itemMultiGrid.flickableItem) + } + } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/MenuRepresentation.qml b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/MenuRepresentation.qml new file mode 100644 index 00000000..2c5a1bf7 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/MenuRepresentation.qml @@ -0,0 +1,681 @@ +/*************************************************************************** + * Copyright (C) 2014 by Weng Xuetian + * Copyright (C) 2013-2017 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.components 3.0 as PlasmaComponents3 + +import org.kde.plasma.extras 2.0 as PlasmaExtras + +import org.kde.plasma.private.kicker 0.1 as Kicker +import org.kde.kcoreaddons 1.0 as KCoreAddons // kuser +import org.kde.plasma.private.shell 2.0 + +import org.kde.kwindowsystem 1.0 +import QtGraphicalEffects 1.0 +import org.kde.kquickcontrolsaddons 2.0 +import org.kde.plasma.private.quicklaunch 1.0 +import QtQuick.Controls 2.12 + +Item{ + + id: main + property int sizeImage: PlasmaCore.Units.iconSizes.large * 2 + + onVisibleChanged: { + root.visible = !root.visible + } + + PlasmaCore.Dialog { + id: root + + objectName: "popupWindow" + //flags: Qt.Window + flags: Qt.WindowStaysOnTopHint + location: PlasmaCore.Types.Floating + hideOnWindowDeactivate: true + + property int iconSize: PlasmaCore.Units.iconSizes.large + property int cellSize: iconSize + + PlasmaCore.Units.gridUnit * 2 + + (2 * Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom, + highlightItemSvg.margins.left + highlightItemSvg.margins.right)) + property bool searching: (searchField.text != "") + + property bool showFavorites + + onVisibleChanged: { + + if (visible) { + root.showFavorites = plasmoid.configuration.showFavoritesFirst + var pos = popupPosition(width, height); + x = pos.x; + y = pos.y; + requestActivate(); + reset(); + animation1.start() + + }else{ + rootItem.opacity = 0 + } + } + + onHeightChanged: { + var pos = popupPosition(width, height); + x = pos.x; + y = pos.y; + } + + onWidthChanged: { + var pos = popupPosition(width, height); + x = pos.x; + y = pos.y; + } + + function toggle(){ + main.visible = !main.visible + } + + function reset() { + searchField.text = ""; + + if(showFavorites) + globalFavoritesGrid.tryActivate(0,0) + else + mainColumn.visibleGrid.tryActivate(0,0) + + + } + + function popupPosition(width, height) { + var screenAvail = plasmoid.availableScreenRect; + var screenGeom = plasmoid.screenGeometry; + + var screen = Qt.rect(screenAvail.x + screenGeom.x, + screenAvail.y + screenGeom.y, + screenAvail.width, + screenAvail.height); + + + var offset = PlasmaCore.Units.smallSpacing + + // Fall back to bottom-left of screen area when the applet is on the desktop or floating. + var x = offset; + var y = screen.height - height - offset; + var appletTopLeft; + var horizMidPoint; + var vertMidPoint; + + + if (plasmoid.configuration.displayPosition === 1) { + horizMidPoint = screen.x + (screen.width / 2); + vertMidPoint = screen.y + (screen.height / 2); + x = horizMidPoint - width / 2; + y = vertMidPoint - height / 2; + } else if (plasmoid.configuration.displayPosition === 2) { + horizMidPoint = screen.x + (screen.width / 2); + vertMidPoint = screen.y + (screen.height / 2); + x = horizMidPoint - width / 2; + y = screen.y + screen.height - height - offset - panelSvg.margins.top; + } else if (plasmoid.location === PlasmaCore.Types.BottomEdge) { + horizMidPoint = screen.x + (screen.width / 2); + appletTopLeft = parent.mapToGlobal(0, 0); + x = (appletTopLeft.x < horizMidPoint) ? screen.x + offset : (screen.x + screen.width) - width - offset; + y = screen.y + screen.height - height - offset - panelSvg.margins.top; + } else if (plasmoid.location === PlasmaCore.Types.TopEdge) { + horizMidPoint = screen.x + (screen.width / 2); + var appletBottomLeft = parent.mapToGlobal(0, parent.height); + x = (appletBottomLeft.x < horizMidPoint) ? screen.x + offset : (screen.x + screen.width) - width - offset; + y = parent.height + panelSvg.margins.bottom + offset; + y = screen.y + y + (plasmoid.configuration.viewUser ? main.sizeImage*0.5 : 0); + } else if (plasmoid.location === PlasmaCore.Types.LeftEdge) { + vertMidPoint = screen.y + (screen.height / 2); + appletTopLeft = parent.mapToGlobal(0, 0); + x = parent.width + panelSvg.margins.right + offset; + y = (appletTopLeft.y < vertMidPoint) ? screen.y + offset : (screen.y + screen.height) - height - offset; + y = screen.y + y + (plasmoid.configuration.viewUser ? main.sizeImage*0.5 : 0); + } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { + vertMidPoint = screen.y + (screen.height / 2); + appletTopLeft = parent.mapToGlobal(0, 0); + x = appletTopLeft.x - panelSvg.margins.left - offset - width; + y = (appletTopLeft.y < vertMidPoint) ? screen.y + offset : (screen.y + screen.height) - height - offset; + y = screen.y + y + (plasmoid.configuration.viewUser ? main.sizeImage*0.5 : 0); + } + return Qt.point(x, y); + } + + FocusScope { + + id: rootItem + Layout.minimumWidth: (root.cellSize * plasmoid.configuration.numberColumns)+ PlasmaCore.Units.largeSpacing + Layout.maximumWidth: (root.cellSize * plasmoid.configuration.numberColumns)+ PlasmaCore.Units.largeSpacing + Layout.minimumHeight: (root.cellSize * plasmoid.configuration.numberRows) + searchField.implicitHeight + (plasmoid.configuration.viewUser ? main.sizeImage*0.5 : PlasmaCore.Units.largeSpacing * 1.5 ) + PlasmaCore.Units.largeSpacing * 6 + Layout.maximumHeight: (root.cellSize * plasmoid.configuration.numberRows) + searchField.implicitHeight + (plasmoid.configuration.viewUser ? main.sizeImage*0.5 : PlasmaCore.Units.largeSpacing * 1.5 ) + PlasmaCore.Units.largeSpacing * 6 + + + focus: true + opacity: 0 + + KCoreAddons.KUser { id: kuser } + Logic { id: logic } + + + OpacityAnimator { id: animation1; target: rootItem; from: 0; to: 1; } + + PlasmaCore.DataSource { + id: pmEngine + engine: "powermanagement" + connectedSources: ["PowerDevil", "Sleep States"] + function performOperation(what) { + var service = serviceForSource("PowerDevil") + var operation = service.operationDescription(what) + service.startOperationCall(operation) + } + } + + PlasmaCore.DataSource { + id: executable + engine: "executable" + connectedSources: [] + onNewData: { + var exitCode = data["exit code"] + var exitStatus = data["exit status"] + var stdout = data["stdout"] + var stderr = data["stderr"] + exited(sourceName, exitCode, exitStatus, stdout, stderr) + disconnectSource(sourceName) + } + function exec(cmd) { + if (cmd) { + connectSource(cmd) + } + } + signal exited(string cmd, int exitCode, int exitStatus, string stdout, string stderr) + } + + PlasmaComponents.Highlight { + id: delegateHighlight + visible: false + z: -1 // otherwise it shows ontop of the icon/label and tints them slightly + } + + PlasmaExtras.Heading { + id: dummyHeading + visible: false + width: 0 + level: 5 + } + + TextMetrics { + id: headingMetrics + font: dummyHeading.font + } + + ActionMenu { + id: actionMenu + onActionClicked: visualParent.actionTriggered(actionId, actionArgument) + } + + PlasmaCore.FrameSvgItem { + id : headingSvg + width: parent.width + backgroundSvg.margins.right + backgroundSvg.margins.left + height: root.cellSize * plasmoid.configuration.numberRows + PlasmaCore.Units.largeSpacing * 2 + backgroundSvg.margins.bottom - 1 //<>+ paginationBar.height + y: globalFavoritesGrid.y - PlasmaCore.Units.largeSpacing + x: - backgroundSvg.margins.left + imagePath: "widgets/plasmoidheading" + prefix: "footer" + opacity: 0.7 + } + + RowLayout{ + id: rowTop + anchors { + left: parent.left + right: parent.right + top: parent.top + margins: PlasmaCore.Units.smallSpacing + topMargin: PlasmaCore.Units.largeSpacing / 2 + } + + PlasmaComponents3.ToolButton { + icon.name: "configure" + onClicked: logic.openUrl("file:///usr/share/applications/systemsettings.desktop") + ToolTip.delay: 200 + ToolTip.timeout: 1000 + ToolTip.visible: hovered + ToolTip.text: i18n("System Preferences") + } + + Item{ + Layout.fillWidth: true + } + + PlasmaComponents3.ToolButton { + icon.name: "user-home" + onClicked: logic.openUrl("file:///usr/share/applications/org.kde.dolphin.desktop") + ToolTip.delay: 200 + ToolTip.timeout: 1000 + ToolTip.visible: hovered + ToolTip.text: i18n("User Home") + } + + PlasmaComponents3.ToolButton { + icon.name: "system-lock-screen" + onClicked: pmEngine.performOperation("lockScreen") + enabled: pmEngine.data["Sleep States"]["LockScreen"] + ToolTip.delay: 200 + ToolTip.timeout: 1000 + ToolTip.visible: hovered + ToolTip.text: i18n("Lock Screen") + } + + PlasmaComponents3.ToolButton { + icon.name: "system-shutdown" + onClicked: pmEngine.performOperation("requestShutDown") + ToolTip.delay: 200 + ToolTip.timeout: 1000 + ToolTip.visible: hovered + ToolTip.text: i18n("Leave ...") + } + } + + PlasmaExtras.Heading { + anchors { + top: rowTop.bottom + topMargin: PlasmaCore.Units.largeSpacing + horizontalCenter: parent.horizontalCenter + } + level: 1 + color: theme.textColor + text: i18n("Hi, ")+ kuser.fullName + font.bold: true + visible: plasmoid.configuration.viewUser + } + + RowLayout { + id: rowSearchField + anchors{ + top: plasmoid.configuration.viewUser ? parent.top : rowTop.bottom + topMargin: plasmoid.configuration.viewUser ? PlasmaCore.Units.largeSpacing*3 + sizeImage/2 : PlasmaCore.Units.largeSpacing/2 + left: parent.left + right: parent.right + margins: PlasmaCore.Units.smallSpacing + } + + Item{ + Layout.fillWidth: true + } + PlasmaComponents3.TextField { + id: searchField + Layout.fillWidth: true + placeholderText: i18n("Type here to search ...") + leftPadding: PlasmaCore.Units.largeSpacing + PlasmaCore.Units.iconSizes.small + text: "" + //clearButtonShown: true // TODO: kubuntu 20.04 + onTextChanged: { + runnerModel.query = text; + } + + Keys.onPressed: { + if (event.key === Qt.Key_Escape) { + event.accepted = true; + if(root.searching){ + searchField.clear() + } else { + root.toggle() + } + } + + if (event.key === Qt.Key_Down || event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab) { + event.accepted = true; + if(root.showFavorites) + globalFavoritesGrid.tryActivate(0,0) + else + mainColumn.visibleGrid.tryActivate(0,0) + } + } + + function backspace() { + if (!root.visible) { + return; + } + focus = true; + text = text.slice(0, -1); + } + + function appendText(newText) { + if (!root.visible) { + return; + } + focus = true; + text = text + newText; + } + PlasmaCore.IconItem { + source: 'search' + anchors { + left: searchField.left + verticalCenter: searchField.verticalCenter + leftMargin: PlasmaCore.Units.smallSpacing * 2 + + } + height: PlasmaCore.Units.iconSizes.small + width: height + } + + } + + Item{ + Layout.fillWidth: true + } + + PlasmaComponents3.ToolButton { + id: btnFavorites + icon.name: 'favorites' + flat: !root.showFavorites + onClicked: { + searchField.text = "" + root.showFavorites = true + } + ToolTip.delay: 200 + ToolTip.timeout: 1000 + ToolTip.visible: hovered + ToolTip.text: i18n("Favorites") + + } + PlasmaComponents3.ToolButton { + icon.name: "view-list-icons" + flat: root.showFavorites + onClicked: { + searchField.text = "" + root.showFavorites = false + //<>allAppsGrid.scrollBar.flickableItem.contentY = 0; + } + ToolTip.delay: 200 + ToolTip.timeout: 1000 + ToolTip.visible: hovered + ToolTip.text: i18n("All apps") + } + } + + // + // + // + // + // + + ItemGridView { + id: globalFavoritesGrid + visible: (plasmoid.configuration.showFavoritesFirst || root.showFavorites ) && !root.searching && root.showFavorites + anchors { + top: rowSearchField.bottom + topMargin: PlasmaCore.Units.largeSpacing * 2 + left: parent.left + right: parent.right + } + + width: root.cellSize * plasmoid.configuration.numberColumns + PlasmaCore.Units.largeSpacing + height: root.cellSize * plasmoid.configuration.numberRows + focus: true + cellWidth: root.cellSize + cellHeight: root.cellSize + iconSize: root.iconSize + dragEnabled: true + dropEnabled: true + usesPlasmaTheme: true + + onKeyNavUp: searchField.focus = true + Keys.onPressed: { + if(event.modifiers & Qt.ControlModifier ||event.modifiers & Qt.ShiftModifier){ + searchField.focus = true; + return + } + if (event.key === Qt.Key_Tab) { + event.accepted = true; + searchField.focus = true + } + } + } + + // + // + // + // + // + + Item{ + id: mainGrids + visible: (!plasmoid.configuration.showFavoritesFirst && !root.showFavorites ) || root.searching || !root.showFavorites //TODO + + anchors { + top: rowSearchField.bottom + topMargin: PlasmaCore.Units.largeSpacing * 2 + left: parent.left + right: parent.right + + } + width: root.cellSize * plasmoid.configuration.numberColumns + PlasmaCore.Units.largeSpacing + height: root.cellSize * plasmoid.configuration.numberRows + + Item { + id: mainColumn + width: root.cellSize * plasmoid.configuration.numberColumns + PlasmaCore.Units.largeSpacing + height: root.cellSize * plasmoid.configuration.numberRows + + property Item visibleGrid: allAppsGrid + + function tryActivate(row, col) { + if (visibleGrid) { + visibleGrid.tryActivate(row, col); + } + } + + ItemGridView { + id: allAppsGrid + + width: root.cellSize * plasmoid.configuration.numberColumns + PlasmaCore.Units.largeSpacing + height: root.cellSize * plasmoid.configuration.numberRows + + cellWidth: root.cellSize + cellHeight: root.cellSize + iconSize: root.iconSize + enabled: (opacity == 1) ? 1 : 0 + dropEnabled: false + dragEnabled: false + opacity: root.searching ? 0 : 1 + + onOpacityChanged: { + if (opacity == 1) { + //allAppsGrid.scrollBar.flickableItem.contentY = 0; + mainColumn.visibleGrid = allAppsGrid; + } + } + onKeyNavUp: searchField.focus = true + } + + ItemMultiGridView { + id: runnerGrid + width: root.cellSize * plasmoid.configuration.numberColumns + PlasmaCore.Units.largeSpacing + height: root.cellSize * plasmoid.configuration.numberRows + z: (opacity == 1.0) ? 1 : 0 + aCellWidth: parent.width - PlasmaCore.Units.largeSpacing + aCellHeight: root.cellSize + enabled: (opacity == 1.0) ? 1 : 0 + model: runnerModel + grabFocus: true + opacity: root.searching ? 1.0 : 0.0 + onOpacityChanged: { + if (opacity == 1.0) { + mainColumn.visibleGrid = runnerGrid; + } + } + onKeyNavUp: searchField.focus = true + } + + Keys.onPressed: { + if(event.modifiers & Qt.ControlModifier ||event.modifiers & Qt.ShiftModifier){ + searchField.focus = true; + return + } + if (event.key === Qt.Key_Tab) { + event.accepted = true; + searchField.focus = true + } else if (event.key === Qt.Key_Backspace) { + event.accepted = true; + if(root.searching) + searchField.backspace(); + else + searchField.focus = true + } else if (event.key === Qt.Key_Escape) { + event.accepted = true; + if(root.searching){ + searchField.clear() + } else { + root.toggle() + } + } else if (event.text !== "") { + event.accepted = true; + searchField.appendText(event.text); + } + } + } + } + + + + + Keys.onPressed: { + if(event.modifiers & Qt.ControlModifier ||event.modifiers & Qt.ShiftModifier){ + searchField.focus = true; + return + } + if (event.key === Qt.Key_Escape) { + event.accepted = true; + if (root.searching) { + reset(); + } else { + root.visible = false; + } + return; + } + + if (searchField.focus) { + return; + } + + if (event.key === Qt.Key_Backspace) { + event.accepted = true; + searchField.backspace(); + } else if (event.text !== "") { + event.accepted = true; + searchField.appendText(event.text); + } + } + + } + + function setModels(){ + globalFavoritesGrid.model = globalFavorites + allAppsGrid.model = rootModel.modelForRow(0); + } + + Component.onCompleted: { + rootModel.refreshed.connect(setModels) + reset(); + rootModel.refresh(); + } + } + + + + PlasmaCore.Dialog { + id: dialog + + width: main.sizeImage + height: width + + visible: root.visible + + y: root.y - sizeImage/2 + x: root.x + root.width/2 - sizeImage/2 + + objectName: "popupWindowIcon" + //flags: Qt.WindowStaysOnTopHint + type: "Notification" + location: PlasmaCore.Types.Floating + + hideOnWindowDeactivate: false + backgroundHints: PlasmaCore.Dialog.NoBackground + + mainItem: Rectangle{ + width: main.sizeImage + height: width + color: 'transparent' + + Image { + id: iconUser + //anchors.centerIn: parent + source: kuser.faceIconUrl.toString() || "user-identity" + cache: false + visible: source !== "" && plasmoid.configuration.viewUser + sourceSize.width: main.sizeImage + sourceSize.height: main.sizeImage + + fillMode: Image.PreserveAspectFit + // Crop the avatar to fit in a circle, like the lock and login screens + // but don't on software rendering where this won't render + layer.enabled:true // iconUser.GraphicsInfo.api !== GraphicsInfo.Software + layer.effect: OpacityMask { + // this Rectangle is a circle due to radius size + maskSource: Rectangle { + width: main.sizeImage + height: width + radius: height / 2 + visible: false + } + } + state: "hide" + states: [ + State { + name: "show" + when: dialog.visible + PropertyChanges { target: iconUser; y: 0; opacity: 1; } + }, + State { + name: "hide" + when: !dialog.visible + PropertyChanges { target: iconUser; y: sizeImage/2 ; opacity: 0; } + } + ] + transitions: Transition { + PropertyAnimation { properties: "opacity,y"; easing.type: Easing.InOutQuad; } + } + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + onClicked: KCMShell.openSystemSettings("kcm_users") + visible: KCMShell.authorize("user_manager.desktop").length > 0 + } + } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/main.qml b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/main.qml new file mode 100644 index 00000000..99fe4350 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/contents/ui/main.qml @@ -0,0 +1,195 @@ +/*************************************************************************** + * Copyright (C) 2014-2015 by Eike Hein * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Layouts 1.1 +import org.kde.plasma.plasmoid 2.0 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +import org.kde.plasma.private.kicker 0.1 as Kicker + +Item { + id: kicker + + anchors.fill: parent + + signal reset + + property bool isDash: false + + Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation + + Plasmoid.compactRepresentation: null + Plasmoid.fullRepresentation: compactRepresentation + + property Item dragSource: null + + property QtObject globalFavorites: rootModel.favoritesModel + property QtObject systemFavorites: rootModel.systemFavoritesModel + + function action_menuedit() { + processRunner.runMenuEditor(); + } + + Component { + id: compactRepresentation + CompactRepresentation {} + } + + Component { + id: menuRepresentation + MenuRepresentation {} + } + + readonly property Kicker.RootModel rootModel: Kicker.RootModel { + id: rootModel + + autoPopulate: false + + appNameFormat: plasmoid.configuration.appNameFormat + flat: true + sorted: true + showSeparators: false + appletInterface: plasmoid + showAllApps: true + showRecentApps: false + showRecentDocs: false + showRecentContacts: false + showPowerSession: false + + Component.onCompleted: { + + favoritesModel.initForClient("org.kde.plasma.kickoff.favorites.instance-" + plasmoid.id) + + if (!plasmoid.configuration.favoritesPortedToKAstats) { + if (favoritesModel.count < 1) { + favoritesModel.portOldFavorites(plasmoid.configuration.favorites); + } + plasmoid.configuration.favoritesPortedToKAstats = true; + } + } + } + + Connections { + target: globalFavorites + + function onFavoritesChanged () { + plasmoid.configuration.favoriteApps = target.favorites; + } + } + + Connections { + target: systemFavorites + + function onFavoritesChanged() { + plasmoid.configuration.favoriteSystemActions = target.favorites; + } + } + + Connections { + target: plasmoid.configuration + + function onFavoriteAppsChanged () { + globalFavorites.favorites = plasmoid.configuration.favoriteApps; + } + + function onFavoriteSystemActionsChanged () { + systemFavorites.favorites = plasmoid.configuration.favoriteSystemActions; + } + + function onHiddenApplicationsChanged(){ + rootModel.refresh(); // Force refresh on hidden + } + } + + Kicker.RunnerModel { + id: runnerModel + + appletInterface: plasmoid + favoritesModel: globalFavorites + deleteWhenEmpty: false + mergeResults: true + } + + Kicker.DragHelper { + id: dragHelper + } + + Kicker.ProcessRunner { + id: processRunner; + } + + PlasmaCore.FrameSvgItem { + id : highlightItemSvg + + visible: false + + imagePath: "widgets/viewitem" + prefix: "hover" + } + + PlasmaCore.FrameSvgItem { + id : panelSvg + + visible: false + + imagePath: "widgets/panel-background" + } + + PlasmaCore.FrameSvgItem { + id : scrollbarSvg + + visible: false + + imagePath: "widgets/scrollbar" + } + + PlasmaCore.FrameSvgItem { + id : backgroundSvg + + visible: false + + imagePath: "dialogs/background" + } + + + PlasmaComponents.Label { + id: toolTipDelegate + + width: contentWidth + height: contentHeight + + property Item toolTip + + text: (toolTip != null) ? toolTip.text : "" + } + + function resetDragSource() { + dragSource = null; + } + + Component.onCompleted: { + plasmoid.setAction("menuedit", i18n("Edit Applications...")); + + //rootModel.refreshed.connect(reset); + //dragHelper.dropped.connect(resetDragSource); + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/metadata.desktop b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/metadata.desktop new file mode 100644 index 00000000..86bfb944 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/metadata.desktop @@ -0,0 +1,35 @@ +[Desktop Entry] +Name=Ditto Menu +Comment=A configurable launcher menu + +Type=Service +Icon=start-here-kde +X-KDE-ServiceTypes=Plasma/Applet + +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml +X-Plasma-Provides=org.kde.plasma.launchermenu + +X-KDE-PluginInfo-Author=adhe +X-KDE-PluginInfo-Email=adhemarks[at]gmail.com +X-KDE-PluginInfo-Name=org.kde.plasma.dittomenu +X-KDE-PluginInfo-Version=0.30 +X-KDE-PluginInfo-Category=Application Launchers +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL v2+ +X-KDE-PluginInfo-EnabledByDefault=true +X-KDE-PluginInfo-Website=https://store.kde.org/p/1312669/ + +Name[fr]=Ditto Menu +Name[ko]=Ditto 메뉴 +Name[nl]=Ditto-menu +Name[pt_BR]=Ditto Menu +Name[ru]=Ditto Menu +Name[tr]=Ditto Menu +Comment[fr]=Un menu de lancement configurable +Comment[ko]=프로그램 실행기 +Comment[nl]=Een instelbare programmastarter +Comment[pl]=Konfigurowalne menu uruchamiania programów +Comment[pt_BR]=Configuração do Menu Iniciar +Comment[ru]=Настраиваемое меню приложений +Comment[tr]=Yapılandırılabilir bir başlatıcı menüsü diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/ReadMe.md b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/ReadMe.md new file mode 100644 index 00000000..68619525 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/ReadMe.md @@ -0,0 +1,45 @@ +> Version 7 of Zren's i18n scripts. [link](https://github.com/Zren/plasma-applet-tiledmenu) + +With KDE Frameworks v5.37 and above, translations are bundled with the `*.plasmoid` file downloaded from the store. + +## Install Translations + +Go to `~/.local/share/plasma/plasmoids/org.kde.plasma.dittomenu/translate/` and run `sh ./build --restartplasma`. + +## New Translations + +1. Fill out [`template.pot`](template.pot) with your translations then open a [new issue](https://github.com/Zren/plasma-applet-tiledmenu/issues/new), name the file `spanish.txt`, attach the txt file to the issue (drag and drop). + +Or if you know how to make a pull request + +1. Copy the `template.pot` file and name it your locale's code (Eg: `en`/`de`/`fr`) with the extension `.po`. Then fill out all the `msgstr ""`. + +## Scripts + +* `sh ./merge` will parse the `i18n()` calls in the `*.qml` files and write it to the `template.pot` file. Then it will merge any changes into the `*.po` language files. +* `sh ./build` will convert the `*.po` files to it's binary `*.mo` version and move it to `contents/locale/...` which will bundle the translations in the `*.plasmoid` without needing the user to manually install them. +* `sh ./plasmoidlocaletest` will run `./build` then `plasmoidviewer` (part of `plasma-sdk`). + +## Links + +* https://zren.github.io/kde/docs/widget/#translations-i18n +* https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems +* https://api.kde.org/frameworks/ki18n/html/prg_guide.html + +## Examples + +* https://l10n.kde.org/stats/gui/trunk-kf5/team/fr/plasma-desktop/ +* https://github.com/psifidotos/nowdock-plasmoid/tree/master/po +* https://github.com/kotelnik/plasma-applet-redshift-control/tree/master/translations + +## Status +| Locale | Lines | % Done| +|----------|---------|-------| +| Template | 30 | | +| fr | 29/30 | 96% | +| ko | 27/30 | 90% | +| nl | 20/30 | 66% | +| pl | 22/30 | 73% | +| pt_BR | 30/30 | 100% | +| ru | 30/30 | 100% | +| tr | 23/30 | 76% | diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/build.sh b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/build.sh new file mode 100755 index 00000000..c88cd5d5 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/build.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# Version: 6 + +# This script will convert the *.po files to *.mo files, rebuilding the package/contents/locale folder. +# Feature discussion: https://phabricator.kde.org/D5209 +# Eg: contents/locale/fr_CA/LC_MESSAGES/plasma_applet_org.kde.plasma.eventcalendar.mo + +DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` +plasmoidName=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Name"` +website=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Website"` +bugAddress="$website" +packageRoot=".." # Root of translatable sources +projectName="plasma_applet_${plasmoidName}" # project name + +#--- +if [ -z "$plasmoidName" ]; then + echo "[build] Error: Couldn't read plasmoidName." + exit +fi + +if [ -z "$(which msgfmt)" ]; then + echo "[build] Error: msgfmt command not found. Need to install gettext" + echo "[build] Running 'sudo apt install gettext'" + sudo apt install gettext + echo "[build] gettext installation should be finished. Going back to installing translations." +fi + +#--- +echo "[build] Compiling messages" + +catalogs=`find . -name '*.po' | sort` +for cat in $catalogs; do + echo "$cat" + catLocale=`basename ${cat%.*}` + msgfmt -o "${catLocale}.mo" "$cat" + + installPath="$DIR/../contents/locale/${catLocale}/LC_MESSAGES/${projectName}.mo" + + echo "[build] Install to ${installPath}" + mkdir -p "$(dirname "$installPath")" + mv "${catLocale}.mo" "${installPath}" +done + +echo "[build] Done building messages" + +if [ "$1" = "--restartplasma" ]; then + echo "[build] Restarting plasmashell" + killall plasmashell + kstart5 plasmashell + echo "[build] Done restarting plasmashell" +else + echo "[build] (re)install the plasmoid and restart plasmashell to test." +fi diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/fr.po b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/fr.po new file mode 100644 index 00000000..9099c891 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/fr.po @@ -0,0 +1,140 @@ +# Translation of dittomenu in fr +# Copyright (C) 2023 +# This file is distributed under the same license as the dittomenu package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: dittomenu\n" +"Report-Msgid-Bugs-To: https://store.kde.org/p/1312669/\n" +"POT-Creation-Date: 2023-05-01 16:59-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: omano\n" +"Language-Team: LANGUAGE \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Ditto Menu" +msgstr "Ditto Menu" + +#: ../metadata.desktop +msgid "A configurable launcher menu" +msgstr "Un menu de lancement configurable" + +#: ../contents/code/tools.js +msgid "Remove from Favorites" +msgstr "Enlever des Favoris" + +#: ../contents/code/tools.js +msgid "Add to Favorites" +msgstr "Ajouter aux Favoris" + +#: ../contents/code/tools.js +msgid "On All Activities" +msgstr "Sur toutes les Activités" + +#: ../contents/code/tools.js +msgid "On The Current Activity" +msgstr "Sur l'Activité actuelle" + +#: ../contents/code/tools.js +msgid "Show In Favorites" +msgstr "Voir dans les Favoris" + +#: ../contents/config/config.qml +msgid "General" +msgstr "Général" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Icon:" +msgstr "Icône:" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Open icon chooser dialog" +msgid "Choose..." +msgstr "Choisir..." + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Reset icon to default" +msgid "Clear Icon" +msgstr "Supprimer l'icône" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show favorites first" +msgstr "Voir les Favoris en premier" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Menu position" +msgstr "Position du menu" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Default" +msgstr "Défaut" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center" +msgstr "Centre" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center bottom" +msgstr "Milieu en bas" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show labels in two lines" +msgstr "Voir les étiquettes sur deux lignes" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of columns" +msgstr "Nombre de colonnes" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of rows" +msgstr "Nombre de lignes" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhide all hidden applications" +msgstr "Ne plus cacher les applications" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhidden!" +msgstr "Plus cachées!" + +#: ../contents/ui/main.qml +msgid "Edit Applications..." +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "System Preferences" +msgstr "Préférences Système" + +#: ../contents/ui/MenuRepresentation.qml +msgid "User Home" +msgstr "Dossier Personnel" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Lock Screen" +msgstr "Verrouiller l'écran" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Leave ..." +msgstr "Quitter ..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "Hi, " +msgstr "Salut, " + +#: ../contents/ui/MenuRepresentation.qml +msgid "Type here to search ..." +msgstr "Rechercher ..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "Favorites" +msgstr "Favoris" + +#: ../contents/ui/MenuRepresentation.qml +msgid "All apps" +msgstr "Toutes les applications" diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/ko.po b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/ko.po new file mode 100644 index 00000000..b63b441c --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/ko.po @@ -0,0 +1,137 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://store.kde.org/p/1312669/\n" +"POT-Creation-Date: 2023-05-01 16:59-0300\n" +"PO-Revision-Date: 2021-09-29 09:43+0900\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.0\n" +"X-Poedit-Basepath: .\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: ../metadata.desktop +msgid "Ditto Menu" +msgstr "Ditto 메뉴" + +#: ../metadata.desktop +msgid "A configurable launcher menu" +msgstr "프로그램 실행기" + +#: ../contents/code/tools.js +msgid "Remove from Favorites" +msgstr "즐겨찾기에서 제거" + +#: ../contents/code/tools.js +msgid "Add to Favorites" +msgstr "즐겨찾기에 추가" + +#: ../contents/code/tools.js +msgid "On All Activities" +msgstr "모든 활동" + +#: ../contents/code/tools.js +msgid "On The Current Activity" +msgstr "현재 활동만" + +#: ../contents/code/tools.js +msgid "Show In Favorites" +msgstr "즐겨찾기에 표시" + +#: ../contents/config/config.qml +msgid "General" +msgstr "일반" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Icon:" +msgstr "아이콘:" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Open icon chooser dialog" +msgid "Choose..." +msgstr "선택..." + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Reset icon to default" +msgid "Clear Icon" +msgstr "아이콘 초기화" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show favorites first" +msgstr "즐겨찾기 먼저 표시" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Menu position" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Default" +msgstr "기본" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center" +msgstr "가운데" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center bottom" +msgstr "가운데 밑" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show labels in two lines" +msgstr "라벨 두 줄로 표시" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of columns" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of rows" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhide all hidden applications" +msgstr "모든 숨겨진 프로그램 복구" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhidden!" +msgstr "복구됨!" + +#: ../contents/ui/main.qml +msgid "Edit Applications..." +msgstr "프로그램 편집..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "System Preferences" +msgstr "시스템 설정" + +#: ../contents/ui/MenuRepresentation.qml +msgid "User Home" +msgstr "사용자 홈" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Lock Screen" +msgstr "잠금" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Leave ..." +msgstr "떠나기..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "Hi, " +msgstr "안녕하세요, " + +#: ../contents/ui/MenuRepresentation.qml +msgid "Type here to search ..." +msgstr "검색..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "Favorites" +msgstr "즐겨찾기" + +#: ../contents/ui/MenuRepresentation.qml +msgid "All apps" +msgstr "모든 프로그램" diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/merge.sh b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/merge.sh new file mode 100755 index 00000000..1e6a239b --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/merge.sh @@ -0,0 +1,223 @@ +#!/bin/sh +# Version: 20 + +# https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems +# https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems/Outside_KDE_repositories +# https://invent.kde.org/sysadmin/l10n-scripty/-/blob/master/extract-messages.sh + +DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` +plasmoidName=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Name"` +widgetName="${plasmoidName##*.}" # Strip namespace +website=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Website"` +bugAddress="$website" +packageRoot=".." # Root of translatable sources +projectName="plasma_applet_${plasmoidName}" # project name + +#--- +if [ -z "$plasmoidName" ]; then + echo "[merge] Error: Couldn't read plasmoidName." + exit +fi + +if [ -z "$(which xgettext)" ]; then + echo "[merge] Error: xgettext command not found. Need to install gettext" + echo "[merge] Running 'sudo apt install gettext'" + sudo apt install gettext + echo "[merge] gettext installation should be finished. Going back to merging translations." +fi + +#--- +echo "[merge] Extracting messages" +potArgs="--from-code=UTF-8 --width=200 --add-location=file" + +find "${packageRoot}" -name '*.desktop' | sort > "${DIR}/infiles.list" +xgettext \ + ${potArgs} \ + --files-from="${DIR}/infiles.list" \ + --language=Desktop \ + -D "${packageRoot}" \ + -D "${DIR}" \ + -o "template.pot.new" \ + || \ + { echo "[merge] error while calling xgettext. aborting."; exit 1; } + +sed -i 's/"Content-Type: text\/plain; charset=CHARSET\\n"/"Content-Type: text\/plain; charset=UTF-8\\n"/' "template.pot.new" + +# See Ki18n's extract-messages.sh for a full example: +# https://invent.kde.org/sysadmin/l10n-scripty/-/blob/master/extract-messages.sh#L25 +# The -kN_ and -kaliasLocale keywords are mentioned in the Outside_KDE_repositories wiki. +# We don't need -kN_ since we don't use intltool-extract but might as well keep it. +# I have no idea what -kaliasLocale is used for. Googling aliasLocale found only listed kde1 code. +# We don't need to parse -ki18nd since that'll extract messages from other domains. +find "${packageRoot}" -name '*.cpp' -o -name '*.h' -o -name '*.c' -o -name '*.qml' -o -name '*.js' | sort > "${DIR}/infiles.list" +xgettext \ + ${potArgs} \ + --files-from="${DIR}/infiles.list" \ + -C -kde \ + -ci18n \ + -ki18n:1 -ki18nc:1c,2 -ki18np:1,2 -ki18ncp:1c,2,3 \ + -kki18n:1 -kki18nc:1c,2 -kki18np:1,2 -kki18ncp:1c,2,3 \ + -kxi18n:1 -kxi18nc:1c,2 -kxi18np:1,2 -kxi18ncp:1c,2,3 \ + -kkxi18n:1 -kkxi18nc:1c,2 -kkxi18np:1,2 -kkxi18ncp:1c,2,3 \ + -kI18N_NOOP:1 -kI18NC_NOOP:1c,2 \ + -kI18N_NOOP2:1c,2 -kI18N_NOOP2_NOSTRIP:1c,2 \ + -ktr2i18n:1 -ktr2xi18n:1 \ + -kN_:1 \ + -kaliasLocale \ + --package-name="${widgetName}" \ + --msgid-bugs-address="${bugAddress}" \ + -D "${packageRoot}" \ + -D "${DIR}" \ + --join-existing \ + -o "template.pot.new" \ + || \ + { echo "[merge] error while calling xgettext. aborting."; exit 1; } + +sed -i 's/# SOME DESCRIPTIVE TITLE./'"# Translation of ${widgetName} in LANGUAGE"'/' "template.pot.new" +sed -i 's/# Copyright (C) YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/'"# Copyright (C) $(date +%Y)"'/' "template.pot.new" + +if [ -f "template.pot" ]; then + newPotDate=`grep "POT-Creation-Date:" template.pot.new | sed 's/.\{3\}$//'` + oldPotDate=`grep "POT-Creation-Date:" template.pot | sed 's/.\{3\}$//'` + sed -i 's/'"${newPotDate}"'/'"${oldPotDate}"'/' "template.pot.new" + changes=`diff "template.pot" "template.pot.new"` + if [ ! -z "$changes" ]; then + # There's been changes + sed -i 's/'"${oldPotDate}"'/'"${newPotDate}"'/' "template.pot.new" + mv "template.pot.new" "template.pot" + + addedKeys=`echo "$changes" | grep "> msgid" | cut -c 9- | sort` + removedKeys=`echo "$changes" | grep "< msgid" | cut -c 9- | sort` + echo "" + echo "Added Keys:" + echo "$addedKeys" + echo "" + echo "Removed Keys:" + echo "$removedKeys" + echo "" + + else + # No changes + rm "template.pot.new" + fi +else + # template.pot didn't already exist + mv "template.pot.new" "template.pot" +fi + +potMessageCount=`expr $(grep -Pzo 'msgstr ""\n(\n|$)' "template.pot" | grep -c 'msgstr ""')` +echo "| Locale | Lines | % Done|" > "./Status.md" +echo "|----------|---------|-------|" >> "./Status.md" +entryFormat="| %-8s | %7s | %5s |" +templateLine=`perl -e "printf(\"$entryFormat\", \"Template\", \"${potMessageCount}\", \"\")"` +echo "$templateLine" >> "./Status.md" + +rm "${DIR}/infiles.list" +echo "[merge] Done extracting messages" + +#--- +echo "[merge] Merging messages" +catalogs=`find . -name '*.po' | sort` +for cat in $catalogs; do + echo "[merge] $cat" + catLocale=`basename ${cat%.*}` + + widthArg="" + catUsesGenerator=`grep "X-Generator:" "$cat"` + if [ -z "$catUsesGenerator" ]; then + widthArg="--width=400" + fi + + cp "$cat" "$cat.new" + sed -i 's/"Content-Type: text\/plain; charset=CHARSET\\n"/"Content-Type: text\/plain; charset=UTF-8\\n"/' "$cat.new" + + msgmerge \ + ${widthArg} \ + --add-location=file \ + --no-fuzzy-matching \ + -o "$cat.new" \ + "$cat.new" "${DIR}/template.pot" + + sed -i 's/# SOME DESCRIPTIVE TITLE./'"# Translation of ${widgetName} in ${catLocale}"'/' "$cat.new" + sed -i 's/# Translation of '"${widgetName}"' in LANGUAGE/'"# Translation of ${widgetName} in ${catLocale}"'/' "$cat.new" + sed -i 's/# Copyright (C) YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/'"# Copyright (C) $(date +%Y)"'/' "$cat.new" + + poEmptyMessageCount=`expr $(grep -Pzo 'msgstr ""\n(\n|$)' "$cat.new" | grep -c 'msgstr ""')` + poMessagesDoneCount=`expr $potMessageCount - $poEmptyMessageCount` + poCompletion=`perl -e "printf(\"%d\", $poMessagesDoneCount * 100 / $potMessageCount)"` + poLine=`perl -e "printf(\"$entryFormat\", \"$catLocale\", \"${poMessagesDoneCount}/${potMessageCount}\", \"${poCompletion}%\")"` + echo "$poLine" >> "./Status.md" + + # mv "$cat" "$cat.old" + mv "$cat.new" "$cat" +done +echo "[merge] Done merging messages" + +#--- +echo "[merge] Updating .desktop file" + +# Generate LINGUAS for msgfmt +if [ -f "$DIR/LINGUAS" ]; then + rm "$DIR/LINGUAS" +fi +touch "$DIR/LINGUAS" +for cat in $catalogs; do + catLocale=`basename ${cat%.*}` + echo "${catLocale}" >> "$DIR/LINGUAS" +done + +cp -f "$DIR/../metadata.desktop" "$DIR/template.desktop" +sed -i '/^Name\[/ d; /^GenericName\[/ d; /^Comment\[/ d; /^Keywords\[/ d' "$DIR/template.desktop" + +msgfmt \ + --desktop \ + --template="$DIR/template.desktop" \ + -d "$DIR/" \ + -o "$DIR/new.desktop" + +# Delete empty msgid messages that used the po header +if [ ! -z "$(grep '^Name=$' "$DIR/new.desktop")" ]; then + echo "[merge] Name in metadata.desktop is empty!" + sed -i '/^Name\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^GenericName=$' "$DIR/new.desktop")" ]; then + echo "[merge] GenericName in metadata.desktop is empty!" + sed -i '/^GenericName\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^Comment=$' "$DIR/new.desktop")" ]; then + echo "[merge] Comment in metadata.desktop is empty!" + sed -i '/^Comment\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^Keywords=$' "$DIR/new.desktop")" ]; then + echo "[merge] Keywords in metadata.desktop is empty!" + sed -i '/^Keywords\[/ d' "$DIR/new.desktop" +fi + +# Place translations at the bottom of the desktop file. +translatedLines=`cat "$DIR/new.desktop" | grep "]="` +if [ ! -z "${translatedLines}" ]; then + sed -i '/^Name\[/ d; /^GenericName\[/ d; /^Comment\[/ d; /^Keywords\[/ d' "$DIR/new.desktop" + if [ "$(tail -c 2 "$DIR/new.desktop" | wc -l)" != "2" ]; then + # Does not end with 2 empty lines, so add an empty line. + echo "" >> "$DIR/new.desktop" + fi + echo "${translatedLines}" >> "$DIR/new.desktop" +fi + +# Cleanup +mv "$DIR/new.desktop" "$DIR/../metadata.desktop" +rm "$DIR/template.desktop" +rm "$DIR/LINGUAS" + +#--- +# Populate ReadMe.md +echo "[merge] Updating translate/ReadMe.md" +sed -i -E 's`share\/plasma\/plasmoids\/(.+)\/translate`share/plasma/plasmoids/'"${plasmoidName}"'/translate`' ./ReadMe.md +if [[ "$website" == *"github.com"* ]]; then + sed -i -E 's`\[new issue\]\(https:\/\/github\.com\/(.+)\/(.+)\/issues\/new\)`[new issue]('"${website}"'/issues/new)`' ./ReadMe.md +fi +sed -i '/^|/ d' ./ReadMe.md # Remove status table from ReadMe +cat ./Status.md >> ./ReadMe.md +rm ./Status.md + +echo "[merge] Done" diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/nl.po b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/nl.po new file mode 100644 index 00000000..477e5ea9 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/nl.po @@ -0,0 +1,187 @@ +# Translation of dittomenu in nl +# Copyright (C) 2021 +# This file is distributed under the same license as the dittomenu package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: dittomenu\n" +"Report-Msgid-Bugs-To: https://store.kde.org/p/1312669/\n" +"POT-Creation-Date: 2023-05-01 16:59-0300\n" +"PO-Revision-Date: 2022-01-01 20:09+0100\n" +"Last-Translator: Heimen Stoffels \n" +"Language-Team: \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.0\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../metadata.desktop +msgid "Ditto Menu" +msgstr "Ditto-menu" + +#: ../metadata.desktop +msgid "A configurable launcher menu" +msgstr "Een instelbare programmastarter" + +#: ../contents/code/tools.js +msgid "Remove from Favorites" +msgstr "Verwijderen uit favorieten" + +#: ../contents/code/tools.js +msgid "Add to Favorites" +msgstr "Toevoegen aan favorieten" + +#: ../contents/code/tools.js +msgid "On All Activities" +msgstr "Op alle activiteiten" + +#: ../contents/code/tools.js +msgid "On The Current Activity" +msgstr "Op de huidige activiteit" + +#: ../contents/code/tools.js +msgid "Show In Favorites" +msgstr "Toevoegen aan favorieten" + +#: ../contents/config/config.qml +msgid "General" +msgstr "Algemeen" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Icon:" +msgstr "Pictogram:" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Open icon chooser dialog" +msgid "Choose..." +msgstr "Kiezen…" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Reset icon to default" +msgid "Clear Icon" +msgstr "Pictogram verwijderen" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show favorites first" +msgstr "Favorieten bovenaan tonen" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Menu position" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Default" +msgstr "Standaard" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center" +msgstr "Gecentreerd" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center bottom" +msgstr "Gecentreerd (onderaan)" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show labels in two lines" +msgstr "Labeltekst verdelen over twee regels" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of columns" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of rows" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhide all hidden applications" +msgstr "Alle verborgen programma's zichtbaar maken" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhidden!" +msgstr "Alles programma's zijn weer zichtbaar!" + +#: ../contents/ui/main.qml +msgid "Edit Applications..." +msgstr "Programma's bewerken…" + +#: ../contents/ui/MenuRepresentation.qml +msgid "System Preferences" +msgstr "Systeeminstellingen" + +#: ../contents/ui/MenuRepresentation.qml +msgid "User Home" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Lock Screen" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Leave ..." +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Hi, " +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Type here to search ..." +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Favorites" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "All apps" +msgstr "" + +#~ msgctxt "@action" +#~ msgid "Lock Screen" +#~ msgstr "Scherm vergrendelen" + +#~ msgid "Behavior" +#~ msgstr "Gedrag" + +#~ msgid "Show applications as:" +#~ msgstr "Programmaweergave:" + +#~ msgid "Name only" +#~ msgstr "Alleen naam" + +#~ msgid "Description only" +#~ msgstr "Alleen beschrijving" + +#~ msgid "Name (Description)" +#~ msgstr "Naam (beschrijving)" + +#~ msgid "Description (Name)" +#~ msgstr "Beschrijving (naam)" + +#~ msgid "Menu position:" +#~ msgstr "Menupositie:" + +#~ msgid "Search" +#~ msgstr "Zoeken" + +#~ msgid "Expand search to bookmarks, files and emails" +#~ msgstr "Ook bladwijzers, bestanden en e-mails doorzoeken" + +#~ msgid "Show user icon" +#~ msgstr "Gebruikersafbeelding tonen" + +#~ msgid "Grid" +#~ msgstr "Rooster" + +#~ msgid "Number of columns in grid" +#~ msgstr "Aantal kolommen op rooster" + +#~ msgid "Number of rows in grid" +#~ msgstr "Aantal rijen op rooster" + +#~ msgid "Search ..." +#~ msgstr "Zoeken…" diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/pl.po b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/pl.po new file mode 100644 index 00000000..501335ce --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/pl.po @@ -0,0 +1,183 @@ +# Translation of dittomenu in pl +# Copyright (C) 2022 +# This file is distributed under the same license as the dittomenu package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: dittomenu\n" +"Report-Msgid-Bugs-To: https://store.kde.org/p/1312669/\n" +"POT-Creation-Date: 2023-05-01 16:59-0300\n" +"PO-Revision-Date: 2022-04-05 10:40+0100\n" +"Last-Translator: Krzysztof Korab \n" +"Language-Team: \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Ditto Menu" +msgstr "" + +#: ../metadata.desktop +msgid "A configurable launcher menu" +msgstr "Konfigurowalne menu uruchamiania programów" + +#: ../contents/code/tools.js +msgid "Remove from Favorites" +msgstr "Usuń z ulubionych" + +#: ../contents/code/tools.js +msgid "Add to Favorites" +msgstr "Dodaj do ulubionych" + +#: ../contents/code/tools.js +msgid "On All Activities" +msgstr "Na wszystkich aktywnościach" + +#: ../contents/code/tools.js +msgid "On The Current Activity" +msgstr "Na bieżącej aktywności" + +#: ../contents/code/tools.js +msgid "Show In Favorites" +msgstr "Pokaż w ulubionych" + +#: ../contents/config/config.qml +msgid "General" +msgstr "Ogólne" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Icon:" +msgstr "Ikona:" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Open icon chooser dialog" +msgid "Choose..." +msgstr "Wybierz..." + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Reset icon to default" +msgid "Clear Icon" +msgstr "Wyczyść ikonę" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show favorites first" +msgstr "Najpierw pokaż ulubione" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Menu position" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Default" +msgstr "Domyślne" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center" +msgstr "Wyśrodkowane" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center bottom" +msgstr "Wyśrodkowane, na dole" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show labels in two lines" +msgstr "Pokaż podpisy w dwóch liniach" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of columns" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of rows" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhide all hidden applications" +msgstr "Uwidocznij wszystkie ukryte aplikacje" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhidden!" +msgstr "Wszystkie programy są widoczne!" + +#: ../contents/ui/main.qml +msgid "Edit Applications..." +msgstr "Edytuj programy..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "System Preferences" +msgstr "Ustawienia systemowe" + +#: ../contents/ui/MenuRepresentation.qml +msgid "User Home" +msgstr "Katalog domowy" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Lock Screen" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Leave ..." +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Hi, " +msgstr "Cześć, " + +#: ../contents/ui/MenuRepresentation.qml +msgid "Type here to search ..." +msgstr "Wpisz tutaj, aby wyszukać..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "Favorites" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "All apps" +msgstr "" + +#~ msgctxt "@action" +#~ msgid "Lock Screen" +#~ msgstr "Zablokuj ekran" + +#~ msgid "Behavior" +#~ msgstr "Zachowanie" + +#~ msgid "Show applications as:" +#~ msgstr "Pokazuj programy jako:" + +#~ msgid "Name only" +#~ msgstr "Tylko nazwa" + +#~ msgid "Description only" +#~ msgstr "Tylko opis" + +#~ msgid "Name (Description)" +#~ msgstr "Nazwa (Opis)" + +#~ msgid "Description (Name)" +#~ msgstr "Opis (Nazwa)" + +#~ msgid "Menu position:" +#~ msgstr "Położenie menu:" + +#~ msgid "Search" +#~ msgstr "Szukaj" + +#~ msgid "Expand search to bookmarks, files and emails" +#~ msgstr "Rozszerz wyszukiwanie na zakładki, pliki i pocztę" + +#~ msgid "Show user icon" +#~ msgstr "Pokaż ikonę użytkownika" + +#~ msgid "Grid" +#~ msgstr "Siatka" + +#~ msgid "Number of columns in grid" +#~ msgstr "Liczba kolumn w siatce" + +#~ msgid "Number of rows in grid" +#~ msgstr "Liczba wierszy w siatce" diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/plasmoidlocaletest.sh b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/plasmoidlocaletest.sh new file mode 100755 index 00000000..dacdedb1 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/plasmoidlocaletest.sh @@ -0,0 +1,181 @@ +#!/bin/bash +# Version 9 +# Requires plasmoidviewer v5.13.0 + +function checkIfLangInstalled { + if [ -x "$(command -v dpkg)" ]; then + dpkg -l ${1} >/dev/null 2>&1 || ( \ + echo -e "${1} not installed.\nInstalling now before continuing.\n" \ + ; sudo apt install ${1} \ + ) || ( \ + echo -e "\nError trying to install ${1}\nPlease run 'sudo apt install ${1}'\n" \ + ; exit 1 \ + ) + elif [ -x "$(command -v pacman)" ]; then + # TODO: run `locale -a` and check if the locale is enabled. + if false; then + # https://wiki.archlinux.org/index.php/Locale + # Uncomment the locale in /etc/locale.gen + # Then run `locale-gen` + echo -e "\nPlease install this locale in System Settings first.\n" + exit 1 + else + echo "" + fi + else + echo -e "\nPackage manager not recognized. If the widget is not translated, please install the package '${1}'\n" + fi +} + +langInput="${1}" +lang="" +languagePack="" + +if [[ "$langInput" =~ ":" ]]; then # String contains a colon so assume it's a locale code. + lang="${langInput}" + IFS=: read -r l1 l2 <<< "${lang}" + languagePack="language-pack-${l2}" +fi + +# https://stackoverflow.com/questions/3191664/list-of-all-locales-and-their-short-codes/28357857#28357857 +declare -a langArr=( + "af_ZA:af:Afrikaans (South Africa)" + "ak_GH:ak:Akan (Ghana)" + "am_ET:am:Amharic (Ethiopia)" + "ar_EG:ar:Arabic (Egypt)" + "as_IN:as:Assamese (India)" + "az_AZ:az:Azerbaijani (Azerbaijan)" + "be_BY:be:Belarusian (Belarus)" + "bem_ZM:bem:Bemba (Zambia)" + "bg_BG:bg:Bulgarian (Bulgaria)" + "bo_IN:bo:Tibetan (India)" + "bs_BA:bs:Bosnian (Bosnia and Herzegovina)" + "ca_ES:ca:Catalan (Spain)" + "chr_US:ch:Cherokee (United States)" + "cs_CZ:cs:Czech (Czech Republic)" + "cy_GB:cy:Welsh (United Kingdom)" + "da_DK:da:Danish (Denmark)" + "de_DE:de:German (Germany)" + "el_GR:el:Greek (Greece)" + "es_MX:es:Spanish (Mexico)" + "et_EE:et:Estonian (Estonia)" + "eu_ES:eu:Basque (Spain)" + "fa_IR:fa:Persian (Iran)" + "ff_SN:ff:Fulah (Senegal)" + "fi_FI:fi:Finnish (Finland)" + "fo_FO:fo:Faroese (Faroe Islands)" + "fr_CA:fr:French (Canada)" + "ga_IE:ga:Irish (Ireland)" + "gl_ES:gl:Galician (Spain)" + "gu_IN:gu:Gujarati (India)" + "gv_GB:gv:Manx (United Kingdom)" + "ha_NG:ha:Hausa (Nigeria)" + "he_IL:he:Hebrew (Israel)" + "hi_IN:hi:Hindi (India)" + "hr_HR:hr:Croatian (Croatia)" + "hu_HU:hu:Hungarian (Hungary)" + "hy_AM:hy:Armenian (Armenia)" + "id_ID:id:Indonesian (Indonesia)" + "ig_NG:ig:Igbo (Nigeria)" + "is_IS:is:Icelandic (Iceland)" + "it_IT:it:Italian (Italy)" + "ja_JP:ja:Japanese (Japan)" + "ka_GE:ka:Georgian (Georgia)" + "kk_KZ:kk:Kazakh (Kazakhstan)" + "kl_GL:kl:Kalaallisut (Greenland)" + "km_KH:km:Khmer (Cambodia)" + "kn_IN:kn:Kannada (India)" + "ko_KR:ko:Korean (South Korea)" + "ko_KR:ko:Korean (South Korea)" + "lg_UG:lg:Ganda (Uganda)" + "lt_LT:lt:Lithuanian (Lithuania)" + "lv_LV:lv:Latvian (Latvia)" + "mg_MG:mg:Malagasy (Madagascar)" + "mk_MK:mk:Macedonian (Macedonia)" + "ml_IN:ml:Malayalam (India)" + "mr_IN:mr:Marathi (India)" + "ms_MY:ms:Malay (Malaysia)" + "mt_MT:mt:Maltese (Malta)" + "my_MM:my:Burmese (Myanmar [Burma])" + "nb_NO:nb:Norwegian Bokmål (Norway)" + "ne_NP:ne:Nepali (Nepal)" + "nl_NL:nl:Dutch (Netherlands)" + "nn_NO:nn:Norwegian Nynorsk (Norway)" + "om_ET:om:Oromo (Ethiopia)" + "or_IN:or:Oriya (India)" + "pa_PK:pa:Punjabi (Pakistan)" + "pl_PL:pl:Polish (Poland)" + "ps_AF:ps:Pashto (Afghanistan)" + "pt_BR:pt:Portuguese (Brazil)" + "ro_RO:ro:Romanian (Romania)" + "ru_RU:ru:Russian (Russia)" + "rw_RW:rw:Kinyarwanda (Rwanda)" + "si_LK:si:Sinhala (Sri Lanka)" + "sk_SK:sk:Slovak (Slovakia)" + "sl_SI:sl:Slovenian (Slovenia)" + "so_SO:so:Somali (Somalia)" + "sq_AL:sq:Albanian (Albania)" + "sr_RS:sr:Serbian (Serbia)" + "sv_SE:sv:Swedish (Sweden)" + "sw_KE:sw:Swahili (Kenya)" + "ta_IN:ta:Tamil (India)" + "te_IN:te:Telugu (India)" + "th_TH:th:Thai (Thailand)" + "ti_ER:ti:Tigrinya (Eritrea)" + "to_TO:to:Tonga (Tonga)" + "tr_TR:tr:Turkish (Turkey)" + "uk_UA:uk:Ukrainian (Ukraine)" + "ur_IN:ur:Urdu (India)" + "uz_UZ:uz:Uzbek (Uzbekistan)" + "vi_VN:vi:Vietnamese (Vietnam)" + "yo_NG:yo:Yoruba (Nigeria)" + "yo_NG:yo:Yoruba (Nigeria)" + "yue_HK:yu:Cantonese (Hong Kong)" + "zh_CN:zh:Chinese (China)" + "zu_ZA:zu:Zulu (South Africa)" +) + +for i in "${langArr[@]}"; do + IFS=: read -r l1 l2 l3 <<< "$i" + if [ "$langInput" == "$l2" ]; then + lang="${l1}:${l2}" + languagePack="language-pack-${l2}" + fi +done + +if [ -z "$lang" ]; then + echo "plasmoidlocaletest doesn't recognize the language '$lang'" + echo "Eg:" + scriptcmd='sh ./plasmoidlocaletest' + for i in "${langArr[@]}"; do + IFS=: read -r l1 l2 l3 <<< "$i" + echo " ${scriptcmd} ${l2} | ${l3}" + done + echo "" + echo "Or use a the full locale code:" + echo " ${scriptcmd} ar_EG:ar" + exit 1 +fi + +IFS=: read -r l1 l2 <<< "${lang}" +l1="${l1}.UTF-8" + +# Check if language is installed +if [ ! -z "$languagePack" ]; then + if [ "$lang" == "zh_CN:zh" ]; then languagePack="language-pack-zh-hans" + fi + + checkIfLangInstalled "$languagePack" || exit 1 +fi + + +echo "LANGUAGE=\"${lang}\"" +echo "LANG=\"${l1}\"" + +scriptDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +packageDir="${scriptDir}/.." + +# Build local translations for plasmoidviewer +sh "${scriptDir}/build" + +LANGUAGE="${lang}" LANG="${l1}" LC_TIME="${l1}" QML_DISABLE_DISK_CACHE=true plasmoidviewer -a "$packageDir" -l topedge -f horizontal -x 0 -y 0 diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/pt_BR.po b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/pt_BR.po new file mode 100644 index 00000000..c3df0c05 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/pt_BR.po @@ -0,0 +1,140 @@ +# Translation of dittomenu in pt_BR +# Copyright (C) 2022 +# This file is distributed under the same license as the dittomenu package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: dittomenu\n" +"Report-Msgid-Bugs-To: https://store.kde.org/p/1312669/\n" +"POT-Creation-Date: 2023-05-01 16:59-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Ditto Menu" +msgstr "Ditto Menu" + +#: ../metadata.desktop +msgid "A configurable launcher menu" +msgstr "Configuração do Menu Iniciar" + +#: ../contents/code/tools.js +msgid "Remove from Favorites" +msgstr "Remover dos favoritos" + +#: ../contents/code/tools.js +msgid "Add to Favorites" +msgstr "Adicionar aos Favoritos" + +#: ../contents/code/tools.js +msgid "On All Activities" +msgstr "Em todas as atividades" + +#: ../contents/code/tools.js +msgid "On The Current Activity" +msgstr "Na atividade atual" + +#: ../contents/code/tools.js +msgid "Show In Favorites" +msgstr "Exibir nos favoritos" + +#: ../contents/config/config.qml +msgid "General" +msgstr "Geral" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Icon:" +msgstr "Ícone" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Open icon chooser dialog" +msgid "Choose..." +msgstr "Procurar" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Reset icon to default" +msgid "Clear Icon" +msgstr "Resetar Ícone" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show favorites first" +msgstr "Exbir os Favoritros primeiro" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Menu position" +msgstr "Posição do menu" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Default" +msgstr "Padrão" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center" +msgstr "Centro" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center bottom" +msgstr "Centro inferior" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show labels in two lines" +msgstr "Exibir os nomes em duas linhas" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of columns" +msgstr "Numero de colunas" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of rows" +msgstr "Numero de filas" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhide all hidden applications" +msgstr "Mostrar aplicativos ocultos" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhidden!" +msgstr "Reexibido" + +#: ../contents/ui/main.qml +msgid "Edit Applications..." +msgstr "Editar Programa" + +#: ../contents/ui/MenuRepresentation.qml +msgid "System Preferences" +msgstr "Configurações do Sistema" + +#: ../contents/ui/MenuRepresentation.qml +msgid "User Home" +msgstr "Diretório do Usuário" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Lock Screen" +msgstr "Tela de bloqueio" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Leave ..." +msgstr "Sair ..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "Hi, " +msgstr "Olá, " + +#: ../contents/ui/MenuRepresentation.qml +msgid "Type here to search ..." +msgstr "Digite aqui para pesquisar" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Favorites" +msgstr "Favoritos" + +#: ../contents/ui/MenuRepresentation.qml +msgid "All apps" +msgstr "Todos os programas" diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/ru.po b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/ru.po new file mode 100644 index 00000000..5bd501d1 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/ru.po @@ -0,0 +1,183 @@ +# Translation of dittomenu in pl +# Copyright (C) 2022 +# This file is distributed under the same license as the dittomenu package. +# FIRST AUTHOR , YEAR.. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: dittomenu\n" +"Report-Msgid-Bugs-To: https://store.kde.org/p/1312669/\n" +"POT-Creation-Date: 2023-05-01 16:59-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Edward Karate \n" +"Language-Team: LANGUAGE \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Ditto Menu" +msgstr "Ditto Menu" + +#: ../metadata.desktop +msgid "A configurable launcher menu" +msgstr "Настраиваемое меню приложений" + +#: ../contents/code/tools.js +msgid "Remove from Favorites" +msgstr "Убрать из избранного" + +#: ../contents/code/tools.js +msgid "Add to Favorites" +msgstr "Добавить в избранное" + +#: ../contents/code/tools.js +msgid "On All Activities" +msgstr "По всем видам деятельности" + +#: ../contents/code/tools.js +msgid "On The Current Activity" +msgstr "О текущей деятельности" + +#: ../contents/code/tools.js +msgid "Show In Favorites" +msgstr "Показать в Избранном" + +#: ../contents/config/config.qml +msgid "General" +msgstr "Общие" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Icon:" +msgstr "Значок" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Open icon chooser dialog" +msgid "Choose..." +msgstr "Выбрать..." + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Reset icon to default" +msgid "Clear Icon" +msgstr "Очистить значок" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show favorites first" +msgstr "Сначала показать избранное" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Menu position" +msgstr "Положение меню" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Default" +msgstr "По умолчанию" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center" +msgstr "Центр" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center bottom" +msgstr "Снизу по центру" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show labels in two lines" +msgstr "Отображать метки в две строки" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of columns" +msgstr "Количество колонок" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of rows" +msgstr "Количество строк" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhide all hidden applications" +msgstr "Показать все скрытые приложения" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhidden!" +msgstr "Показаны!" + +#: ../contents/ui/main.qml +msgid "Edit Applications..." +msgstr "Редактировать меню..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "System Preferences" +msgstr "Параметры системы" + +#: ../contents/ui/MenuRepresentation.qml +msgid "User Home" +msgstr "Домашняя папка" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Lock Screen" +msgstr "Заблокировать" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Leave ..." +msgstr "Выход ..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "Hi, " +msgstr "Привет, " + +#: ../contents/ui/MenuRepresentation.qml +msgid "Type here to search ..." +msgstr "Введите текст для поиска..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "Favorites" +msgstr "Избранное" + +#: ../contents/ui/MenuRepresentation.qml +msgid "All apps" +msgstr "Все приложения" + +#~ msgctxt "@action" +#~ msgid "Lock Screen" +#~ msgstr "Заблокировать" + +#~ msgid "Behavior" +#~ msgstr "Поведение" + +#~ msgid "Show applications as:" +#~ msgstr "Показывать приложения в виде:" + +#~ msgid "Name only" +#~ msgstr "Только имя" + +#~ msgid "Description only" +#~ msgstr "Только описание" + +#~ msgid "Name (Description)" +#~ msgstr "Имя (Описание)" + +#~ msgid "Description (Name)" +#~ msgstr "Описание (Имя)" + +#~ msgid "Menu position:" +#~ msgstr "Позиция меню" + +#~ msgid "Search" +#~ msgstr "Поиск" + +#~ msgid "Expand search to bookmarks, files and emails" +#~ msgstr "Расширить поиск по закладкам, файлам и почте" + +#~ msgid "Show user icon" +#~ msgstr "Показать иконку пользователя" + +#~ msgid "Grid" +#~ msgstr "Сетка" + +#~ msgid "Number of columns in grid" +#~ msgstr "Количество колонок в сетке" + +#~ msgid "Number of rows in grid" +#~ msgstr "Количество строк в сетке" diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/template.pot b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/template.pot new file mode 100644 index 00000000..ab57d312 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/template.pot @@ -0,0 +1,140 @@ +# Translation of dittomenu in LANGUAGE +# Copyright (C) 2023 +# This file is distributed under the same license as the dittomenu package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: dittomenu\n" +"Report-Msgid-Bugs-To: https://store.kde.org/p/1312669/\n" +"POT-Creation-Date: 2023-05-01 16:59-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Ditto Menu" +msgstr "" + +#: ../metadata.desktop +msgid "A configurable launcher menu" +msgstr "" + +#: ../contents/code/tools.js +msgid "Remove from Favorites" +msgstr "" + +#: ../contents/code/tools.js +msgid "Add to Favorites" +msgstr "" + +#: ../contents/code/tools.js +msgid "On All Activities" +msgstr "" + +#: ../contents/code/tools.js +msgid "On The Current Activity" +msgstr "" + +#: ../contents/code/tools.js +msgid "Show In Favorites" +msgstr "" + +#: ../contents/config/config.qml +msgid "General" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Icon:" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Open icon chooser dialog" +msgid "Choose..." +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Reset icon to default" +msgid "Clear Icon" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show favorites first" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Menu position" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Default" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center bottom" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show labels in two lines" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of columns" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of rows" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhide all hidden applications" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhidden!" +msgstr "" + +#: ../contents/ui/main.qml +msgid "Edit Applications..." +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "System Preferences" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "User Home" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Lock Screen" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Leave ..." +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Hi, " +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Type here to search ..." +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Favorites" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "All apps" +msgstr "" diff --git a/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/tr.po b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/tr.po new file mode 100644 index 00000000..fa1c50bf --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.dittomenu/translate/tr.po @@ -0,0 +1,186 @@ +# Translation of dittomenu in tr +# Copyright (C) 2022 +# This file is distributed under the same license as the dittomenu package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: dittomenu\n" +"Report-Msgid-Bugs-To: https://store.kde.org/p/1312669/\n" +"POT-Creation-Date: 2023-05-01 16:59-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Language: tr_TR\n" +"X-Source-Language: C\n" + +#: ../metadata.desktop +msgid "Ditto Menu" +msgstr "Ditto Menu" + +#: ../metadata.desktop +msgid "A configurable launcher menu" +msgstr "Yapılandırılabilir bir başlatıcı menüsü" + +#: ../contents/code/tools.js +msgid "Remove from Favorites" +msgstr "Favorilerden Çıkar" + +#: ../contents/code/tools.js +msgid "Add to Favorites" +msgstr "Favorilerden Ekle" + +#: ../contents/code/tools.js +msgid "On All Activities" +msgstr "Tüm Etkinliklerde" + +#: ../contents/code/tools.js +msgid "On The Current Activity" +msgstr "Mevcut Etkinlik Üzerine" + +#: ../contents/code/tools.js +msgid "Show In Favorites" +msgstr "Favorilerde Göster" + +#: ../contents/config/config.qml +msgid "General" +msgstr "Genel" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Icon:" +msgstr "Sİmge:" + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Open icon chooser dialog" +msgid "Choose..." +msgstr "Seçmek..." + +#: ../contents/ui/ConfigGeneral.qml +msgctxt "@item:inmenu Reset icon to default" +msgid "Clear Icon" +msgstr "Simgeyi Temizle" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show favorites first" +msgstr "Önce favorileri göster" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Menu position" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Default" +msgstr "Varsayılan" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center" +msgstr "Orta" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Center bottom" +msgstr "Orta alt" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Show labels in two lines" +msgstr "Etiketleri iki satırda göster" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of columns" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Number of rows" +msgstr "" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhide all hidden applications" +msgstr "Tüm gizli uygulamaları göster" + +#: ../contents/ui/ConfigGeneral.qml +msgid "Unhidden!" +msgstr "Gizli!" + +#: ../contents/ui/main.qml +msgid "Edit Applications..." +msgstr "Uygulamaları Düzenle..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "System Preferences" +msgstr "Sistem Tercihleri" + +#: ../contents/ui/MenuRepresentation.qml +msgid "User Home" +msgstr "Kullanıcı Ana Sayfası" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Lock Screen" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Leave ..." +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "Hi, " +msgstr "Merhaba, " + +#: ../contents/ui/MenuRepresentation.qml +msgid "Type here to search ..." +msgstr "Aramak için buraya yazınız ..." + +#: ../contents/ui/MenuRepresentation.qml +msgid "Favorites" +msgstr "" + +#: ../contents/ui/MenuRepresentation.qml +msgid "All apps" +msgstr "" + +#~ msgctxt "@action" +#~ msgid "Lock Screen" +#~ msgstr "Kilit Ekranı" + +#~ msgid "Behavior" +#~ msgstr "Davranış" + +#~ msgid "Show applications as:" +#~ msgstr "Uygulamaları şu şekilde göster:" + +#~ msgid "Name only" +#~ msgstr "Sadece isim" + +#~ msgid "Description only" +#~ msgstr "Yalnızca açıklama" + +#~ msgid "Name (Description)" +#~ msgstr "İsim (Açıklama)" + +#~ msgid "Description (Name)" +#~ msgstr "Açıklama (İsim)" + +#~ msgid "Menu position:" +#~ msgstr "Menü konumu:" + +#~ msgid "Search" +#~ msgstr "Ara" + +#~ msgid "Expand search to bookmarks, files and emails" +#~ msgstr "Aramayı yer imlerine, dosyalara ve e-postalara genişletin" + +#~ msgid "Show user icon" +#~ msgstr "Kullanıcı simgesini göster" + +#~ msgid "Grid" +#~ msgstr "Izgara" + +#~ msgid "Number of columns in grid" +#~ msgstr "Izgaradaki sütun sayısı" + +#~ msgid "Number of rows in grid" +#~ msgstr "Izgaradaki satır sayısı" diff --git a/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/fonts/SofiaProLight.ttf b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/fonts/SofiaProLight.ttf new file mode 100644 index 00000000..cecebf10 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/fonts/SofiaProLight.ttf differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/fonts/SourceSansPro-Semibold.otf b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/fonts/SourceSansPro-Semibold.otf new file mode 100644 index 00000000..fffdbafe Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/fonts/SourceSansPro-Semibold.otf differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/AlbumArtStackView.qml b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/AlbumArtStackView.qml new file mode 100644 index 00000000..7a125927 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/AlbumArtStackView.qml @@ -0,0 +1,229 @@ +/* + SPDX-FileCopyrightText: 2013 Marco Martin + SPDX-FileCopyrightText: 2014 Sebastian Kügler + SPDX-FileCopyrightText: 2014 Kai Uwe Broulik + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Window 2.15 + +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.components 3.0 as PC3 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.extras 2.0 as PlasmaExtras + +Item { + id: container + + /** + * Whether the album art image is available or in loading status + */ + readonly property bool hasImage: (pendingImage !== null && (pendingImage.status === Image.Ready || pendingImage.status === Image.Loading)) + || (albumArt.currentItem instanceof Image && albumArt.currentItem.status === Image.Ready) + + readonly property bool animating: exitTransition.running || popExitTransition.running + + /** + * Whether the component is used in the compact representation + */ + property bool inCompactRepresentation: false + + /** + * Provides source item for \ShaderEffectSource + */ + readonly property alias albumArt: albumArt + + property Image pendingImage: null + + onWidthChanged: geometryChangeTimer.restart(); + onHeightChanged: geometryChangeTimer.restart(); + + function loadAlbumArt() { + if (pendingImage !== null) { + pendingImage.destroy(); + pendingImage = null; + } + + if (!root.albumArt) { + albumArt.clear(StackView.PopTransition); + return; + } + + const oldImageRatio = albumArt.currentItem instanceof Image ? albumArt.currentItem.sourceSize.width / albumArt.currentItem.sourceSize.height : 1; + pendingImage = albumArtComponent.createObject(albumArt, { + "source": root.albumArt, + "sourceSize": Qt.size(container.width * Screen.devicePixelRatio, container.height * Screen.devicePixelRatio), + "opacity": 0, + }); + + function replaceWhenLoaded() { + if (pendingImage.status === Image.Loading) { + return; + } + + if (pendingImage.status === Image.Ready) { + const newImageRatio = pendingImage.sourceSize.width / pendingImage.sourceSize.height; + exitTransitionOpacityAnimator.duration = oldImageRatio === newImageRatio ? 0 : PlasmaCore.Units.longDuration; + } else { + // Load placeholder icon, but keep the invalid image to avoid flashing application icons + exitTransitionOpacityAnimator.duration = 0; + } + + albumArt.replace(pendingImage, {}, StackView.ReplaceTransition); + pendingImage.statusChanged.disconnect(replaceWhenLoaded); + pendingImage = null; + } + + pendingImage.statusChanged.connect(replaceWhenLoaded); + replaceWhenLoaded(); + } + + // Reload album art when size of container changes + Timer { + id: geometryChangeTimer + interval: 250 + onTriggered: container.loadAlbumArt(); + } + + StackView { + id: albumArt + + anchors.fill: parent + + readonly property string icon: (mpris2Source.currentData && mpris2Source.currentData["Desktop Icon Name"]) || "media-album-cover" + + replaceEnter: Transition { + OpacityAnimator { + from: 0 + to: 1 + duration: PlasmaCore.Units.longDuration + } + } + + replaceExit: Transition { + id: exitTransition + + SequentialAnimation { + PauseAnimation { + duration: PlasmaCore.Units.longDuration + } + + /** + * If the new ratio and the old ratio are different, + * perform a fade-out animation for the old image + * to prevent it from suddenly disappearing. + */ + OpacityAnimator { + id: exitTransitionOpacityAnimator + from: 1 + to: 0 + duration: 0 + } + } + } + + popExit: Transition { + id: popExitTransition + + OpacityAnimator { + from: 1 + to: 0 + duration: PlasmaCore.Units.longDuration + } + } + + Component { + id: albumArtComponent + + Image { // Album Art + horizontalAlignment: Image.AlignHCenter + verticalAlignment: Image.AlignVCenter + fillMode: Image.PreserveAspectFit + + asynchronous: true + cache: false + + StackView.onRemoved: { + source = ""; // HACK: Reduce memory usage + destroy(); + } + } + } + + Component { + id: fallbackIconItem + + PlasmaCore.IconItem { // Fallback + id: fallbackIcon + + anchors.margins: PlasmaCore.Units.largeSpacing * 2 + opacity: 0 + source: albumArt.icon + + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.OutCubic + property: "opacity" + running: true + target: fallbackIcon + to: 1 + } + } + } + + // "No media playing" placeholder message + Component { + id: placeholderMessage + + // Put PlaceholderMessage in Item so PlaceholderMessage will not fill its parent. + Item { + property alias source: message.iconName + + PlasmaExtras.PlaceholderMessage { + id: message + anchors.centerIn: parent + width: parent.width // For text wrap + iconName: albumArt.icon + text: (root.isPlaying || root.state === "paused") ? i18n("No title") : i18n("No media playing") + } + } + } + + Component { + id: busyComponent + + Item { + PC3.BusyIndicator { + id: busyIndicator + anchors.centerIn: parent + opacity: 0 + } + + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.OutCubic + property: "opacity" + running: true + target: busyIndicator + to: 1 + } + } + + } + } + + Loader { + anchors.fill: parent + visible: active + + readonly property bool isLoadingImage: pendingImage !== null && pendingImage.status === Image.Loading + + active: (inCompactRepresentation || Plasmoid.expanded) && (!container.hasImage || isLoadingImage) + asynchronous: true + sourceComponent: root.track ? (isLoadingImage ? busyComponent : fallbackIconItem) : placeholderMessage + } +} + diff --git a/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/CompactRepresentation.qml b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/CompactRepresentation.qml new file mode 100644 index 00000000..7c0dbadf --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/CompactRepresentation.qml @@ -0,0 +1,268 @@ +/* + SPDX-FileCopyrightText: 2022 Fushan Wen + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import QtQml 2.15 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 3.0 as PC3 +import org.kde.plasma.plasmoid 2.0 + +/** + * [Album Art][Now Playing] + */ +MouseArea { + id: compactRepresentation + + Layout.preferredWidth: { + switch (compactRepresentation.layoutForm) { + case CompactRepresentation.LayoutType.VerticalPanel: + case CompactRepresentation.LayoutType.VerticalDesktop: + return compactRepresentation.parent.width; + case CompactRepresentation.LayoutType.HorizontalPanel: + case CompactRepresentation.LayoutType.HorizontalDesktop: + return iconLoader.active ? iconLoader.item.implicitWidth : playerRow.width; + case CompactRepresentation.LayoutType.IconOnly: + default: + return -1; + } + } + Layout.preferredHeight: { + switch (compactRepresentation.layoutForm) { + case CompactRepresentation.LayoutType.VerticalPanel: + return iconLoader.active ? compactRepresentation.parent.width : playerRow.height; + default: + return -1; + } + } + Layout.maximumHeight: Layout.preferredHeight + + enum LayoutType { + Tray, + HorizontalPanel, + VerticalPanel, + HorizontalDesktop, + VerticalDesktop, + IconOnly + } + + property int layoutForm: CompactRepresentation.LayoutType.IconOnly + + Binding on layoutForm { + when: playerRow.active + delayed: true + restoreMode: Binding.RestoreBindingOrValue + value: { + if (compactRepresentation.inTray) { + return CompactRepresentation.LayoutType.Tray; + } else if (compactRepresentation.inPanel) { + return compactRepresentation.isVertical ? CompactRepresentation.LayoutType.VerticalPanel : CompactRepresentation.LayoutType.HorizontalPanel; + } else if (compactRepresentation.parent.width > compactRepresentation.parent.height + playerRow.item.columnSpacing) { + return CompactRepresentation.LayoutType.HorizontalDesktop; + } else if (compactRepresentation.parent.height - compactRepresentation.parent.width >= playerRow.item.labelHeight + playerRow.item.rowSpacing) { + return CompactRepresentation.LayoutType.VerticalDesktop; + } + return CompactRepresentation.LayoutType.IconOnly; + } + } + + readonly property bool isVertical: Plasmoid.formFactor === PlasmaCore.Types.Vertical + readonly property bool inPanel: [PlasmaCore.Types.TopEdge, PlasmaCore.Types.RightEdge, PlasmaCore.Types.BottomEdge, PlasmaCore.Types.LeftEdge].includes(Plasmoid.location) + readonly property bool inTray: parent.objectName === "org.kde.desktop-CompactApplet" + + acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.BackButton | Qt.ForwardButton + hoverEnabled: true + + property int wheelDelta: 0 + + onWheel: { + const service = mpris2Source.serviceForSource(mpris2Source.current) + const operation = service.operationDescription("ChangeVolume") + wheelDelta += wheel.angleDelta.y || wheel.angleDelta.x + while (wheelDelta >= 120) { + wheelDelta -= 120; + operation.delta = volumePercentStep / 100; + operation.showOSD = true; + service.startOperationCall(operation); + } + while (wheelDelta <= -120) { + wheelDelta += 120; + operation.delta = -volumePercentStep / 100; + operation.showOSD = true; + service.startOperationCall(operation); + } + } + + onClicked: { + switch (mouse.button) { + case Qt.MiddleButton: + root.togglePlaying() + break + case Qt.BackButton: + root.action_previous() + break + case Qt.ForwardButton: + root.action_next() + break + default: + Plasmoid.expanded = !Plasmoid.expanded + } + } + + Loader { + id: iconLoader + anchors.fill: parent + visible: active + + active: inTray || !root.track + sourceComponent: PlasmaCore.IconItem { + active: compactRepresentation.containsMouse + source: { + if (root.isPlaying) { + return "media-playback-playing"; + } else if (root.state === "paused") { + return "media-playback-paused"; + } else { + return "media-playback-stopped"; + } + } + } + } + + Loader { + id: playerRow + + width: { + if (!active) { + return 0; + } + switch (compactRepresentation.layoutForm) { + case CompactRepresentation.LayoutType.VerticalPanel: + case CompactRepresentation.LayoutType.VerticalDesktop: + return compactRepresentation.parent.width; + case CompactRepresentation.LayoutType.HorizontalPanel: + return item.implicitWidth; + case CompactRepresentation.LayoutType.HorizontalDesktop: + return Math.min(item.implicitWidth, compactRepresentation.parent.width); + case CompactRepresentation.LayoutType.IconOnly: + default: + return Math.min(compactRepresentation.parent.width, compactRepresentation.parent.height); + } + } + + height: { + if (!active) { + return 0; + } + switch (compactRepresentation.layoutForm) { + case CompactRepresentation.LayoutType.VerticalPanel: + return item.implicitHeight; + case CompactRepresentation.LayoutType.VerticalDesktop: + case CompactRepresentation.LayoutType.HorizontalPanel: + case CompactRepresentation.LayoutType.HorizontalDesktop: + return compactRepresentation.parent.height; + case CompactRepresentation.LayoutType.IconOnly: + default: + return Math.min(compactRepresentation.parent.width, compactRepresentation.parent.height); + } + } + + visible: active + + active: !iconLoader.active + sourceComponent: GridLayout { + id: grid + readonly property real labelHeight: songTitle.contentHeight + + rowSpacing: PlasmaCore.Units.smallSpacing + columnSpacing: rowSpacing + flow: { + switch (compactRepresentation.layoutForm) { + case CompactRepresentation.LayoutType.VerticalPanel: + case CompactRepresentation.LayoutType.VerticalDesktop: + return GridLayout.TopToBottom; + default: + return GridLayout.LeftToRight; + } + } + + Item { + id: spacerItem + visible: compactRepresentation.layoutForm === CompactRepresentation.LayoutType.VerticalDesktop + Layout.fillHeight: true + } + + AlbumArtStackView { + id: albumArt + + Layout.alignment: Qt.AlignVCenter + Layout.preferredWidth: Math.min(compactRepresentation.parent.width, compactRepresentation.parent.height) + Layout.preferredHeight: Layout.preferredWidth + + inCompactRepresentation: true + + Connections { + target: root + + function onAlbumArtChanged() { + albumArt.loadAlbumArt(); + } + } + + Component.onCompleted: albumArt.loadAlbumArt() + } + + ColumnLayout { + Layout.alignment: Qt.AlignVCenter + visible: (compactRepresentation.layoutForm !== CompactRepresentation.LayoutType.VerticalPanel + && compactRepresentation.layoutForm !== CompactRepresentation.LayoutType.IconOnly) + || (compactRepresentation.layoutForm === CompactRepresentation.LayoutType.VerticalPanel + && compactRepresentation.parent.width >= PlasmaCore.Units.gridUnit * 5) + + spacing: 0 + + // Song Title + PC3.Label { + id: songTitle + + Layout.fillWidth: true + Layout.maximumWidth: compactRepresentation.layoutForm === CompactRepresentation.LayoutType.HorizontalPanel ? PlasmaCore.Units.gridUnit * 10 : -1 + + elide: Text.ElideRight + horizontalAlignment: grid.flow === GridLayout.TopToBottom ? Text.AlignHCenter : Text.AlignJustify + maximumLineCount: 1 + text: root.track + textFormat: Text.PlainText + wrapMode: Text.Wrap + } + + // Song Artist + PC3.Label { + id: songArtist + + Layout.fillWidth: true + Layout.maximumWidth: songTitle.Layout.maximumWidth + visible: root.artist && playerRow.height >= songTitle.contentHeight + contentHeight * 0.8 /* For CJK */ + (compactRepresentation.layoutForm === CompactRepresentation.LayoutType.VerticalDesktop ? albumArt.Layout.preferredHeight + grid.rowSpacing : 0) + + elide: Text.ElideRight + font.pointSize: PlasmaCore.Theme.smallestFont.pointSize + horizontalAlignment: songTitle.horizontalAlignment + maximumLineCount: 1 + opacity: 0.6 + text: root.artist + textFormat: Text.PlainText + wrapMode: Text.Wrap + } + } + + Item { + visible: spacerItem.visible + Layout.fillHeight: true + } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/ExpandedRepresentation.qml b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/ExpandedRepresentation.qml new file mode 100644 index 00000000..09ece3d2 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/ExpandedRepresentation.qml @@ -0,0 +1,501 @@ +/* + SPDX-FileCopyrightText: 2013 Sebastian Kügler + SPDX-FileCopyrightText: 2014, 2016 Kai Uwe Broulik + SPDX-FileCopyrightText: 2020 Carson Black + SPDX-FileCopyrightText: 2020 Ismael Asensio + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 as QQC2 +import QtQuick.Layouts 1.1 + +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 3.0 as PlasmaComponents3 +import org.kde.plasma.extras 2.0 as PlasmaExtras +import org.kde.kcoreaddons 1.0 as KCoreAddons +import org.kde.kirigami 2.4 as Kirigami +import QtGraphicalEffects 1.0 + +PlasmaExtras.Representation { + id: expandedRepresentation + FontLoader { + id: sofiaLight + source: "../fonts/SofiaProLight.ttf" + } + FontLoader { + id: fontB + source: "../fonts/SourceSansPro-Semibold.otf" + } + Layout.minimumWidth: Plasmoid.switchWidth + Layout.minimumHeight: Plasmoid.switchHeight + Layout.preferredWidth: PlasmaCore.Units.gridUnit * 20 + Layout.preferredHeight: 212 + Layout.maximumWidth: PlasmaCore.Units.gridUnit * 40 + Layout.maximumHeight: PlasmaCore.Units.gridUnit * 40 + + collapseMarginsHint: true + + readonly property int controlSize: PlasmaCore.Units.iconSizes.medium + + property double position: (mpris2Source.currentData && mpris2Source.currentData.Position) || 0 + readonly property real rate: (mpris2Source.currentData && mpris2Source.currentData.Rate) || 1 + readonly property double length: currentMetadata ? currentMetadata["mpris:length"] || 0 : 0 + readonly property bool canSeek: (mpris2Source.currentData && mpris2Source.currentData.CanSeek) || false + readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software + readonly property var appletInterface: Plasmoid.self + + // only show hours (the default for KFormat) when track is actually longer than an hour + readonly property int durationFormattingOptions: length >= 60*60*1000*1000 ? 0 : KCoreAddons.FormatTypes.FoldHours + + property bool disablePositionUpdate: false + property bool keyPressed: false + + KeyNavigation.down: playerSelector.count ? playerSelector.currentItem : (seekSlider.visible ? seekSlider : seekSlider.KeyNavigation.down) + KeyNavigation.up: seekSlider.KeyNavigation.down + + function retrievePosition() { + var service = mpris2Source.serviceForSource(mpris2Source.current); + var operation = service.operationDescription("GetPosition"); + service.startOperationCall(operation); + } + + Connections { + target: Plasmoid.self + function onExpandedChanged() { + if (Plasmoid.expanded) { + retrievePosition(); + } + } + } + + onPositionChanged: { + // we don't want to interrupt the user dragging the slider + if (!seekSlider.pressed && !keyPressed) { + // we also don't want passive position updates + disablePositionUpdate = true + // Slider refuses to set value beyond its end, make sure "to" is up-to-date first + seekSlider.to = length; + seekSlider.value = position + disablePositionUpdate = false + } + } + + onLengthChanged: { + disablePositionUpdate = true + // When reducing maximumValue, value is clamped to it, however + // when increasing it again it gets its old value back. + // To keep us from seeking to the end of the track when moving + // to a new track, we'll reset the value to zero and ask for the position again + seekSlider.value = 0 + seekSlider.to = length + retrievePosition() + disablePositionUpdate = false + } + + Keys.onPressed: keyPressed = true + + Keys.onReleased: { + keyPressed = false + + if ((event.key == Qt.Key_Tab || event.key == Qt.Key_Backtab) && event.modifiers & Qt.ControlModifier) { + event.accepted = true; + if (root.mprisSourcesModel.length > 2) { + var nextIndex = playerSelector.currentIndex + 1; + if (event.key == Qt.Key_Backtab || event.modifiers & Qt.ShiftModifier) { + nextIndex -= 2; + } + if (nextIndex == root.mprisSourcesModel.length) { + nextIndex = 0; + } + if (nextIndex < 0) { + nextIndex = root.mprisSourcesModel.length - 1; + } + playerSelector.currentIndex = nextIndex; + disablePositionUpdate = true; + mpris2Source.current = root.mprisSourcesModel[nextIndex]["source"]; + disablePositionUpdate = false; + } + } + + if (!event.modifiers) { + event.accepted = true + + if (event.key === Qt.Key_Space || event.key === Qt.Key_K) { + // K is YouTube's key for "play/pause" :) + root.togglePlaying() + } else if (event.key === Qt.Key_P) { + root.action_previous() + } else if (event.key === Qt.Key_N) { + root.action_next() + } else if (event.key === Qt.Key_S) { + root.action_stop() + } else if (event.key === Qt.Key_J) { // TODO ltr languages + // seek back 5s + seekSlider.value = Math.max(0, seekSlider.value - 5000000) // microseconds + seekSlider.moved(); + } else if (event.key === Qt.Key_L) { + // seek forward 5s + seekSlider.value = Math.min(seekSlider.to, seekSlider.value + 5000000) + seekSlider.moved(); + } else if (event.key === Qt.Key_Home) { + seekSlider.value = 0 + seekSlider.moved(); + } else if (event.key === Qt.Key_End) { + seekSlider.value = seekSlider.to + seekSlider.moved(); + } else if (event.key >= Qt.Key_0 && event.key <= Qt.Key_9) { + // jump to percentage, ie. 0 = beginnign, 1 = 10% of total length etc + seekSlider.value = seekSlider.to * (event.key - Qt.Key_0) / 10 + seekSlider.moved(); + } else { + event.accepted = false + } + } + } + + // Album Art Background + Details + Touch area to adjust position or volume + MultiPointTouchArea { + id: touchArea + anchors.fill: parent + clip: true + + maximumTouchPoints: 1 + minimumTouchPoints: 1 + mouseEnabled: false + touchPoints: [ + TouchPoint { + id: point1 + + property bool seeking: false + property bool adjustingVolume: false + + onPressedChanged: if (!pressed) { + seeking = false; + adjustingVolume = false; + } + onSeekingChanged: if (seeking) { + queuedPositionUpdate.stop(); + } else { + seekSlider.moved(); + } + } + ] + + Connections { + enabled: seekSlider.visible && point1.pressed && !point1.adjustingVolume + target: point1 + // Control seek slider + function onXChanged() { + if (!point1.seeking && Math.abs(point1.x - point1.startX) < touchArea.width / 20) { + return; + } + point1.seeking = true; + seekSlider.value = seekSlider.valueAt(Math.max(0, Math.min(1, seekSlider.position + (point1.x - point1.previousX) / touchArea.width))); // microseconds + } + } + + Connections { + enabled: point1.pressed && !point1.seeking + target: point1 + function onYChanged() { + if (!point1.adjustingVolume && Math.abs(point1.y - point1.startY) < touchArea.height / 20) { + return; + } + point1.adjustingVolume = true; + const service = mpris2Source.serviceForSource(mpris2Source.current); + const operation = service.operationDescription("ChangeVolume"); + operation.delta = (point1.previousY - point1.y) / touchArea.height; + service.startOperationCall(operation); + } + } + + + ColumnLayout { // Album Art + Details + id: albumRow + width: parent.width + height: 165 + visible: root.track + anchors.centerIn: parent + AlbumArtStackView { + id: albumArt + anchors.horizontalCenter: parent.horizontalCenter + width: 80 + height: 80 + + Connections { + enabled: Plasmoid.expanded + target: root + + function onAlbumArtChanged() { + albumArt.loadAlbumArt(); + } + } + + Connections { + target: Plasmoid.self + + function onExpandedChanged() { + // NOTE: Don't use strict equality + if (!Plasmoid.expanded + || (albumArt.albumArt.currentItem instanceof Image && albumArt.albumArt.currentItem.source == root.albumArt)) { + return; + } + + albumArt.loadAlbumArt(); + } + } + } + + Timer { + id: seekTimer + interval: 1000 / expandedRepresentation.rate + repeat: true + running: root.isPlaying && Plasmoid.expanded && !keyPressed && interval > 0 && seekSlider.to >= 1000000 + onTriggered: { + // some players don't continuously update the seek slider position via mpris + // add one second; value in microseconds + if (!seekSlider.pressed) { + disablePositionUpdate = true + if (seekSlider.value == seekSlider.to) { + retrievePosition(); + } else { + seekSlider.value += 1000000 + } + disablePositionUpdate = false + } + } + } + ColumnLayout { // Details Column + id: infotrack + visible: root.track + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredWidth: 50 + spacing: 2 + /* + * We use Kirigami.Heading instead of PlasmaExtras.Heading + * to prevent a binding loop caused by the PC2 Label component + * used by PlasmaExtras.Heading + */ + Kirigami.Heading { // Song Title + id: songTitle + level: 1 + + color: (softwareRendering || !albumArt.hasImage) ? PlasmaCore.ColorScope.textColor : "white" + + textFormat: Text.PlainText + wrapMode: Text.Wrap + fontSizeMode: Text.VerticalFit + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + anchors.horizontalCenter: parent.horizontalCenter + text: root.track + font.family: fontB.name + font.pixelSize: 20 + Layout.fillWidth: true + Layout.maximumHeight: PlasmaCore.Units.gridUnit*5 + } + Rectangle { + id: progressBar + anchors.horizontalCenter: parent.horizontalCenter + width: 280 + height: 2 + color: "white" + radius: 12 + opacity: 0.5 + + Rectangle { + id: progressIndicator + width: progressBar.width * (seekSlider.value/seekSlider.to) + height: progressBar.height + color: "white" + radius: progressBar.radius + opacity: 1 + } + } + Kirigami.Heading { // Song Artist + id: songArtist + visible: root.artist + level: 2 + + color: (softwareRendering || !albumArt.hasImage) ? PlasmaCore.ColorScope.textColor : "white" + + textFormat: Text.PlainText + font.family: sofiaLight.name + wrapMode: Text.Wrap + fontSizeMode: Text.VerticalFit + font.pixelSize: 15 + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + anchors.horizontalCenter: parent.horizontalCenter + text: root.artist + Layout.fillWidth: true + Layout.maximumHeight: PlasmaCore.Units.gridUnit*2 + } + + } + RowLayout { // Player Controls + id: playerControls + property bool enabled: root.canControl + property int controlsSize: PlasmaCore.Theme.mSize(PlasmaCore.Theme.defaultFont).height * 3 + + Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: PlasmaCore.Units.smallSpacing + spacing: PlasmaCore.Units.smallSpacing + + PlasmaComponents3.ToolButton { // Previous + id: previousButton + icon.width: expandedRepresentation.controlSize + icon.height: expandedRepresentation.controlSize + Layout.alignment: Qt.AlignVCenter + enabled: playerControls.enabled && root.canGoPrevious + icon.name: LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward" + + display: PlasmaComponents3.AbstractButton.IconOnly + text: i18nc("Play previous track", "Previous Track") + + KeyNavigation.left: shuffleButton + KeyNavigation.right: playPauseButton.enabled ? playPauseButton : playPauseButton.KeyNavigation.right + KeyNavigation.up: playPauseButton.KeyNavigation.up + + onClicked: { + seekSlider.value = 0 // Let the media start from beginning. Bug 362473 + root.action_previous() + } + } + + PlasmaComponents3.ToolButton { // Pause/Play + id: playPauseButton + icon.width: expandedRepresentation.controlSize + icon.height: expandedRepresentation.controlSize + + Layout.alignment: Qt.AlignVCenter + enabled: root.isPlaying ? root.canPause : root.canPlay + icon.name: root.isPlaying ? "media-playback-pause" : "media-playback-start" + + display: PlasmaComponents3.AbstractButton.IconOnly + text: root.isPlaying ? i18nc("Pause playback", "Pause") : i18nc("Start playback", "Play") + + KeyNavigation.left: previousButton.enabled ? previousButton : previousButton.KeyNavigation.left + KeyNavigation.right: nextButton.enabled ? nextButton : nextButton.KeyNavigation.right + KeyNavigation.up: seekSlider.visible ? seekSlider : seekSlider.KeyNavigation.up + + onClicked: root.togglePlaying() + } + + PlasmaComponents3.ToolButton { // Next + id: nextButton + icon.width: expandedRepresentation.controlSize + icon.height: expandedRepresentation.controlSize + Layout.alignment: Qt.AlignVCenter + enabled: playerControls.enabled && root.canGoNext + icon.name: LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward" + + display: PlasmaComponents3.AbstractButton.IconOnly + text: i18nc("Play next track", "Next Track") + + KeyNavigation.left: playPauseButton.enabled ? playPauseButton : playPauseButton.KeyNavigation.left + KeyNavigation.right: repeatButton + KeyNavigation.up: playPauseButton.KeyNavigation.up + + onClicked: { + seekSlider.value = 0 // Let the media start from beginning. Bug 362473 + root.action_next() + } + } + + } + } + } + + ColumnLayout { // Main Column Layout + anchors.fill: parent + anchors.top: parent.top + anchors.topMargin: albumRow.height - infotrack.height + 18 + visible: root.track + + RowLayout { + // Seek Bar + spacing: PlasmaCore.Units.smallSpacing + visible: false + // if there's no "mpris:length" in the metadata, we cannot seek, so hide it in that case + enabled: !root.noPlayer && root.track && expandedRepresentation.length > 0 ? true : false + opacity: enabled ? 1 : 0 + Behavior on opacity { + NumberAnimation { duration: PlasmaCore.Units.longDuration } + } + + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + Layout.maximumWidth: Math.min(PlasmaCore.Units.gridUnit*45, Math.round(expandedRepresentation.width*(7/10))) + + // ensure the layout doesn't shift as the numbers change and measure roughly the longest text that could occur with the current song + + + + PlasmaComponents3.Slider { // Slider + id: seekSlider + Layout.fillWidth: true + z: 999 + value: 0 + visible: false + + KeyNavigation.up: playerSelector.currentItem + KeyNavigation.down: playPauseButton.enabled ? playPauseButton : (playPauseButton.KeyNavigation.left.enabled ? playPauseButton.KeyNavigation.left : playPauseButton.KeyNavigation.right) + Keys.onLeftPressed: { + seekSlider.value = Math.max(0, seekSlider.value - 5000000) // microseconds + seekSlider.moved(); + } + Keys.onRightPressed: { + seekSlider.value = Math.max(0, seekSlider.value + 5000000) // microseconds + seekSlider.moved(); + } + + onMoved: { + if (!disablePositionUpdate) { + // delay setting the position to avoid race conditions + queuedPositionUpdate.restart() + } + } + onPressedChanged: { + // Property binding evaluation is non-deterministic + // so binding visible to pressed and delay to 0 when pressed + // will not make the tooltip show up immediately. + if (pressed) { + seekToolTip.delay = 0; + seekToolTip.visible = true; + } else { + seekToolTip.delay = Qt.binding(() => Kirigami.Units.toolTipDelay); + seekToolTip.visible = Qt.binding(() => seekToolTipHandler.hovered); + } + } + + HoverHandler { + id: seekToolTipHandler + } + + } + + } + + + } + + + Timer { + id: queuedPositionUpdate + interval: 100 + onTriggered: { + if (position == seekSlider.value) { + return; + } + var service = mpris2Source.serviceForSource(mpris2Source.current) + var operation = service.operationDescription("SetPosition") + operation.microseconds = seekSlider.value + service.startOperationCall(operation) + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/main.qml b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/main.qml new file mode 100644 index 00000000..aba4f88a --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/contents/ui/main.qml @@ -0,0 +1,311 @@ +/* + SPDX-FileCopyrightText: 2013 Sebastian Kügler + SPDX-FileCopyrightText: 2014 Kai Uwe Broulik + SPDX-FileCopyrightText: 2020 Ismael Asensio + SPDX-FileCopyrightText: 2024 zayronxio + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +import QtQuick 2.0 +import QtQuick.Layouts 1.1 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.extras 2.0 as PlasmaExtras +import org.kde.plasma.private.mediacontroller 1.0 + +Item { + id: root + + Plasmoid.backgroundHints: "NoBackground" + + opacity: plasmoid.configuration.opacity/100 + property var currentMetadata: mpris2Source.currentData ? mpris2Source.currentData.Metadata : undefined + property string track: { + if (!currentMetadata) { + return "" + } + var xesamTitle = currentMetadata["xesam:title"] + if (xesamTitle) { + return xesamTitle + } + // if no track title is given, print out the file name + var xesamUrl = currentMetadata["xesam:url"] ? currentMetadata["xesam:url"].toString() : "" + if (!xesamUrl) { + return "" + } + var lastSlashPos = xesamUrl.lastIndexOf('/') + if (lastSlashPos < 0) { + return "" + } + var lastUrlPart = xesamUrl.substring(lastSlashPos + 1) + return decodeURIComponent(lastUrlPart) + } + property string artist: { + if (!currentMetadata) { + return "" + } + var xesamArtist = currentMetadata["xesam:artist"] + if (!xesamArtist || xesamArtist.length === 0) { + xesamArtist = currentMetadata["xesam:albumArtist"] || [""] + } + return xesamArtist.join(", ") + } + property string albumArt: currentMetadata ? currentMetadata["mpris:artUrl"] || "" : "" + + readonly property string identity: !root.noPlayer ? mpris2Source.currentData.Identity || mpris2Source.current : "" + + property bool noPlayer: mpris2Source.sources.length <= 1 + + property var mprisSourcesModel: [] + + readonly property bool canControl: (!root.noPlayer && mpris2Source.currentData.CanControl) || false + readonly property bool canGoPrevious: (canControl && mpris2Source.currentData.CanGoPrevious) || false + readonly property bool canGoNext: (canControl && mpris2Source.currentData.CanGoNext) || false + readonly property bool canPlay: (canControl && mpris2Source.currentData.CanPlay) || false + readonly property bool canPause: (canControl && mpris2Source.currentData.CanPause) || false + readonly property bool isPlaying: root.state === "playing" + readonly property bool canRaise: (!root.noPlayer && mpris2Source.currentData.CanRaise) || false + readonly property bool canQuit: (!root.noPlayer && mpris2Source.currentData.CanQuit) || false + + // var instead of bool so we can use "undefined" for "shuffle not supported" + readonly property var shuffle: !root.noPlayer && typeof mpris2Source.currentData.Shuffle === "boolean" + ? mpris2Source.currentData.Shuffle : undefined + readonly property var loopStatus: !root.noPlayer && typeof mpris2Source.currentData.LoopStatus === "string" + ? mpris2Source.currentData.LoopStatus : undefined + + GlobalConfig { + id: config + } + + readonly property int volumePercentStep: config.volumeStep + + Plasmoid.switchWidth: PlasmaCore.Units.gridUnit * 14 + Plasmoid.switchHeight: 212 + Plasmoid.icon: "media-playback-playing" + Plasmoid.toolTipMainText: i18n("No media playing") + Plasmoid.toolTipSubText: identity + Plasmoid.toolTipTextFormat: Text.PlainText + Plasmoid.status: PlasmaCore.Types.PassiveStatus + + function populateContextualActions() { + Plasmoid.clearActions() + + Plasmoid.setAction("open", i18nc("Open player window or bring it to the front if already open", "Open"), "go-up-symbolic") + Plasmoid.action("open").visible = Qt.binding(() => root.canRaise) + Plasmoid.action("open").priority = Plasmoid.LowPriorityAction + + Plasmoid.setAction("previous", i18nc("Play previous track", "Previous Track"), + Qt.application.layoutDirection === Qt.RightToLeft ? "media-skip-forward" : "media-skip-backward"); + Plasmoid.action("previous").enabled = Qt.binding(() => root.canGoPrevious) + Plasmoid.action("previous").visible = Qt.binding(() => root.canControl) + Plasmoid.action("previous").priority = Plasmoid.LowPriorityAction + + Plasmoid.setAction("pause", i18nc("Pause playback", "Pause"), "media-playback-pause") + Plasmoid.action("pause").enabled = Qt.binding(() => root.state === "playing" && root.canPause) + Plasmoid.action("pause").visible = Qt.binding(() => root.canControl && root.state === "playing" && root.canPause) + Plasmoid.action("pause").priority = Plasmoid.LowPriorityAction + + Plasmoid.setAction("play", i18nc("Start playback", "Play"), "media-playback-start") + Plasmoid.action("play").enabled = Qt.binding(() => root.state !== "playing" && root.canPlay) + Plasmoid.action("play").visible = Qt.binding(() => root.canControl && root.state !== "playing") + Plasmoid.action("play").priority = Plasmoid.LowPriorityAction + + Plasmoid.setAction("next", i18nc("Play next track", "Next Track"), + Qt.application.layoutDirection === Qt.RightToLeft ? "media-skip-backward" : "media-skip-forward") + Plasmoid.action("next").enabled = Qt.binding(() => root.canGoNext) + Plasmoid.action("next").visible = Qt.binding(() => root.canControl) + Plasmoid.action("next").priority = Plasmoid.LowPriorityAction + + Plasmoid.setAction("stop", i18nc("Stop playback", "Stop"), "media-playback-stop") + Plasmoid.action("stop").enabled = Qt.binding(() => root.state === "playing" || root.state === "paused") + Plasmoid.action("stop").visible = Qt.binding(() => root.canControl) + Plasmoid.action("stop").priority = Plasmoid.LowPriorityAction + + Plasmoid.setActionSeparator("quitseparator"); + Plasmoid.action("quitseparator").visible = Qt.binding(() => root.canQuit) + Plasmoid.action("quitseparator").priority = Plasmoid.LowPriorityAction + + Plasmoid.setAction("quit", i18nc("Quit player", "Quit"), "application-exit") + Plasmoid.action("quit").visible = Qt.binding(() => root.canQuit) + Plasmoid.action("quit").priority = Plasmoid.LowPriorityAction + } + + // HACK Some players like Amarok take quite a while to load the next track + // this avoids having the plasmoid jump between popup and panel + onStateChanged: { + if (state != "") { + Plasmoid.status = PlasmaCore.Types.ActiveStatus + } else { + updatePlasmoidStatusTimer.restart() + } + } + + Timer { + id: updatePlasmoidStatusTimer + interval: 3000 + onTriggered: { + if (state != "") { + Plasmoid.status = PlasmaCore.Types.ActiveStatus + } else { + Plasmoid.status = PlasmaCore.Types.PassiveStatus + } + } + } + + Plasmoid.compactRepresentation: CompactRepresentation {} + Plasmoid.fullRepresentation: ExpandedRepresentation {} + + PlasmaCore.DataSource { + id: mpris2Source + + readonly property string multiplexSource: "@multiplex" + property string current: multiplexSource + + readonly property var currentData: data[current] + + engine: "mpris2" + connectedSources: sources + + onSourceAdded: { + updateMprisSourcesModel() + } + + onSourceRemoved: { + // if player is closed, reset to multiplex source + if (source === current) { + current = multiplexSource + } + updateMprisSourcesModel() + } + } + + Component.onCompleted: { + plasmoid.removeAction("configure"); + mpris2Source.serviceForSource("@multiplex").enableGlobalShortcuts() + updateMprisSourcesModel() + populateContextualActions() + } + + function togglePlaying() { + if (root.isPlaying) { + if (root.canPause) { + root.action_pause(); + } + } else { + if (root.canPlay) { + root.action_play(); + } + } + } + + function action_open() { + serviceOp(mpris2Source.current, "Raise"); + } + function action_quit() { + serviceOp(mpris2Source.current, "Quit"); + } + + function action_play() { + serviceOp(mpris2Source.current, "Play"); + } + + function action_pause() { + serviceOp(mpris2Source.current, "Pause"); + } + + function action_playPause() { + serviceOp(mpris2Source.current, "PlayPause"); + } + + function action_previous() { + serviceOp(mpris2Source.current, "Previous"); + } + + function action_next() { + serviceOp(mpris2Source.current, "Next"); + } + + function action_stop() { + serviceOp(mpris2Source.current, "Stop"); + } + + function serviceOp(src, op) { + var service = mpris2Source.serviceForSource(src); + var operation = service.operationDescription(op); + return service.startOperationCall(operation); + } + + function updateMprisSourcesModel () { + + var model = [{ + 'text': i18n("Choose player automatically"), + 'icon': 'emblem-favorite', + 'source': mpris2Source.multiplexSource + }] + + var proxyPIDs = []; // for things like plasma-browser-integration + var sources = mpris2Source.sources + for (var i = 0, length = sources.length; i < length; ++i) { + var source = sources[i] + if (source === mpris2Source.multiplexSource) { + continue + } + + const playerData = mpris2Source.data[source]; + // source data is removed before its name is removed from the list + if (!playerData) { + continue; + } + + model.push({ + 'text': playerData["Identity"], + 'icon': playerData["Desktop Icon Name"] || playerData["DesktopEntry"] || "emblem-music-symbolic", + 'source': source + }); + + + if ("kde:pid" in playerData["Metadata"]) { + var proxyPID = playerData["Metadata"]["kde:pid"]; + if (!proxyPIDs.includes(proxyPID)) { + proxyPIDs.push(proxyPID); + } + } + } + + // prefer proxy controls like plasma-browser-integration over browser built-in controls + model = model.filter( item => { + if (mpris2Source.data[item["source"]] && "InstancePid" in mpris2Source.data[item["source"]]) { + return !(proxyPIDs.includes(mpris2Source.data[item["source"]]["InstancePid"])); + } + return true; + }); + + root.mprisSourcesModel = model; + } + + states: [ + State { + name: "playing" + when: !root.noPlayer && mpris2Source.currentData.PlaybackStatus === "Playing" + + PropertyChanges { + target: Plasmoid.self + icon: "media-playback-playing" + toolTipMainText: track + toolTipSubText: artist ? i18nc("@info:tooltip %1 is a musical artist and %2 is an app name", "by %1 (%2)\nMiddle-click to pause\nScroll to adjust volume", artist, identity) : i18nc("@info:tooltip %1 is an app name", "%1\nMiddle-click to pause\nScroll to adjust volume", identity) + } + }, + State { + name: "paused" + when: !root.noPlayer && mpris2Source.currentData.PlaybackStatus === "Paused" + + PropertyChanges { + target: Plasmoid.self + icon: "media-playback-paused" + toolTipMainText: track + toolTipSubText: artist ? i18nc("@info:tooltip %1 is a musical artist and %2 is an app name", "by %1 (paused, %2)\nMiddle-click to play\nScroll to adjust volume", artist, identity) : i18nc("@info:tooltip %1 is an app name", "Paused (%1)\nMiddle-click to play\nScroll to adjust volume", identity) + } + } + ] +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/metadata.json b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/metadata.json new file mode 100644 index 00000000..afc61632 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.mediaSimple/metadata.json @@ -0,0 +1,36 @@ +{ + "KPlugin": { + "Authors": [ + { + "Email": "Zayronxio@gmail.com", + "Name": "Zayronxio" + } + ], + "Category": "Multimedia", + "Description": "Media Player Controls simple", + "EnabledByDefault": true, + "FormFactors": [ + "tablet", + "handset", + "desktop" + ], + "Icon": "applications-multimedia", + "Id": "org.kde.plasma.mediaSimple", + "License": "GPL-2.0+", + "Name": "Widget Music Simple", + "ServiceTypes": [ + "Plasma/Applet" + ], + "Version": "1.0", + "Website": "https://www.kde.org/plasma-desktop" + }, + "X-Plasma-API": "declarativeappletscript", + "X-Plasma-DBusActivationService": "org.mpris.MediaPlayer2.*", + "X-Plasma-MainScript": "ui/main.qml", + "X-Plasma-NotificationArea": "true", + "X-Plasma-NotificationAreaCategory": "SystemServices", + "X-Plasma-Provides": [ + "org.kde.plasma.multimediacontrols" + ], + "X-Plasma-StandAloneApp": true +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/config/config.qml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/config/config.qml new file mode 100644 index 00000000..56bb0466 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/config/config.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n("General") + icon: "preferences-desktop-color" + source: "config/ConfigGeneral.qml" + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/config/main.xml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/config/main.xml new file mode 100644 index 00000000..11dd0de6 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/config/main.xml @@ -0,0 +1,40 @@ + + + + + + + showdesktop + + + + + + run_commands + + + qdbus org.kde.kglobalaccel /component/kmix invokeShortcut "increase_volume" + + + qdbus org.kde.kglobalaccel /component/kmix invokeShortcut "decrease_volume" + + + 8 + + + false + + + 1000 + + + + + + + + + + + + diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/ar/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/ar/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo new file mode 100644 index 00000000..7e3d4f98 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/ar/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/es/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/es/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo new file mode 100644 index 00000000..b95c14f3 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/es/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/fr/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/fr/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo new file mode 100644 index 00000000..cc80b434 Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/fr/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/nl/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/nl/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo new file mode 100644 index 00000000..95ce3b7b Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/nl/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/pt_BR/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/pt_BR/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo new file mode 100644 index 00000000..3d3f478a Binary files /dev/null and b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/locale/pt_BR/LC_MESSAGES/plasma_applet_org.kde.plasma.win7showdesktop.mo differ diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/AppletConfig.qml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/AppletConfig.qml new file mode 100644 index 00000000..d1cb17a3 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/AppletConfig.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 + +QtObject { + id: config + + // Colors + function alpha(c, newAlpha) { + return Qt.rgba(c.r, c.g, c.b, newAlpha) + } + property color defaultEdgeColor: alpha(theme.textColor, 0.4) + property color defaultHoveredColor: theme.buttonBackgroundColor + property color defaultPressedColor: theme.buttonHoverColor + property color edgeColor: plasmoid.configuration.edgeColor || defaultEdgeColor + property color hoveredColor: plasmoid.configuration.hoveredColor || defaultHoveredColor + property color pressedColor: plasmoid.configuration.pressedColor || defaultPressedColor +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/config/ConfigGeneral.qml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/config/ConfigGeneral.qml new file mode 100644 index 00000000..df7bebcf --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/config/ConfigGeneral.qml @@ -0,0 +1,226 @@ + +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.kirigami 2.3 as Kirigami + +import ".." +import "../lib" + +ConfigPage { + id: page + showAppletVersion: true + + property string cfg_click_action: 'showdesktop' + property alias cfg_click_command: click_command.text + + property string cfg_mousewheel_action: 'run_commands' + property alias cfg_mousewheel_up: mousewheel_up.text + property alias cfg_mousewheel_down: mousewheel_down.text + + property bool showDebug: false + property int indentWidth: 24 + + AppletConfig { + id: config + } + + function setClickCommand(command) { + cfg_click_action = 'run_command' + clickGroup_runcommand.checked = true + cfg_click_command = command + } + + function setMouseWheelCommands(up, down) { + cfg_mousewheel_action = 'run_commands' + mousewheelGroup_runcommands.checked = true + cfg_mousewheel_up = up + cfg_mousewheel_down = down + } + + ConfigSection { + title: i18n("Look") + + Kirigami.FormLayout { + Layout.fillWidth: true + + ConfigSpinBox { + Kirigami.FormData.label: i18n("Size:") + configKey: 'size' + suffix: i18n("px") + } + + ConfigColor { + Kirigami.FormData.label: i18n("Edge Color:") + configKey: "edgeColor" + defaultColor: config.defaultEdgeColor + label: "" + } + + ConfigColor { + Kirigami.FormData.label: i18n("Hovered Color:") + configKey: "hoveredColor" + defaultColor: config.defaultHoveredColor + label: "" + } + + ConfigColor { + Kirigami.FormData.label: i18n("Pressed Color:") + configKey: "pressedColor" + defaultColor: config.defaultPressedColor + label: "" + } + } + } + + ExclusiveGroup { id: clickGroup } + ConfigSection { + title: i18n("Click") + + RadioButton { + exclusiveGroup: clickGroup + checked: cfg_click_action == 'showdesktop' + text: i18nd("plasma_applet_org.kde.plasma.showdesktop", "Show Desktop") + onClicked: { + cfg_click_action = 'showdesktop' + } + } + + RadioButton { + exclusiveGroup: clickGroup + checked: cfg_click_action == 'minimizeall' + text: i18ndc("plasma_applet_org.kde.plasma.showdesktop", "@action", "Minimize All Windows") + + onClicked: { + cfg_click_action = 'minimizeall' + } + } + + RadioButton { + id: clickGroup_runcommand + exclusiveGroup: clickGroup + checked: cfg_click_action == 'run_command' + text: i18n("Run Command") + onClicked: { + cfg_click_action = 'run_command' + } + } + RowLayout { + Layout.fillWidth: true + Text { width: indentWidth } // indent + TextField { + Layout.fillWidth: true + id: click_command + } + } + RadioButton { + exclusiveGroup: clickGroup + checked: false + text: i18nd("kwin_effects", "Toggle Present Windows (All desktops)") + property string command: 'qdbus org.kde.kglobalaccel /component/kwin invokeShortcut "ExposeAll"' + onClicked: setClickCommand(command) + } + RadioButton { + exclusiveGroup: clickGroup + checked: false + text: i18nd("kwin_effects", "Toggle Present Windows (Current desktop)") + property string command: 'qdbus org.kde.kglobalaccel /component/kwin invokeShortcut "Expose"' + onClicked: setClickCommand(command) + } + RadioButton { + exclusiveGroup: clickGroup + checked: false + text: i18nd("kwin_effects", "Toggle Present Windows (Window class)") + property string command: 'qdbus org.kde.kglobalaccel /component/kwin invokeShortcut "ExposeClass"' + onClicked: setClickCommand(command) + } + } + + + ExclusiveGroup { id: mousewheelGroup } + ConfigSection { + title: i18n("Mouse Wheel") + + + RadioButton { + id: mousewheelGroup_runcommands + exclusiveGroup: mousewheelGroup + checked: cfg_mousewheel_action == 'run_commands' + text: i18n("Run Commands") + onClicked: { + cfg_mousewheel_action = 'run_commands' + } + } + RowLayout { + Layout.fillWidth: true + Text { width: indentWidth } // indent + Label { + text: i18n("Scroll Up:") + } + TextField { + Layout.fillWidth: true + id: mousewheel_up + } + } + RowLayout { + Layout.fillWidth: true + Text { width: indentWidth } // indent + Label { + text: i18n("Scroll Down:") + } + TextField { + Layout.fillWidth: true + id: mousewheel_down + } + } + + RadioButton { + exclusiveGroup: mousewheelGroup + checked: false + text: i18n("Volume (No UI) (amixer)") + onClicked: setMouseWheelCommands('amixer -q sset Master 10%+', 'amixer -q sset Master 10%-') + } + + RadioButton { + exclusiveGroup: mousewheelGroup + checked: false + text: i18n("Volume (UI) (qdbus)") + property string upCommand: 'qdbus org.kde.kglobalaccel /component/kmix invokeShortcut "increase_volume"' + property string downCommand: 'qdbus org.kde.kglobalaccel /component/kmix invokeShortcut "decrease_volume"' + onClicked: setMouseWheelCommands(upCommand, downCommand) + } + + RadioButton { + exclusiveGroup: mousewheelGroup + checked: false + text: i18n("Switch Desktop (qdbus)") + property string upCommand: 'qdbus org.kde.kglobalaccel /component/kwin invokeShortcut "Switch One Desktop to the Left"' + property string downCommand: 'qdbus org.kde.kglobalaccel /component/kwin invokeShortcut "Switch One Desktop to the Right"' + onClicked: setMouseWheelCommands(upCommand, downCommand) + } + } + + ConfigSection { + title: i18n("Peek") + + Kirigami.FormLayout { + Layout.fillWidth: true + + ConfigCheckBox { + Kirigami.FormData.label: i18n("Show desktop on hover:") + configKey: "peekingEnabled" + text: i18n("Enable") + } + + ConfigSpinBox { + Kirigami.FormData.label: i18n("Peek threshold:") + configKey: 'peekingThreshold' + suffix: i18n("ms") + stepSize: 50 + minimumValue: 0 + } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/AppletVersion.qml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/AppletVersion.qml new file mode 100644 index 00000000..b61caf5e --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/AppletVersion.qml @@ -0,0 +1,49 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.plasmoid 2.0 + +Item { + implicitWidth: label.implicitWidth + implicitHeight: label.implicitHeight + + property string version: "?" + property string metadataFilepath: plasmoid.file("", "../metadata.desktop") + + PlasmaCore.DataSource { + id: executable + engine: "executable" + connectedSources: [] + onNewData: { + var exitCode = data["exit code"] + var exitStatus = data["exit status"] + var stdout = data["stdout"] + var stderr = data["stderr"] + exited(exitCode, exitStatus, stdout, stderr) + disconnectSource(sourceName) // cmd finished + } + function exec(cmd) { + connectSource(cmd) + } + signal exited(int exitCode, int exitStatus, string stdout, string stderr) + } + + Connections { + target: executable + onExited: { + version = stdout.replace('\n', ' ').trim() + } + } + + Label { + id: label + text: i18n("Version: %1", version) + } + + Component.onCompleted: { + var cmd = 'kreadconfig5 --file "' + metadataFilepath + '" --group "Desktop Entry" --key "X-KDE-PluginInfo-Version"' + executable.exec(cmd) + } + +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigCheckBox.qml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigCheckBox.qml new file mode 100644 index 00000000..e2c0d055 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigCheckBox.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +import ".." + +CheckBox { + id: configCheckBox + + property string configKey: '' + checked: plasmoid.configuration[configKey] + onClicked: plasmoid.configuration[configKey] = !plasmoid.configuration[configKey] +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigColor.qml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigColor.qml new file mode 100644 index 00000000..7a7bd9e8 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigColor.qml @@ -0,0 +1,109 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 +import QtQuick.Dialogs 1.2 +import QtQuick.Window 2.2 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +import ".." + +RowLayout { + id: configColor + spacing: 2 + // Layout.fillWidth: true + Layout.maximumWidth: 300 * units.devicePixelRatio + + property alias label: label.text + property alias horizontalAlignment: label.horizontalAlignment + + property string configKey: '' + property string defaultColor: '' + property string value: { + if (configKey) { + return plasmoid.configuration[configKey] + } else { + return "#000" + } + } + + readonly property color defaultColorValue: defaultColor + readonly property color valueColor: { + if (value == '' && defaultColor) { + return defaultColor + } else { + return value + } + } + + onValueChanged: { + if (!textField.activeFocus) { + textField.text = configColor.value + } + if (configKey) { + if (value == defaultColorValue) { + plasmoid.configuration[configKey] = "" + } else { + plasmoid.configuration[configKey] = value + } + } + } + + function setValue(newColor) { + textField.text = newColor + } + + Label { + id: label + text: "Label" + Layout.fillWidth: horizontalAlignment == Text.AlignRight + horizontalAlignment: Text.AlignLeft + } + + MouseArea { + id: mouseArea + width: textField.height + height: textField.height + hoverEnabled: true + + onClicked: dialog.open() + + Rectangle { + anchors.fill: parent + color: configColor.valueColor + border.width: 2 + border.color: parent.containsMouse ? theme.highlightColor : "#BB000000" + } + } + + TextField { + id: textField + placeholderText: defaultColor ? defaultColor : "#AARRGGBB" + Layout.fillWidth: label.horizontalAlignment == Text.AlignLeft + onTextChanged: { + // Make sure the text is: + // Empty (use default) + // or #123 or #112233 or #11223344 before applying the color. + if (text.length === 0 + || (text.indexOf('#') === 0 && (text.length == 4 || text.length == 7 || text.length == 9)) + ) { + configColor.value = text + } + } + } + + ColorDialog { + id: dialog + visible: false + modality: Qt.WindowModal + title: configColor.label + showAlphaChannel: true + color: configColor.valueColor + onCurrentColorChanged: { + if (visible && color != currentColor) { + configColor.value = currentColor + } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigPage.qml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigPage.qml new file mode 100644 index 00000000..1711f632 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigPage.qml @@ -0,0 +1,37 @@ +// Version 4 + +import QtQuick 2.0 +import QtQuick.Layouts 1.0 + +Item { + id: page + Layout.fillWidth: true + default property alias _contentChildren: content.data + implicitHeight: content.implicitHeight + + ColumnLayout { + id: content + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + + // Workaround for crash when using default on a Layout. + // https://bugreports.qt.io/browse/QTBUG-52490 + // Still affecting Qt 5.7.0 + Component.onDestruction: { + while (children.length > 0) { + children[children.length - 1].parent = page + } + } + } + + property alias showAppletVersion: appletVersionLoader.active + Loader { + id: appletVersionLoader + active: false + visible: active + source: "AppletVersion.qml" + anchors.right: parent.right + anchors.bottom: parent.top + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigSection.qml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigSection.qml new file mode 100644 index 00000000..64d303a1 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigSection.qml @@ -0,0 +1,24 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 + +GroupBox { + id: configSection + Layout.fillWidth: true + default property alias _contentChildren: content.data + + ColumnLayout { + id: content + anchors.left: parent.left + anchors.right: parent.right + + // Workaround for crash when using default on a Layout. + // https://bugreports.qt.io/browse/QTBUG-52490 + // Still affecting Qt 5.7.0 + Component.onDestruction: { + while (children.length > 0) { + children[children.length - 1].parent = configSection + } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigSpinBox.qml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigSpinBox.qml new file mode 100644 index 00000000..76c2efb8 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/lib/ConfigSpinBox.qml @@ -0,0 +1,47 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 + +RowLayout { + id: configSpinBox + + property string configKey: '' + property alias decimals: spinBox.decimals + property alias horizontalAlignment: spinBox.horizontalAlignment + property alias maximumValue: spinBox.maximumValue + property alias minimumValue: spinBox.minimumValue + property alias prefix: spinBox.prefix + property alias stepSize: spinBox.stepSize + property alias suffix: spinBox.suffix + property alias value: spinBox.value + + property alias before: labelBefore.text + property alias after: labelAfter.text + + Label { + id: labelBefore + text: "" + visible: text + } + + SpinBox { + id: spinBox + + value: plasmoid.configuration[configKey] + // onValueChanged: plasmoid.configuration[configKey] = value + onValueChanged: serializeTimer.start() + maximumValue: 2147483647 + } + + Label { + id: labelAfter + text: "" + visible: text + } + + Timer { // throttle + id: serializeTimer + interval: 300 + onTriggered: plasmoid.configuration[configKey] = value + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/main.qml b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/main.qml new file mode 100644 index 00000000..fb3cf0de --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/contents/ui/main.qml @@ -0,0 +1,551 @@ +/* + Copyright (C) 2019 Chris Holland + Copyright (C) 2014 Ashish Madeti + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +import QtQuick 2.7 +import QtQuick.Layouts 1.1 + +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +// import org.kde.plasma.components 2.0 as PlasmaComponents + +import org.kde.plasma.private.showdesktop 0.1 as ShowDesktopWidget + +import org.kde.draganddrop 2.0 as DragAndDrop +import org.kde.taskmanager 0.1 as TaskManager + +Item { + id: widget + + Layout.minimumWidth: Layout.maximumWidth + Layout.minimumHeight: Layout.maximumHeight + + // In Latte, widgets are always Mutable. + property bool isInLatte: false // Latte v8 + // Latte will set inEditMode=true when editing the dock. + // https://techbase.kde.org/LatteDock#latteBridge + property QtObject latteBridge: null // Latte v9 + readonly property bool inLatte: latteBridge !== null + + readonly property bool isWidgetUnlocked: { + if (isInLatte) { // Latte v8 + return false + } else if (inLatte) { // Latte v9 + return latteBridge.inEditMode + } else if (plasmoid.immutability != PlasmaCore.Types.Mutable) { // Plasma 5.17 and below + return false + } else { // Plasma 5.18 + return widget.editMode + } + } + + //--- containment.editMode detector + property var containmentInterface: null + readonly property bool editMode: containmentInterface ? containmentInterface.editMode : false + onParentChanged: { + if (parent) { + for (var obj = widget, depth = 0; !!obj; obj = obj.parent, depth++) { + // console.log('depth', depth, 'obj', obj) + if (obj.toString().startsWith('ContainmentInterface')) { + // desktop containment / plasmoidviewer + // Note: This doesn't always work. FolderViewDropArea may not yet have + // ContainmentInterface as a parent when this loop runs. + if (typeof obj['editMode'] === 'boolean') { + // console.log('\t', 'obj.editMode', obj.editMode, typeof obj['editMode']) + widget.containmentInterface = obj + break + } + } else if (obj.toString().startsWith('DeclarativeDropArea')) { + // panel containment + if (typeof obj['Plasmoid'] !== 'undefined' && obj['Plasmoid'].toString().startsWith('ContainmentInterface')) { + if (typeof obj['Plasmoid']['editMode'] === 'boolean') { + // console.log('\t', 'obj.Plasmoid', obj.Plasmoid, typeof obj['Plasmoid']) // ContainmentInterface + // console.log('\t', 'obj.Plasmoid.editMode', obj.Plasmoid.editMode, typeof obj['Plasmoid']['editMode']) + widget.containmentInterface = obj.Plasmoid + break + } + } + } + } + } + } + + //--- + property int iconSize: units.iconSizes.smallMedium + property int size: { + if (isWidgetUnlocked) { + return iconSize + } else { + return Math.max(1, plasmoid.configuration.size) * units.devicePixelRatio + } + } + + AppletConfig { + id: config + } + + //--- + state: { + if (plasmoid.formFactor == PlasmaCore.Types.Vertical) return "vertical" + if (plasmoid.formFactor == PlasmaCore.Types.Horizontal) return "horizontal" + return "square" + } + + states: [ + State { name: "square" + PropertyChanges { + target: widget + Layout.minimumWidth: units.iconSizeHints.desktop + Layout.minimumHeight: units.iconSizeHints.desktop + Layout.maximumWidth: -1 + Layout.maximumHeight: -1 + iconSize: units.iconSizeHints.desktop + } + PropertyChanges { + target: buttonRect + y: 0 + x: 0 + width: plasmoid.width + height: plasmoid.height + } + PropertyChanges { + target: edgeLine + color: "transparent" + anchors.fill: edgeLine.parent + border.color: config.edgeColor + } + }, + State { name: "vertical" // ...panel (fat short button) + // Assume it's on the bottom. Breeze has margins of top=4 right=5 bottom=1 left=N/A + PropertyChanges { + target: widget + Layout.maximumWidth: plasmoid.width + Layout.maximumHeight: widget.size // size + bottomMargin = totalHeight + iconSize: Math.min(plasmoid.width, units.iconSizes.smallMedium) + } + PropertyChanges { + target: buttonRect + rightMargin: 5 + bottomMargin: 5 + } + PropertyChanges { + target: edgeLine + height: 1 * units.devicePixelRatio + } + AnchorChanges { + target: edgeLine + anchors.left: edgeLine.parent.left + anchors.top: edgeLine.parent.top + anchors.right: edgeLine.parent.right + } + }, + State { name: "horizontal" // ...panel (thin tall button) + // Assume it's on the right. Breeze has margins of top=4 right=5 bottom=1 left=N/A + PropertyChanges { + target: widget + Layout.maximumWidth: widget.size // size + rightMargin = totalWidth + Layout.maximumHeight: plasmoid.height + iconSize: Math.min(plasmoid.height, units.iconSizes.smallMedium) + } + PropertyChanges { + target: buttonRect + topMargin: 4 + rightMargin: 5 + bottomMargin: 3 + } + PropertyChanges { + target: edgeLine + width: 1 * units.devicePixelRatio + } + AnchorChanges { + target: edgeLine + anchors.left: edgeLine.parent.left + anchors.top: edgeLine.parent.top + anchors.bottom: edgeLine.parent.bottom + } + } + ] + + Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation + Plasmoid.onActivated: widget.performClick() + + function performClick() { + if (plasmoid.configuration.click_action == 'minimizeall') { + minimizeAll.toggleActive() + } else if (plasmoid.configuration.click_action == 'run_command') { + widget.exec(plasmoid.configuration.click_command) + } else { // Default: showdesktop + showdesktop.showingDesktop = !showdesktop.showingDesktop + } + } + + function performMouseWheelUp() { + widget.exec(plasmoid.configuration.mousewheel_up) + } + + function performMouseWheelDown() { + widget.exec(plasmoid.configuration.mousewheel_down) + } + + //--- ShowDesktop + // https://github.com/KDE/plasma-desktop/blob/master/applets/showdesktop/package/contents/ui/main.qml + ShowDesktopWidget.ShowDesktop { + id: showdesktop + property bool isPeeking: false + onIsPeekingChanged: { + if (isPeeking) { + showingDesktop = true + } + } + + function initPeeking() { + // console.log('initPeeking') + // console.log('showingDesktop', showingDesktop) + // console.log('peekTimer.running', peekTimer.running) + if (!showingDesktop) { + if (plasmoid.configuration.peekingEnabled) { + peekTimer.restart() + } + } + } + + function cancelPeek() { + // console.log('cancelPeek') + // console.log('peekTimer.running', peekTimer.running) + peekTimer.stop() + if (isPeeking) { + isPeeking = false + showingDesktop = false + } + } + } + + //--- MinimizeAll + // https://github.com/KDE/plasma-desktop/blob/master/applets/minimizeall/package/contents/ui/main.qml + QtObject { + id: minimizeAll + property bool active: false + property var minimizedClients: [] //list of persistentmodelindexes from task manager model of clients minimised by us + + property var taskModel: TaskManager.TasksModel { + id: tasksModel + sortMode: TaskManager.TasksModel.SortDisabled + groupMode: TaskManager.TasksModel.GroupDisabled + } + property var taskModelConnection: Connections { + target: tasksModel + enabled: minimizeAll.active + + onActiveTaskChanged: { + if (tasksModel.activeTask.valid) { //to suppress changing focus to non windows, such as the desktop + minimizeAll.active = false + minimizeAll.minimizedClients = [] + } + } + onVirtualDesktopChanged: minimizeAll.deactivate() + onActivityChanged: minimizeAll.deactivate() + } + + function logClientList(clients) { + for (var i = 0; i < clients.length; i++) { + var idx = clients[i] + if (!idx.valid) { + continue + } + console.log(' ', tasksModel.data(idx, TaskManager.AbstractTasksModel.StackingOrder), tasksModel.data(idx, TaskManager.AbstractTasksModel.AppName)) + } + } + + function sortByStackingOrder(clients) { + clients.sort(function(a, b){ + return getClientStackingOrder(a) - getClientStackingOrder(b) + }) + } + + function getClientStackingOrder(idx) { + if (!idx.valid) { + return 0 + } + var stackingOrder = tasksModel.data(idx, TaskManager.AbstractTasksModel.StackingOrder) + return stackingOrder + } + + function activate() { + // console.log('activate') + var clients = [] + for (var i = 0; i < tasksModel.count; i++) { + var idx = tasksModel.makeModelIndex(i) + if (!tasksModel.data(idx, TaskManager.AbstractTasksModel.IsMinimized)) { + tasksModel.requestToggleMinimized(idx) + clients.push(tasksModel.makePersistentModelIndex(i)) + } + } + // logClientList(clients) + sortByStackingOrder(clients) + minimizedClients = clients + active = true + } + + function deactivate() { + // console.log('deactivate') + // logClientList(minimizedClients) + active = false + for (var i = 0; i < minimizedClients.length; i++) { + var idx = minimizedClients[i] + // Client deleted, do nothing + if (!idx.valid) { + continue + } + + // If the user has restored it already, do nothing + if (!tasksModel.data(idx, TaskManager.AbstractTasksModel.IsMinimized)) { + continue + } + tasksModel.requestToggleMinimized(idx) + } + minimizedClients = [] + } + + function toggleActive() { + if (active) { + deactivate() + } else { + activate() + } + } + } + //--- + + Timer { + id: peekTimer + interval: plasmoid.configuration.peekingThreshold + onTriggered: { + showdesktop.isPeeking = true + } + } + + Rectangle { + id: buttonRect + color: "transparent" + + property int topMargin: 0 + property int rightMargin: 0 + property int bottomMargin: 0 + property int leftMargin: 0 + + y: -topMargin + x: -leftMargin + width: leftMargin + plasmoid.width + rightMargin + height: topMargin + plasmoid.height + bottomMargin + + Item { + anchors.fill: parent + + // Rectangle { + // id: surfaceNormal + // anchors.fill: parent + // anchors.topMargin: 1 + // color: "transparent" + // border.color: theme.buttonBackgroundColor + // } + + Rectangle { + id: surfaceHovered + anchors.fill: parent + anchors.topMargin: 1 + color: config.hoveredColor + opacity: 0 + } + + Rectangle { + id: surfacePressed + anchors.fill: parent + anchors.topMargin: 1 + color: config.pressedColor + opacity: 0 + } + + Rectangle { + id: edgeLine + color: "transparent" + border.color: config.edgeColor + border.width: 1 * units.devicePixelRatio + } + + state: { + if (control.containsPress) return "pressed" + if (control.containsMouse) return "hovered" + return "normal" + } + + states: [ + State { name: "normal" }, + State { name: "hovered" + PropertyChanges { + target: surfaceHovered + opacity: 1 + } + }, + State { name: "pressed" + PropertyChanges { + target: surfacePressed + opacity: 1 + } + } + ] + + transitions: [ + Transition { + to: "normal" + //Cross fade from pressed to normal + ParallelAnimation { + NumberAnimation { target: surfaceHovered; property: "opacity"; to: 0; duration: 100 } + NumberAnimation { target: surfacePressed; property: "opacity"; to: 0; duration: 100 } + } + } + ] + + MouseArea { + id: control + anchors.fill: parent + hoverEnabled: true + onClicked: { + if (showdesktop.isPeeking && showdesktop.showingDesktop) { + showdesktop.isPeeking = false + } else { + peekTimer.stop() + + if (true) { + widget.performClick() + } else { + showdesktop.showingDesktop = false + minimizeAll.toggleActive() + } + } + } + onEntered: { + // console.log('onEntered') + showdesktop.initPeeking() + } + onExited: { + // console.log('onExited') + showdesktop.cancelPeek() + } + + + // org.kde.plasma.volume + property int wheelDelta: 0 + onWheel: { + var delta = wheel.angleDelta.y || wheel.angleDelta.x + wheelDelta += delta + // Magic number 120 for common "one click" + // See: http://qt-project.org/doc/qt-5/qml-qtquick-wheelevent.html#angleDelta-prop + while (wheelDelta >= 120) { + wheelDelta -= 120 + widget.performMouseWheelUp() + } + while (wheelDelta <= -120) { + wheelDelta += 120 + widget.performMouseWheelDown() + } + wheel.accepted = true + } + } + + DragAndDrop.DropArea { + anchors.fill: parent + onDragEnter: { + // console.log('showDesktopDropArea.onDragEnter') + // showdesktop.initPeeking() + showdesktop.showingDesktop = true + } + } + } + + // PlasmaComponents.Button { + // anchors.fill: parent + // // anchors.left: parent.left + // // anchors.top: parent.top + 3 + // // anchors.right: parent.right + 5 + // // anchors.bottom: parent.bottom + 5 + // // width: parent.width + // // height: parent.height + // onClicked: showdesktop.showDesktop() + // } + } + + PlasmaCore.IconItem { + anchors.centerIn: parent + visible: widget.isWidgetUnlocked + source: "transform-move" + width: units.iconSizes.smallMedium + height: units.iconSizes.smallMedium + } + + // org.kde.plasma.mediacontrollercompact + PlasmaCore.DataSource { + id: executeSource + engine: "executable" + connectedSources: [] + onNewData: disconnectSource(sourceName) // cmd finished + function getUniqueId(cmd) { + // Note: we assume that 'cmd' is executed quickly so that a previous call + // with the same 'cmd' has already finished (otherwise no new cmd will be + // added because it is already in the list) + // Workaround: We append spaces onto the user's command to workaround this. + var cmd2 = cmd + for (var i = 0; i < 10; i++) { + if (executeSource.connectedSources.includes(cmd2)) { + cmd2 += ' ' + } + } + return cmd2 + } + } + function exec(cmd) { + executeSource.connectSource(executeSource.getUniqueId(cmd)) + } + + + Component.onCompleted: { + // Plasma 5.21 introduced a way to ignore margins. + // * https://invent.kde.org/frameworks/plasma-framework/-/blob/master/src/scriptengines/qml/plasmoid/appletinterface.h#L249 + // * https://invent.kde.org/frameworks/plasma-framework/-/blob/master/src/plasma/plasma.h#L54 + if (plasmoid.hasOwnProperty('constraintHints')) { + plasmoid.constraintHints = PlasmaCore.Types.CanFillArea + } + + plasmoid.setAction("toggleLockWidgets", i18n("Toggle Lock Widgets"), "object-locked") + plasmoid.setAction("showdesktop", i18nd("plasma_applet_org.kde.plasma.showdesktop", "Show Desktop"), "user-desktop") + plasmoid.setAction("minimizeall", i18ndc("plasma_applet_org.kde.plasma.showdesktop", "@action", "Minimize All Windows"), "user-desktop") + } + + //--- + function action_toggleLockWidgets() { + var cmd = 'qdbus org.kde.plasmashell /PlasmaShell evaluateScript "lockCorona(!locked)"' + widget.exec(cmd) + } + + function action_showdesktop() { + showdesktop.showingDesktop = true + } + + function action_minimizeall() { + minimizeAll.toggleActive() + } +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/metadata.desktop b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/metadata.desktop new file mode 100644 index 00000000..957f4ba5 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/metadata.desktop @@ -0,0 +1,32 @@ +[Desktop Entry] +Name=Show Desktop (Win7) +Comment=Show the Plasma desktop + +Type=Service +Icon=user-desktop + +X-KDE-PluginInfo-Author=Chris Holland +X-KDE-PluginInfo-Email=zrenfire@gmail.com +X-KDE-PluginInfo-Name=org.kde.plasma.win7showdesktop +X-KDE-PluginInfo-Version=13 +X-KDE-PluginInfo-Website=https://github.com/Zren/plasma-applet-win7showdesktop +X-KDE-PluginInfo-Category=Windows and Tasks +X-KDE-PluginInfo-License=GPL +X-Plasma-MainScript=ui/main.qml +X-Plasma-Provides=org.kde.plasma.windowmanagement + +X-Plasma-API=declarativeappletscript +X-KDE-ServiceTypes=Plasma/Applet +X-KDE-FormFactors=desktop + + +Name[ar]=أظهر سطح المكتب (Win7) +Name[es]=Mostrar el escritorio (Win7) +Name[fr]=Afficher un bureau (Win7) +Name[nl]=Bureaublad tonen (Win7) +Name[pt_BR]=Exibir a área de trabalho (Win7) +Comment[ar]=أظهر سطح مكتب بلازما +Comment[es]=Mostrar el escritorio de Plasma +Comment[fr]=Afficher le bureau Plasma +Comment[nl]=Toont het Plasma-bureaublad +Comment[pt_BR]=Mostra a área de trabalho do Plasma diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/metadata.json b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/metadata.json new file mode 100644 index 00000000..dc661bd8 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/metadata.json @@ -0,0 +1,39 @@ +{ + "KPlugin": { + "Authors": [ + { + "Email": "zrenfire@gmail.com", + "Name": "Chris Holland" + } + ], + "Category": "Windows and Tasks", + "Description": "Show the Plasma desktop", + "Description[ar]": "أظهر سطح مكتب بلازما", + "Description[es]": "Mostrar el escritorio de Plasma", + "Description[fr]": "Afficher le bureau Plasma", + "Description[nl]": "Toont het Plasma-bureaublad", + "Description[pt_BR]": "Mostra a área de trabalho do Plasma", + "FormFactors": [ + "desktop" + ], + "Icon": "user-desktop", + "Id": "org.kde.plasma.win7showdesktop", + "License": "GPL", + "Name": "Show Desktop (Win7)", + "Name[ar]": "أظهر سطح المكتب (Win7)", + "Name[es]": "Mostrar el escritorio (Win7)", + "Name[fr]": "Afficher un bureau (Win7)", + "Name[nl]": "Bureaublad tonen (Win7)", + "Name[pt_BR]": "Exibir a área de trabalho (Win7)", + "ServiceTypes": [ + "Plasma/Applet" + ], + "Version": "13", + "Website": "https://github.com/Zren/plasma-applet-win7showdesktop" + }, + "X-Plasma-API": "declarativeappletscript", + "X-Plasma-MainScript": "ui/main.qml", + "X-Plasma-Provides": [ + "org.kde.plasma.windowmanagement" + ] +} diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/ReadMe.md b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/ReadMe.md new file mode 100644 index 00000000..2dd504a2 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/ReadMe.md @@ -0,0 +1,43 @@ +> Version 7 of Zren's i18n scripts. + +With KDE Frameworks v5.37 and above, translations are bundled with the `*.plasmoid` file downloaded from the store. + +## Install Translations + +Go to `~/.local/share/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/` and run `sh ./build --restartplasma`. + +## New Translations + +1. Fill out [`template.pot`](template.pot) with your translations then open a [new issue](https://github.com/Zren/plasma-applet-win7showdesktop/issues/new), name the file `spanish.txt`, attach the txt file to the issue (drag and drop). + +Or if you know how to make a pull request + +1. Copy the `template.pot` file and name it your locale's code (Eg: `en`/`de`/`fr`) with the extension `.po`. Then fill out all the `msgstr ""`. + +## Scripts + +* `sh ./merge` will parse the `i18n()` calls in the `*.qml` files and write it to the `template.pot` file. Then it will merge any changes into the `*.po` language files. +* `sh ./build` will convert the `*.po` files to it's binary `*.mo` version and move it to `contents/locale/...` which will bundle the translations in the `*.plasmoid` without needing the user to manually install them. +* `sh ./plasmoidlocaletest` will run `./build` then `plasmoidviewer` (part of `plasma-sdk`). + +## Links + +* https://zren.github.io/kde/docs/widget/#translations-i18n +* https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems +* https://api.kde.org/frameworks/ki18n/html/prg_guide.html + +## Examples + +* https://l10n.kde.org/stats/gui/trunk-kf5/team/fr/plasma-desktop/ +* https://github.com/psifidotos/nowdock-plasmoid/tree/master/po +* https://github.com/kotelnik/plasma-applet-redshift-control/tree/master/translations + +## Status +| Locale | Lines | % Done| +|----------|---------|-------| +| Template | 25 | | +| ar | 5/25 | 20% | +| es | 25/25 | 100% | +| fr | 5/25 | 20% | +| nl | 25/25 | 100% | +| pt_BR | 20/25 | 80% | diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/ar.po b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/ar.po new file mode 100644 index 00000000..0c24a9e0 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/ar.po @@ -0,0 +1,116 @@ +# Translation of win7showdesktop in ar +# Copyright (C) 2022 +# This file is distributed under the same license as the win7showdesktop package. +# FIRST AUTHOR , YEAR. +msgid "" +msgstr "" +"Project-Id-Version: win7showdesktop\n" +"Report-Msgid-Bugs-To: https://github.com/Zren/plasma-applet-win7showdesktop\n" +"POT-Creation-Date: 2023-08-16 12:36-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: ar \n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Show Desktop (Win7)" +msgstr "أظهر سطح المكتب (Win7)" + +#: ../metadata.desktop +msgid "Show the Plasma desktop" +msgstr "أظهر سطح مكتب بلازما" + +#: ../contents/config/config.qml +msgid "General" +msgstr "عامّ" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Look" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Size:" +msgstr "الحجم:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "px" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Edge Color:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Hovered Color:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Pressed Color:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Click" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Command" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Mouse Wheel" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Commands" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Up:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Down:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (No UI) (amixer)" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (UI) (qdbus)" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Switch Desktop (qdbus)" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Show desktop on hover:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Enable" +msgstr "مكّن" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek threshold:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "ms" +msgstr "" + +#: ../contents/ui/lib/AppletVersion.qml +msgid "Version: %1" +msgstr "" + +#: ../contents/ui/main.qml +msgid "Toggle Lock Widgets" +msgstr "" diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/build b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/build new file mode 100755 index 00000000..c88cd5d5 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/build @@ -0,0 +1,53 @@ +#!/bin/sh +# Version: 6 + +# This script will convert the *.po files to *.mo files, rebuilding the package/contents/locale folder. +# Feature discussion: https://phabricator.kde.org/D5209 +# Eg: contents/locale/fr_CA/LC_MESSAGES/plasma_applet_org.kde.plasma.eventcalendar.mo + +DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` +plasmoidName=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Name"` +website=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Website"` +bugAddress="$website" +packageRoot=".." # Root of translatable sources +projectName="plasma_applet_${plasmoidName}" # project name + +#--- +if [ -z "$plasmoidName" ]; then + echo "[build] Error: Couldn't read plasmoidName." + exit +fi + +if [ -z "$(which msgfmt)" ]; then + echo "[build] Error: msgfmt command not found. Need to install gettext" + echo "[build] Running 'sudo apt install gettext'" + sudo apt install gettext + echo "[build] gettext installation should be finished. Going back to installing translations." +fi + +#--- +echo "[build] Compiling messages" + +catalogs=`find . -name '*.po' | sort` +for cat in $catalogs; do + echo "$cat" + catLocale=`basename ${cat%.*}` + msgfmt -o "${catLocale}.mo" "$cat" + + installPath="$DIR/../contents/locale/${catLocale}/LC_MESSAGES/${projectName}.mo" + + echo "[build] Install to ${installPath}" + mkdir -p "$(dirname "$installPath")" + mv "${catLocale}.mo" "${installPath}" +done + +echo "[build] Done building messages" + +if [ "$1" = "--restartplasma" ]; then + echo "[build] Restarting plasmashell" + killall plasmashell + kstart5 plasmashell + echo "[build] Done restarting plasmashell" +else + echo "[build] (re)install the plasmoid and restart plasmashell to test." +fi diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/es.po b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/es.po new file mode 100644 index 00000000..b8598a37 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/es.po @@ -0,0 +1,118 @@ +# Translation of win7showdesktop in spanish +# Copyright (C) 2019 +# This file is distributed under the same license as the win7showdesktop package. +# WUniversales , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: win7showdesktop \n" +"Report-Msgid-Bugs-To: https://github.com/Zren/plasma-applet-win7showdesktop\n" +"POT-Creation-Date: 2023-08-16 12:36-0400\n" +"PO-Revision-Date: 2019-10-19 12:36\n" +"Last-Translator: wunivesales \n" +"Language-Team: Spanish \n" +"Language: Spanish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Show Desktop (Win7)" +msgstr "Mostrar el escritorio (Win7)" + +#: ../metadata.desktop +msgid "Show the Plasma desktop" +msgstr "Mostrar el escritorio de Plasma" + +#: ../contents/config/config.qml +msgid "General" +msgstr "General" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Look" +msgstr "Apariencia" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Size:" +msgstr "Tamaño:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "px" +msgstr "px" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Edge Color:" +msgstr "Color del borde:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Hovered Color:" +msgstr "Color del hover:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Pressed Color:" +msgstr "Color al pulsar:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Click" +msgstr "Click" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Command" +msgstr "Ejecutar comando:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Mouse Wheel" +msgstr "Rueda del ratón" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Commands" +msgstr "Ejecutar comandos" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Up:" +msgstr "Desplazarse hacia arriba:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Down:" +msgstr "Desplazarse hacia abajo:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (No UI) (amixer)" +msgstr "Volumen (Sin UI) (amixer)" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (UI) (qdbus)" +msgstr "Volumen (Con UI) (qdbus)" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Switch Desktop (qdbus)" +msgstr "Cambiar escritorio (qdbus)" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek" +msgstr "Previsualizar" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Show desktop on hover:" +msgstr "Mostrar escritorio al pasar el mouse:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Enable" +msgstr "Activar" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek threshold:" +msgstr "Límite de visualización:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "ms" +msgstr "ms" + +#: ../contents/ui/lib/AppletVersion.qml +msgid "Version: %1" +msgstr "Versión: %1" + +#: ../contents/ui/main.qml +msgid "Toggle Lock Widgets" +msgstr "Alternar widgets bloqueados" diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/fr.po b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/fr.po new file mode 100644 index 00000000..84d96920 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/fr.po @@ -0,0 +1,116 @@ +# Translation of win7showdesktop in fr +# Copyright (C) 2022 +# This file is distributed under the same license as the win7showdesktop package. +# FIRST AUTHOR , YEAR. +msgid "" +msgstr "" +"Project-Id-Version: win7showdesktop\n" +"Report-Msgid-Bugs-To: https://github.com/Zren/plasma-applet-win7showdesktop\n" +"POT-Creation-Date: 2023-08-16 12:36-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: fr \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Show Desktop (Win7)" +msgstr "Afficher un bureau (Win7)" + +#: ../metadata.desktop +msgid "Show the Plasma desktop" +msgstr "Afficher le bureau Plasma" + +#: ../contents/config/config.qml +msgid "General" +msgstr "Général" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Look" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Size:" +msgstr "Taille : " + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "px" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Edge Color:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Hovered Color:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Pressed Color:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Click" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Command" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Mouse Wheel" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Commands" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Up:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Down:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (No UI) (amixer)" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (UI) (qdbus)" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Switch Desktop (qdbus)" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Show desktop on hover:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Enable" +msgstr "Activer" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek threshold:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "ms" +msgstr "" + +#: ../contents/ui/lib/AppletVersion.qml +msgid "Version: %1" +msgstr "" + +#: ../contents/ui/main.qml +msgid "Toggle Lock Widgets" +msgstr "" diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/merge b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/merge new file mode 100755 index 00000000..283deb34 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/merge @@ -0,0 +1,239 @@ +#!/bin/sh +# Version: 22 + +# https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems +# https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems/Outside_KDE_repositories +# https://invent.kde.org/sysadmin/l10n-scripty/-/blob/master/extract-messages.sh + +DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` +plasmoidName=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Name"` +widgetName="${plasmoidName##*.}" # Strip namespace +website=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Website"` +bugAddress="$website" +packageRoot=".." # Root of translatable sources +projectName="plasma_applet_${plasmoidName}" # project name + +#--- +if [ -z "$plasmoidName" ]; then + echo "[merge] Error: Couldn't read plasmoidName." + exit +fi + +if [ -z "$(which xgettext)" ]; then + echo "[merge] Error: xgettext command not found. Need to install gettext" + echo "[merge] Running 'sudo apt install gettext'" + sudo apt install gettext + echo "[merge] gettext installation should be finished. Going back to merging translations." +fi + +#--- +echo "[merge] Extracting messages" +potArgs="--from-code=UTF-8 --width=200 --add-location=file" + +# Note: xgettext v0.20.1 (Kubuntu 20.04) and below will attempt to translate Icon, +# so we need to specify Name, GenericName, Comment, and Keywords. +# https://github.com/Zren/plasma-applet-lib/issues/1 +# https://savannah.gnu.org/support/?108887 +find "${packageRoot}" -name '*.desktop' | sort > "${DIR}/infiles.list" +xgettext \ + ${potArgs} \ + --files-from="${DIR}/infiles.list" \ + --language=Desktop \ + -k -kName -kGenericName -kComment -kKeywords \ + -D "${packageRoot}" \ + -D "${DIR}" \ + -o "template.pot.new" \ + || \ + { echo "[merge] error while calling xgettext. aborting."; exit 1; } + +sed -i 's/"Content-Type: text\/plain; charset=CHARSET\\n"/"Content-Type: text\/plain; charset=UTF-8\\n"/' "template.pot.new" + +# See Ki18n's extract-messages.sh for a full example: +# https://invent.kde.org/sysadmin/l10n-scripty/-/blob/master/extract-messages.sh#L25 +# The -kN_ and -kaliasLocale keywords are mentioned in the Outside_KDE_repositories wiki. +# We don't need -kN_ since we don't use intltool-extract but might as well keep it. +# I have no idea what -kaliasLocale is used for. Googling aliasLocale found only listed kde1 code. +# We don't need to parse -ki18nd since that'll extract messages from other domains. +find "${packageRoot}" -name '*.cpp' -o -name '*.h' -o -name '*.c' -o -name '*.qml' -o -name '*.js' | sort > "${DIR}/infiles.list" +xgettext \ + ${potArgs} \ + --files-from="${DIR}/infiles.list" \ + -C -kde \ + -ci18n \ + -ki18n:1 -ki18nc:1c,2 -ki18np:1,2 -ki18ncp:1c,2,3 \ + -kki18n:1 -kki18nc:1c,2 -kki18np:1,2 -kki18ncp:1c,2,3 \ + -kxi18n:1 -kxi18nc:1c,2 -kxi18np:1,2 -kxi18ncp:1c,2,3 \ + -kkxi18n:1 -kkxi18nc:1c,2 -kkxi18np:1,2 -kkxi18ncp:1c,2,3 \ + -kI18N_NOOP:1 -kI18NC_NOOP:1c,2 \ + -kI18N_NOOP2:1c,2 -kI18N_NOOP2_NOSTRIP:1c,2 \ + -ktr2i18n:1 -ktr2xi18n:1 \ + -kN_:1 \ + -kaliasLocale \ + --package-name="${widgetName}" \ + --msgid-bugs-address="${bugAddress}" \ + -D "${packageRoot}" \ + -D "${DIR}" \ + --join-existing \ + -o "template.pot.new" \ + || \ + { echo "[merge] error while calling xgettext. aborting."; exit 1; } + +sed -i 's/# SOME DESCRIPTIVE TITLE./'"# Translation of ${widgetName} in LANGUAGE"'/' "template.pot.new" +sed -i 's/# Copyright (C) YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/'"# Copyright (C) $(date +%Y)"'/' "template.pot.new" + +if [ -f "template.pot" ]; then + newPotDate=`grep "POT-Creation-Date:" template.pot.new | sed 's/.\{3\}$//'` + oldPotDate=`grep "POT-Creation-Date:" template.pot | sed 's/.\{3\}$//'` + sed -i 's/'"${newPotDate}"'/'"${oldPotDate}"'/' "template.pot.new" + changes=`diff "template.pot" "template.pot.new"` + if [ ! -z "$changes" ]; then + # There's been changes + sed -i 's/'"${oldPotDate}"'/'"${newPotDate}"'/' "template.pot.new" + mv "template.pot.new" "template.pot" + + addedKeys=`echo "$changes" | grep "> msgid" | cut -c 9- | sort` + removedKeys=`echo "$changes" | grep "< msgid" | cut -c 9- | sort` + echo "" + echo "Added Keys:" + echo "$addedKeys" + echo "" + echo "Removed Keys:" + echo "$removedKeys" + echo "" + + else + # No changes + rm "template.pot.new" + fi +else + # template.pot didn't already exist + mv "template.pot.new" "template.pot" +fi + +potMessageCount=`expr $(grep -Pzo 'msgstr ""\n(\n|$)' "template.pot" | grep -c 'msgstr ""')` +echo "| Locale | Lines | % Done|" > "./Status.md" +echo "|----------|---------|-------|" >> "./Status.md" +entryFormat="| %-8s | %7s | %5s |" +templateLine=`perl -e "printf(\"$entryFormat\", \"Template\", \"${potMessageCount}\", \"\")"` +echo "$templateLine" >> "./Status.md" + +rm "${DIR}/infiles.list" +echo "[merge] Done extracting messages" + +#--- +echo "[merge] Merging messages" +catalogs=`find . -name '*.po' | sort` +for cat in $catalogs; do + echo "[merge] $cat" + catLocale=`basename ${cat%.*}` + + widthArg="" + catUsesGenerator=`grep "X-Generator:" "$cat"` + if [ -z "$catUsesGenerator" ]; then + widthArg="--width=400" + fi + + compendiumArg="" + if [ ! -z "$COMPENDIUM_DIR" ]; then + langCode=`basename "${cat%.*}"` + compendiumPath=`realpath "$COMPENDIUM_DIR/compendium-${langCode}.po"` + if [ -f "$compendiumPath" ]; then + echo "compendiumPath=$compendiumPath" + compendiumArg="--compendium=$compendiumPath" + fi + fi + + cp "$cat" "$cat.new" + sed -i 's/"Content-Type: text\/plain; charset=CHARSET\\n"/"Content-Type: text\/plain; charset=UTF-8\\n"/' "$cat.new" + + msgmerge \ + ${widthArg} \ + --add-location=file \ + --no-fuzzy-matching \ + ${compendiumArg} \ + -o "$cat.new" \ + "$cat.new" "${DIR}/template.pot" + + sed -i 's/# SOME DESCRIPTIVE TITLE./'"# Translation of ${widgetName} in ${catLocale}"'/' "$cat.new" + sed -i 's/# Translation of '"${widgetName}"' in LANGUAGE/'"# Translation of ${widgetName} in ${catLocale}"'/' "$cat.new" + sed -i 's/# Copyright (C) YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/'"# Copyright (C) $(date +%Y)"'/' "$cat.new" + + poEmptyMessageCount=`expr $(grep -Pzo 'msgstr ""\n(\n|$)' "$cat.new" | grep -c 'msgstr ""')` + poMessagesDoneCount=`expr $potMessageCount - $poEmptyMessageCount` + poCompletion=`perl -e "printf(\"%d\", $poMessagesDoneCount * 100 / $potMessageCount)"` + poLine=`perl -e "printf(\"$entryFormat\", \"$catLocale\", \"${poMessagesDoneCount}/${potMessageCount}\", \"${poCompletion}%\")"` + echo "$poLine" >> "./Status.md" + + # mv "$cat" "$cat.old" + mv "$cat.new" "$cat" +done +echo "[merge] Done merging messages" + +#--- +echo "[merge] Updating .desktop file" + +# Generate LINGUAS for msgfmt +if [ -f "$DIR/LINGUAS" ]; then + rm "$DIR/LINGUAS" +fi +touch "$DIR/LINGUAS" +for cat in $catalogs; do + catLocale=`basename ${cat%.*}` + echo "${catLocale}" >> "$DIR/LINGUAS" +done + +cp -f "$DIR/../metadata.desktop" "$DIR/template.desktop" +sed -i '/^Name\[/ d; /^GenericName\[/ d; /^Comment\[/ d; /^Keywords\[/ d' "$DIR/template.desktop" + +msgfmt \ + --desktop \ + --template="$DIR/template.desktop" \ + -d "$DIR/" \ + -o "$DIR/new.desktop" + +# Delete empty msgid messages that used the po header +if [ ! -z "$(grep '^Name=$' "$DIR/new.desktop")" ]; then + echo "[merge] Name in metadata.desktop is empty!" + sed -i '/^Name\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^GenericName=$' "$DIR/new.desktop")" ]; then + echo "[merge] GenericName in metadata.desktop is empty!" + sed -i '/^GenericName\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^Comment=$' "$DIR/new.desktop")" ]; then + echo "[merge] Comment in metadata.desktop is empty!" + sed -i '/^Comment\[/ d' "$DIR/new.desktop" +fi +if [ ! -z "$(grep '^Keywords=$' "$DIR/new.desktop")" ]; then + echo "[merge] Keywords in metadata.desktop is empty!" + sed -i '/^Keywords\[/ d' "$DIR/new.desktop" +fi + +# Place translations at the bottom of the desktop file. +translatedLines=`cat "$DIR/new.desktop" | grep "]="` +if [ ! -z "${translatedLines}" ]; then + sed -i '/^Name\[/ d; /^GenericName\[/ d; /^Comment\[/ d; /^Keywords\[/ d' "$DIR/new.desktop" + if [ "$(tail -c 2 "$DIR/new.desktop" | wc -l)" != "2" ]; then + # Does not end with 2 empty lines, so add an empty line. + echo "" >> "$DIR/new.desktop" + fi + echo "${translatedLines}" >> "$DIR/new.desktop" +fi + +# Cleanup +mv "$DIR/new.desktop" "$DIR/../metadata.desktop" +rm "$DIR/template.desktop" +rm "$DIR/LINGUAS" + +#--- +# Populate ReadMe.md +echo "[merge] Updating translate/ReadMe.md" +sed -i -E 's`share\/plasma\/plasmoids\/(.+)\/translate`share/plasma/plasmoids/'"${plasmoidName}"'/translate`' ./ReadMe.md +if [[ "$website" == *"github.com"* ]]; then + sed -i -E 's`\[new issue\]\(https:\/\/github\.com\/(.+)\/(.+)\/issues\/new\)`[new issue]('"${website}"'/issues/new)`' ./ReadMe.md +fi +sed -i '/^|/ d' ./ReadMe.md # Remove status table from ReadMe +cat ./Status.md >> ./ReadMe.md +rm ./Status.md + +echo "[merge] Done" diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/nl.po b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/nl.po new file mode 100644 index 00000000..42f74fcb --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/nl.po @@ -0,0 +1,119 @@ +# Translation of win7showdesktop in nl +# Copyright (C) 2019 +# This file is distributed under the same license as the win7showdesktop package. +# +# Heimen Stoffels , 2019. +msgid "" +msgstr "" +"Project-Id-Version: win7showdesktop\n" +"Report-Msgid-Bugs-To: https://github.com/Zren/plasma-applet-win7showdesktop\n" +"POT-Creation-Date: 2023-08-16 12:36-0400\n" +"PO-Revision-Date: 2020-03-30 13:57+0200\n" +"Last-Translator: Heimen Stoffels \n" +"Language-Team: Dutch \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 2.3\n" + +#: ../metadata.desktop +msgid "Show Desktop (Win7)" +msgstr "Bureaublad tonen (Win7)" + +#: ../metadata.desktop +msgid "Show the Plasma desktop" +msgstr "Toont het Plasma-bureaublad" + +#: ../contents/config/config.qml +msgid "General" +msgstr "Algemeen" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Look" +msgstr "Uiterlijk" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Size:" +msgstr "Grootte:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "px" +msgstr "px" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Edge Color:" +msgstr "Randkleur:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Hovered Color:" +msgstr "Kleur bij tonen zonder klikken:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Pressed Color:" +msgstr "Kleur bij indrukken:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Click" +msgstr "Klikken" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Command" +msgstr "Opdracht uitvoeren" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Mouse Wheel" +msgstr "Scrollwiel" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Commands" +msgstr "Opdrachten uitvoeren" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Up:" +msgstr "Omhoogscrollen:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Down:" +msgstr "Omlaagscrollen:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (No UI) (amixer)" +msgstr "Volume (zonder venster - amixer)" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (UI) (qdbus)" +msgstr "Volume (met venster - qdbus)" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Switch Desktop (qdbus)" +msgstr "Overschakelen naar ander bureaublad (qdbus)" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek" +msgstr "Gluren" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Show desktop on hover:" +msgstr "Bureaublad tonen zonder klikken:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Enable" +msgstr "Inschakelen" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek threshold:" +msgstr "Gluurvertraging:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "ms" +msgstr "ms" + +#: ../contents/ui/lib/AppletVersion.qml +msgid "Version: %1" +msgstr "Versie: %1" + +#: ../contents/ui/main.qml +msgid "Toggle Lock Widgets" +msgstr "Widgets ver-/ontgrendelen" diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/plasmoidlocaletest b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/plasmoidlocaletest new file mode 100755 index 00000000..dacdedb1 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/plasmoidlocaletest @@ -0,0 +1,181 @@ +#!/bin/bash +# Version 9 +# Requires plasmoidviewer v5.13.0 + +function checkIfLangInstalled { + if [ -x "$(command -v dpkg)" ]; then + dpkg -l ${1} >/dev/null 2>&1 || ( \ + echo -e "${1} not installed.\nInstalling now before continuing.\n" \ + ; sudo apt install ${1} \ + ) || ( \ + echo -e "\nError trying to install ${1}\nPlease run 'sudo apt install ${1}'\n" \ + ; exit 1 \ + ) + elif [ -x "$(command -v pacman)" ]; then + # TODO: run `locale -a` and check if the locale is enabled. + if false; then + # https://wiki.archlinux.org/index.php/Locale + # Uncomment the locale in /etc/locale.gen + # Then run `locale-gen` + echo -e "\nPlease install this locale in System Settings first.\n" + exit 1 + else + echo "" + fi + else + echo -e "\nPackage manager not recognized. If the widget is not translated, please install the package '${1}'\n" + fi +} + +langInput="${1}" +lang="" +languagePack="" + +if [[ "$langInput" =~ ":" ]]; then # String contains a colon so assume it's a locale code. + lang="${langInput}" + IFS=: read -r l1 l2 <<< "${lang}" + languagePack="language-pack-${l2}" +fi + +# https://stackoverflow.com/questions/3191664/list-of-all-locales-and-their-short-codes/28357857#28357857 +declare -a langArr=( + "af_ZA:af:Afrikaans (South Africa)" + "ak_GH:ak:Akan (Ghana)" + "am_ET:am:Amharic (Ethiopia)" + "ar_EG:ar:Arabic (Egypt)" + "as_IN:as:Assamese (India)" + "az_AZ:az:Azerbaijani (Azerbaijan)" + "be_BY:be:Belarusian (Belarus)" + "bem_ZM:bem:Bemba (Zambia)" + "bg_BG:bg:Bulgarian (Bulgaria)" + "bo_IN:bo:Tibetan (India)" + "bs_BA:bs:Bosnian (Bosnia and Herzegovina)" + "ca_ES:ca:Catalan (Spain)" + "chr_US:ch:Cherokee (United States)" + "cs_CZ:cs:Czech (Czech Republic)" + "cy_GB:cy:Welsh (United Kingdom)" + "da_DK:da:Danish (Denmark)" + "de_DE:de:German (Germany)" + "el_GR:el:Greek (Greece)" + "es_MX:es:Spanish (Mexico)" + "et_EE:et:Estonian (Estonia)" + "eu_ES:eu:Basque (Spain)" + "fa_IR:fa:Persian (Iran)" + "ff_SN:ff:Fulah (Senegal)" + "fi_FI:fi:Finnish (Finland)" + "fo_FO:fo:Faroese (Faroe Islands)" + "fr_CA:fr:French (Canada)" + "ga_IE:ga:Irish (Ireland)" + "gl_ES:gl:Galician (Spain)" + "gu_IN:gu:Gujarati (India)" + "gv_GB:gv:Manx (United Kingdom)" + "ha_NG:ha:Hausa (Nigeria)" + "he_IL:he:Hebrew (Israel)" + "hi_IN:hi:Hindi (India)" + "hr_HR:hr:Croatian (Croatia)" + "hu_HU:hu:Hungarian (Hungary)" + "hy_AM:hy:Armenian (Armenia)" + "id_ID:id:Indonesian (Indonesia)" + "ig_NG:ig:Igbo (Nigeria)" + "is_IS:is:Icelandic (Iceland)" + "it_IT:it:Italian (Italy)" + "ja_JP:ja:Japanese (Japan)" + "ka_GE:ka:Georgian (Georgia)" + "kk_KZ:kk:Kazakh (Kazakhstan)" + "kl_GL:kl:Kalaallisut (Greenland)" + "km_KH:km:Khmer (Cambodia)" + "kn_IN:kn:Kannada (India)" + "ko_KR:ko:Korean (South Korea)" + "ko_KR:ko:Korean (South Korea)" + "lg_UG:lg:Ganda (Uganda)" + "lt_LT:lt:Lithuanian (Lithuania)" + "lv_LV:lv:Latvian (Latvia)" + "mg_MG:mg:Malagasy (Madagascar)" + "mk_MK:mk:Macedonian (Macedonia)" + "ml_IN:ml:Malayalam (India)" + "mr_IN:mr:Marathi (India)" + "ms_MY:ms:Malay (Malaysia)" + "mt_MT:mt:Maltese (Malta)" + "my_MM:my:Burmese (Myanmar [Burma])" + "nb_NO:nb:Norwegian Bokmål (Norway)" + "ne_NP:ne:Nepali (Nepal)" + "nl_NL:nl:Dutch (Netherlands)" + "nn_NO:nn:Norwegian Nynorsk (Norway)" + "om_ET:om:Oromo (Ethiopia)" + "or_IN:or:Oriya (India)" + "pa_PK:pa:Punjabi (Pakistan)" + "pl_PL:pl:Polish (Poland)" + "ps_AF:ps:Pashto (Afghanistan)" + "pt_BR:pt:Portuguese (Brazil)" + "ro_RO:ro:Romanian (Romania)" + "ru_RU:ru:Russian (Russia)" + "rw_RW:rw:Kinyarwanda (Rwanda)" + "si_LK:si:Sinhala (Sri Lanka)" + "sk_SK:sk:Slovak (Slovakia)" + "sl_SI:sl:Slovenian (Slovenia)" + "so_SO:so:Somali (Somalia)" + "sq_AL:sq:Albanian (Albania)" + "sr_RS:sr:Serbian (Serbia)" + "sv_SE:sv:Swedish (Sweden)" + "sw_KE:sw:Swahili (Kenya)" + "ta_IN:ta:Tamil (India)" + "te_IN:te:Telugu (India)" + "th_TH:th:Thai (Thailand)" + "ti_ER:ti:Tigrinya (Eritrea)" + "to_TO:to:Tonga (Tonga)" + "tr_TR:tr:Turkish (Turkey)" + "uk_UA:uk:Ukrainian (Ukraine)" + "ur_IN:ur:Urdu (India)" + "uz_UZ:uz:Uzbek (Uzbekistan)" + "vi_VN:vi:Vietnamese (Vietnam)" + "yo_NG:yo:Yoruba (Nigeria)" + "yo_NG:yo:Yoruba (Nigeria)" + "yue_HK:yu:Cantonese (Hong Kong)" + "zh_CN:zh:Chinese (China)" + "zu_ZA:zu:Zulu (South Africa)" +) + +for i in "${langArr[@]}"; do + IFS=: read -r l1 l2 l3 <<< "$i" + if [ "$langInput" == "$l2" ]; then + lang="${l1}:${l2}" + languagePack="language-pack-${l2}" + fi +done + +if [ -z "$lang" ]; then + echo "plasmoidlocaletest doesn't recognize the language '$lang'" + echo "Eg:" + scriptcmd='sh ./plasmoidlocaletest' + for i in "${langArr[@]}"; do + IFS=: read -r l1 l2 l3 <<< "$i" + echo " ${scriptcmd} ${l2} | ${l3}" + done + echo "" + echo "Or use a the full locale code:" + echo " ${scriptcmd} ar_EG:ar" + exit 1 +fi + +IFS=: read -r l1 l2 <<< "${lang}" +l1="${l1}.UTF-8" + +# Check if language is installed +if [ ! -z "$languagePack" ]; then + if [ "$lang" == "zh_CN:zh" ]; then languagePack="language-pack-zh-hans" + fi + + checkIfLangInstalled "$languagePack" || exit 1 +fi + + +echo "LANGUAGE=\"${lang}\"" +echo "LANG=\"${l1}\"" + +scriptDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +packageDir="${scriptDir}/.." + +# Build local translations for plasmoidviewer +sh "${scriptDir}/build" + +LANGUAGE="${lang}" LANG="${l1}" LC_TIME="${l1}" QML_DISABLE_DISK_CACHE=true plasmoidviewer -a "$packageDir" -l topedge -f horizontal -x 0 -y 0 diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/pt_BR.po b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/pt_BR.po new file mode 100644 index 00000000..00273e47 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/pt_BR.po @@ -0,0 +1,116 @@ +# Translation of win7showdesktop in brazilian portuguese +# Copyright (C) 2019 +# This file is distributed under the same license as the win7showdesktop package. +# Andrew Miranda , 2020. +msgid "" +msgstr "" +"Project-Id-Version: win7showdesktop \n" +"Report-Msgid-Bugs-To: https://github.com/Zren/plasma-applet-win7showdesktop\n" +"POT-Creation-Date: 2023-08-16 12:36-0400\n" +"PO-Revision-Date: 2020-15-01 10:25-0300\n" +"Last-Translator: Andrew Miranda \n" +"Language-Team: Portuguese Brazilian \n" +"Language: Portuguese Brazilian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Show Desktop (Win7)" +msgstr "Exibir a área de trabalho (Win7)" + +#: ../metadata.desktop +msgid "Show the Plasma desktop" +msgstr "Mostra a área de trabalho do Plasma" + +#: ../contents/config/config.qml +msgid "General" +msgstr "Geral" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Look" +msgstr "Aparência" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Size:" +msgstr "Tamanho:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "px" +msgstr "px" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Edge Color:" +msgstr "Cor da borda:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Hovered Color:" +msgstr "Cor de foco:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Pressed Color:" +msgstr "Cor de clique:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Click" +msgstr "Clique" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Command" +msgstr "Executar comando:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Mouse Wheel" +msgstr "Roda do mouse" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Commands" +msgstr "Executar comandos" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Up:" +msgstr "Rolar para cima:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Down:" +msgstr "Rolar para baixo:" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (No UI) (amixer)" +msgstr "Volume (Sem UI) (amixer)" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (UI) (qdbus)" +msgstr "Volume (Com UI) (qdbus)" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Switch Desktop (qdbus)" +msgstr "Alternar área de trabalho (qdbus)" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Show desktop on hover:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Enable" +msgstr "Ativar" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek threshold:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "ms" +msgstr "" + +#: ../contents/ui/lib/AppletVersion.qml +msgid "Version: %1" +msgstr "Versão: %1" + +#: ../contents/ui/main.qml +msgid "Toggle Lock Widgets" +msgstr "" diff --git a/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/template.pot b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/template.pot new file mode 100644 index 00000000..63c87d01 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.plasma.win7showdesktop/translate/template.pot @@ -0,0 +1,118 @@ +# Translation of win7showdesktop in LANGUAGE +# Copyright (C) 2023 +# This file is distributed under the same license as the win7showdesktop package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: win7showdesktop\n" +"Report-Msgid-Bugs-To: https://github.com/Zren/plasma-applet-win7showdesktop\n" +"POT-Creation-Date: 2023-08-16 12:36-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../metadata.desktop +msgid "Show Desktop (Win7)" +msgstr "" + +#: ../metadata.desktop +msgid "Show the Plasma desktop" +msgstr "" + +#: ../contents/config/config.qml +msgid "General" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Look" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Size:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "px" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Edge Color:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Hovered Color:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Pressed Color:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Click" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Command" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Mouse Wheel" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Run Commands" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Up:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Scroll Down:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (No UI) (amixer)" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Volume (UI) (qdbus)" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Switch Desktop (qdbus)" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Show desktop on hover:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Enable" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "Peek threshold:" +msgstr "" + +#: ../contents/ui/config/ConfigGeneral.qml +msgid "ms" +msgstr "" + +#: ../contents/ui/lib/AppletVersion.qml +msgid "Version: %1" +msgstr "" + +#: ../contents/ui/main.qml +msgid "Toggle Lock Widgets" +msgstr "" diff --git a/kde/plasma/plasmoids/org.kde.tail/contents/config/config.qml b/kde/plasma/plasmoids/org.kde.tail/contents/config/config.qml new file mode 100644 index 00000000..f52098e3 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.tail/contents/config/config.qml @@ -0,0 +1,17 @@ +import QtQuick 2.0 +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n("Settings") + icon: "preferences-desktop-settings" + source: "config/configSettings.qml" + } + + ConfigCategory { + name: i18n("About") + icon: "preferences-desktop-notification" + source: "config/configAbout.qml" + } + +} diff --git a/kde/plasma/plasmoids/org.kde.tail/contents/config/main.xml b/kde/plasma/plasmoids/org.kde.tail/contents/config/main.xml new file mode 100644 index 00000000..9f40777e --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.tail/contents/config/main.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/kde/plasma/plasmoids/org.kde.tail/contents/ui/config/configAbout.qml b/kde/plasma/plasmoids/org.kde.tail/contents/ui/config/configAbout.qml new file mode 100644 index 00000000..bd8ce3fe --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.tail/contents/ui/config/configAbout.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.2 as QtControls +import QtQuick.Layouts 1.0 as QtLayouts +import org.kde.plasma.plasmoid 2.0 + +Item { + id: settingsPage + + + QtLayouts.ColumnLayout { + + Column { + QtLayouts.RowLayout { + QtControls.Label { + text: i18n("Version: 1.0.0") + } + } + } + } +} diff --git a/kde/plasma/plasmoids/org.kde.tail/contents/ui/config/configSettings.qml b/kde/plasma/plasmoids/org.kde.tail/contents/ui/config/configSettings.qml new file mode 100644 index 00000000..b809e538 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.tail/contents/ui/config/configSettings.qml @@ -0,0 +1,36 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.2 as QtControls +import QtQuick.Layouts 1.0 as QtLayouts +import QtQuick.Dialogs 1.0 +Item { + id: settingsPage + + property alias cfg_filename: filename.text + + QtLayouts.RowLayout { + QtControls.TextField { + id: filename + } + + QtControls.Button { + QtLayouts.Layout.alignment: Qt.AlignRight; + QtLayouts.Layout.rightMargin: 15 + text: i18n("Choose file") + onClicked: fileDialog.open(); + } + } + FileDialog { + id: fileDialog + title: "Please choose a file" + folder: shortcuts.home + onAccepted: { + filename.text = fileDialog.fileUrl.toString().substring(7) + fileDialog.close() + } + onRejected: { + fileDialog.close() + } + } +} + + diff --git a/kde/plasma/plasmoids/org.kde.tail/contents/ui/main.qml b/kde/plasma/plasmoids/org.kde.tail/contents/ui/main.qml new file mode 100644 index 00000000..1c502263 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.tail/contents/ui/main.qml @@ -0,0 +1,71 @@ +import QtQuick 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import QtQuick.Controls 2.0 as QtControls +Item { + + + + PlasmaCore.DataSource { + id: executable + property int lastline: 1 + engine: "executable" + connectedSources: [] + onNewData: { + var lines = data["stdout"].split(/\r?\n/); + var i; + var linenumber; + for (i = 0; i <= lines.length - 1; i++) { + linenumber = parseInt(lines[i].substring(0,7).trim()); + if(linenumber > executable.lastline) { + executable.lastline = linenumber; + output.text = output.text + lines[i].substring(7) + '\n'; + scrollbar.increase(); + } + } + disconnectSource("cat -n " + plasmoid.configuration.filename + " | tail") + } + } + + + Flickable { + id: flickable + anchors.fill: parent + + QtControls.TextArea.flickable: QtControls.TextArea { + id: output + text: "" + wrapMode: QtControls.TextArea.Wrap + } + + QtControls.ScrollBar.vertical: QtControls.ScrollBar { + id: scrollbar + stepSize: 2 + } +} + + + + Timer { + id: timer + interval: 10000 + running: true + repeat: true + onTriggered: { + if(plasmoid.configuration.filename.length && !executable.connectedSources.length) { + executable.connectSource("cat -n " + plasmoid.configuration.filename + " | tail") + } + } + + Component.onCompleted: { + triggered() + } + } + + Component.onCompleted: { + output.text = '' + if(plasmoid.configuration.filename.length) { + executable.connectSource("cat -n " + plasmoid.configuration.filename + " | tail") + } + } + +} diff --git a/kde/plasma/plasmoids/org.kde.tail/metadata.desktop b/kde/plasma/plasmoids/org.kde.tail/metadata.desktop new file mode 100644 index 00000000..eb5c3110 --- /dev/null +++ b/kde/plasma/plasmoids/org.kde.tail/metadata.desktop @@ -0,0 +1,19 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Tail +Comment=Read all changes in files in a plasmoid. +Type=Service + +Icon=media-floppy +X-KDE-ServiceTypes=Plasma/Applet +X-KDE-PluginInfo-Author=Hill +X-KDE-PluginInfo-Email=zanturik@gmail.com +X-KDE-PluginInfo-License=LGPLv2 +X-KDE-PluginInfo-Name=org.kde.tail +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=tail.maka.tk +X-KDE-PluginInfo-Category=Utilities + +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml +X-Plasma-StandAloneApp=true diff --git a/lone-files/kglobalshortcutsrc b/lone-files/kglobalshortcutsrc new file mode 100644 index 00000000..bfe094a0 --- /dev/null +++ b/lone-files/kglobalshortcutsrc @@ -0,0 +1,332 @@ +[ActivityManager] +_k_friendly_name=Aktivitätenverwaltung +switch-to-activity-d7d15086-7d92-470b-924f-df8f497fbac9=none,none,Zu Aktivität „Standard“ wechseln + +[KDE Keyboard Layout Switcher] +Switch keyboard layout to Deutsch=none,none,Tastaturbelegung zu Deutsch umschalten +Switch to Next Keyboard Layout=none,Meta+Alt+K,Auf nächste Tastaturbelegung umschalten +_k_friendly_name=Umschaltung der Tastaturbelegung + +[kaccess] +Toggle Screen Reader On and Off=none,Meta+Alt+S,Screenreader ein-/ausschalten +_k_friendly_name=Zugangshilfen + +[kcm_touchpad] +Disable Touchpad=Touchpad Off,Touchpad Off,Touchpad abschalten +Enable Touchpad=Touchpad On,Touchpad On,Touchpad aktivieren +Toggle Touchpad=Touchpad Toggle\tMeta+Ctrl+Zenkaku Hankaku,Touchpad Toggle,Touchpad umschalten +_k_friendly_name=Touchpad + +[kded5] +Show System Activity=none,Ctrl+Esc,Systemaktivität anzeigen +_k_friendly_name=KDE Daemon +display=none,Display\tMeta+P,Anzeige wechseln + +[khotkeys] +_k_friendly_name=Dienst für eigene Kurzbefehle +{d03619b6-9b3c-48cc-9d9c-a2aadb485550}=none,none,Suchen + +[kmix] +_k_friendly_name=Lautstärke +decrease_microphone_volume=Microphone Volume Down\tMeta+Volume Down,Microphone Volume Down,Mikrofonlautstärke verringern +decrease_volume=Volume Down,Volume Down,Lautstärke verringern +increase_microphone_volume=Microphone Volume Up\tMeta+Volume Up,Microphone Volume Up,Mikrofonlautstärke erhöhen +increase_volume=Volume Up,Volume Up,Lautstärke erhöhen +mic_mute=Meta+Volume Mute\tMicrophone Mute,Microphone Mute\tMeta+Volume Mute,Mikrofon stummschalten +mute=Volume Mute,Volume Mute,Stummschalten + +[ksmserver] +Halt Without Confirmation=none,,Ohne Rückfrage herunterfahren +Lock Session=Meta+L,Meta+L\tScreensaver,Sitzung sperren +Log Out=Meta+Ö,Ctrl+Alt+Del,Abmelden +Log Out Without Confirmation=none,,Ohne Rückfrage abmelden +Reboot Without Confirmation=none,,Ohne Rückfrage neu starten +_k_friendly_name=Sitzungsverwaltung + +[kwin] +Activate Window Demanding Attention=none,Meta+Ctrl+A,Fenster aktivieren\\, das Aufmerksamkeit erfordert +Alt-F4-Desktop=none,none,Close Window or show Logout Option +Decrease Opacity=none,,Die Deckkraft des aktiven Fensters um 5 % verringern +Edit Tiles=none,Meta+T,Tiling-Editor ein-/ausschalten +Expose=none,Ctrl+F9,Fenster der aktuellen Arbeitsfläche anzeigen +ExposeAll=none,Ctrl+F10\tLaunch (C),Fenster aller Arbeitsflächen anzeigen +ExposeClass=none,Ctrl+F7,Fenster der Fensterklasse anzeigen +ExposeClassCurrentDesktop=none,none,Fenster der Fensterklasse auf der aktuellen Arbeitsfläche anzeigen +Increase Opacity=none,,Die Deckkraft des aktiven Fensters um 5 % erhöhen +Kill Window=Meta+Esc,Meta+Ctrl+Esc,Fenster beseitigen +Move Tablet to Next Output=none,none,Move the tablet to the next output +MoveMouseToCenter=none,Meta+F6,Mauszeiger zentrieren +MoveMouseToFocus=none,Meta+F5,Mauszeiger in den Fokus verschieben +MoveZoomDown=none,none,Vergrößerten Bereich nach unten verschieben +MoveZoomLeft=none,none,Vergrößerten Bereich nach links verschieben +MoveZoomRight=none,none,Vergrößerten Bereich nach rechts verschieben +MoveZoomUp=none,none,Vergrößerten Bereich nach oben verschieben +Overview=none,Meta+W,Übersicht umschalten +Setup Window Shortcut=none,,Kurzbefehl für Fenster einrichten +Show Desktop=none,Meta+D,Blick auf die Arbeitsfläche +ShowDesktopGrid=none,Meta+F8,Arbeitsflächen-Raster anzeigen +Suspend Compositing=none,Alt+Shift+F12,Compositing aussetzen +Switch One Desktop Down=none,Meta+Ctrl+Down,Eine Arbeitsfläche nach unten +Switch One Desktop Up=none,Meta+Ctrl+Up,Eine Arbeitsfläche nach oben +Switch One Desktop to the Left=none,Meta+Ctrl+Left,Eine Arbeitsfläche nach links +Switch One Desktop to the Right=none,Meta+Ctrl+Right,Eine Arbeitsfläche nach rechts +Switch Window Down=none,Meta+Alt+Down,Zum Fenster darunter wechseln +Switch Window Left=none,Meta+Alt+Left,Zum Fenster links wechseln +Switch Window Right=none,Meta+Alt+Right,Zum Fenster rechts wechseln +Switch Window Up=none,Meta+Alt+Up,Zum Fenster darüber wechseln +Switch to Desktop 1=none,Ctrl+F1,Auf Arbeitsfläche 1 umschalten +Switch to Desktop 10=none,,Auf Arbeitsfläche 10 umschalten +Switch to Desktop 11=none,,Auf Arbeitsfläche 11 umschalten +Switch to Desktop 12=none,,Auf Arbeitsfläche 12 umschalten +Switch to Desktop 13=none,,Auf Arbeitsfläche 13 umschalten +Switch to Desktop 14=none,,Auf Arbeitsfläche 14 umschalten +Switch to Desktop 15=none,,Auf Arbeitsfläche 15 umschalten +Switch to Desktop 16=none,,Auf Arbeitsfläche 16 umschalten +Switch to Desktop 17=none,,Auf Arbeitsfläche 17 umschalten +Switch to Desktop 18=none,,Auf Arbeitsfläche 18 umschalten +Switch to Desktop 19=none,,Auf Arbeitsfläche 19 umschalten +Switch to Desktop 2=none,Ctrl+F2,Auf Arbeitsfläche 2 umschalten +Switch to Desktop 20=none,,Auf Arbeitsfläche 20 umschalten +Switch to Desktop 3=none,Ctrl+F3,Auf Arbeitsfläche 3 umschalten +Switch to Desktop 4=none,Ctrl+F4,Auf Arbeitsfläche 4 umschalten +Switch to Desktop 5=none,,Auf Arbeitsfläche 5 umschalten +Switch to Desktop 6=none,,Auf Arbeitsfläche 6 umschalten +Switch to Desktop 7=none,,Auf Arbeitsfläche 7 umschalten +Switch to Desktop 8=none,,Auf Arbeitsfläche 8 umschalten +Switch to Desktop 9=none,,Auf Arbeitsfläche 9 umschalten +Switch to Next Desktop=none,,Zur nächsten Arbeitsfläche umschalten +Switch to Next Screen=none,,Zum nächsten Bildschirm wechseln +Switch to Previous Desktop=none,,Zur vorherigen Arbeitsfläche umschalten +Switch to Previous Screen=none,,Zum vorherigen Bildschirm wechseln +Switch to Screen 0=none,,Zum Bildschirm 0 wechseln +Switch to Screen 1=none,,Zum Bildschirm 1 wechseln +Switch to Screen 2=none,,Zum Bildschirm 2 wechseln +Switch to Screen 3=none,,Zum Bildschirm 3 wechseln +Switch to Screen 4=none,,Zum Bildschirm 4 wechseln +Switch to Screen 5=none,,Zum Bildschirm 5 wechseln +Switch to Screen 6=none,,Zum Bildschirm 6 wechseln +Switch to Screen 7=none,,Zum Bildschirm 7 wechseln +Switch to Screen Above=none,,Zum Bildschirm oben wechseln +Switch to Screen Below=none,,Zum Bildschirm unten wechseln +Switch to Screen to the Left=none,,Zum Bildschirm links wechseln +Switch to Screen to the Right=none,,Zum Bildschirm rechts wechseln +Toggle Night Color=none,none,Nachtfarben umschalten +Toggle Window Raise/Lower=none,,Fenster nach vorne/hinten +Walk Through Desktop List=none,,Nächster Eintrag in Arbeitsflächenliste +Walk Through Desktop List (Reverse)=none,,Nächster Eintrag in Arbeitsflächenliste (Gegenrichtung) +Walk Through Desktops=none,,Zwischen Arbeitsflächen umschalten +Walk Through Desktops (Reverse)=none,,Zwischen Arbeitsflächen umschalten (Gegenrichtung) +Walk Through Windows=none,Alt+Tab,Zwischen Fenstern wechseln +Walk Through Windows (Reverse)=none,Alt+Shift+Backtab,Zwischen Fenstern wechseln (Gegenrichtung) +Walk Through Windows Alternative=Alt+Tab,,Alternatives Wechseln zwischen Fenstern +Walk Through Windows Alternative (Reverse)=none,,Alternatives Wechseln zwischen Fenstern (Gegenrichtung) +Walk Through Windows of Current Application=none,Alt+`,Zwischen Fenstern der aktuellen Anwendung wechseln +Walk Through Windows of Current Application (Reverse)=none,Alt+~,Zwischen Fenstern der aktuellen Anwendung wechseln (Gegenrichtung) +Walk Through Windows of Current Application Alternative=none,,Alternatives Wechseln zwischen Fenstern der aktuellen Anwendung +Walk Through Windows of Current Application Alternative (Reverse)=none,,Alternatives Wechseln zwischen Fenstern der aktuellen Anwendung (Gegenrichtung) +Window Above Other Windows=none,,Fenster im Vordergrund halten +Window Below Other Windows=none,,Fenster im Hintergrund halten +Window Close=Alt+F4\tMeta+Q,Alt+F4,Fenster schließen +Window Fullscreen=Meta+F,,Fenster auf Vollbildgröße +Window Grow Horizontal=none,,Fenster waagerecht maximieren +Window Grow Vertical=none,,Fenster senkrecht maximieren +Window Lower=none,,Fenster nach hinten +Window Maximize=none,Meta+PgUp,Fenster maximieren +Window Maximize Horizontal=none,,Fenster waagerecht maximieren +Window Maximize Vertical=none,,Fenster senkrecht maximieren +Window Minimize=none,Meta+PgDown,Fenster minimieren +Window Move=none,,Fenster verschieben +Window Move Center=none,,Fenster zentrieren +Window No Border=none,,Titelleiste und Rahmen des Fensters ein-/ausschalten +Window On All Desktops=none,,Fenster auf allen Arbeitsflächen anzeigen +Window One Desktop Down=none,Meta+Ctrl+Shift+Down,Fenster eine Arbeitsfläche nach unten +Window One Desktop Up=none,Meta+Ctrl+Shift+Up,Fenster eine Arbeitsfläche nach oben +Window One Desktop to the Left=none,Meta+Ctrl+Shift+Left,Fenster eine Arbeitsfläche nach links +Window One Desktop to the Right=none,Meta+Ctrl+Shift+Right,Fenster eine Arbeitsfläche nach rechts +Window One Screen Down=none,,Fenster einen Bildschirm nach unten +Window One Screen Up=none,,Fenster einen Bildschirm nach oben +Window One Screen to the Left=none,,Fenster einen Bildschirm nach links +Window One Screen to the Right=none,,Fenster einen Bildschirm nach rechts +Window Operations Menu=Alt+F3,Alt+F3,Fensteraktionen-Menü +Window Pack Down=none,,Fenster nach unten verschieben +Window Pack Left=none,,Fenster nach links verschieben +Window Pack Right=none,,Fenster nach rechts verschieben +Window Pack Up=none,,Fenster nach oben verschieben +Window Quick Tile Bottom=none,Meta+Down,Fenster am unteren Bildschirmrand anordnen +Window Quick Tile Bottom Left=none,,Fenster am linken unteren Bildschirmrand anordnen +Window Quick Tile Bottom Right=none,,Fenster am rechten unteren Bildschirmrand anordnen +Window Quick Tile Left=none,Meta+Left,Fenster am linken Bildschirmrand anordnen +Window Quick Tile Right=none,Meta+Right,Fenster am rechten Bildschirmrand anordnen +Window Quick Tile Top=none,Meta+Up,Fenster am oberen Bildschirmrand anordnen +Window Quick Tile Top Left=none,,Fenster am linken oberen Bildschirmrand anordnen +Window Quick Tile Top Right=none,,Fenster am rechten oberen Bildschirmrand anordnen +Window Raise=none,,Fenster nach vorne +Window Resize=none,,Fenstergröße ändern +Window Shade=none,,Fensterheber betätigen +Window Shrink Horizontal=none,,Fenster waagerecht verkleinern +Window Shrink Vertical=none,,Fenster senkrecht verkleinern +Window to Desktop 1=none,,Fenster auf Arbeitsfläche 1 +Window to Desktop 10=none,,Fenster auf Arbeitsfläche 10 +Window to Desktop 11=none,,Fenster auf Arbeitsfläche 11 +Window to Desktop 12=none,,Fenster auf Arbeitsfläche 12 +Window to Desktop 13=none,,Fenster auf Arbeitsfläche 13 +Window to Desktop 14=none,,Fenster auf Arbeitsfläche 14 +Window to Desktop 15=none,,Fenster auf Arbeitsfläche 15 +Window to Desktop 16=none,,Fenster auf Arbeitsfläche 16 +Window to Desktop 17=none,,Fenster auf Arbeitsfläche 17 +Window to Desktop 18=none,,Fenster auf Arbeitsfläche 18 +Window to Desktop 19=none,,Fenster auf Arbeitsfläche 19 +Window to Desktop 2=none,,Fenster auf Arbeitsfläche 2 +Window to Desktop 20=none,,Fenster auf Arbeitsfläche 20 +Window to Desktop 3=none,,Fenster auf Arbeitsfläche 3 +Window to Desktop 4=none,,Fenster auf Arbeitsfläche 4 +Window to Desktop 5=none,,Fenster auf Arbeitsfläche 5 +Window to Desktop 6=none,,Fenster auf Arbeitsfläche 6 +Window to Desktop 7=none,,Fenster auf Arbeitsfläche 7 +Window to Desktop 8=none,,Fenster auf Arbeitsfläche 8 +Window to Desktop 9=none,,Fenster auf Arbeitsfläche 9 +Window to Next Desktop=none,,Fenster auf nächste Arbeitsfläche verschieben +Window to Next Screen=none,Meta+Shift+Right,Fenster auf nächsten Bildschirm verschieben +Window to Previous Desktop=none,,Fenster auf vorherige Arbeitsfläche verschieben +Window to Previous Screen=none,Meta+Shift+Left,Fenster auf vorherigen Bildschirm verschieben +Window to Screen 0=none,,Fenster auf Bildschirm 0 +Window to Screen 1=none,,Fenster auf Bildschirm 1 +Window to Screen 2=none,,Fenster auf Bildschirm 2 +Window to Screen 3=none,,Fenster auf Bildschirm 3 +Window to Screen 4=none,,Fenster auf Bildschirm 4 +Window to Screen 5=none,,Fenster auf Bildschirm 5 +Window to Screen 6=none,,Fenster auf Bildschirm 6 +Window to Screen 7=none,,Fenster auf Bildschirm 7 +_k_friendly_name=KWin +view_actual_size=none,Meta+0,Auf Originalgröße zoomen +view_zoom_in=none,Meta++\tMeta+=,Vergrößern +view_zoom_out=none,Meta+-,Verkleinern + +[librewolf.desktop] +_k_friendly_name=LibreWolf +_launch=Meta+D,none,LibreWolf +new-private-window=none,none,Neues privates Fenster +new-window=none,none,Neues Fenster +profile-manager-window=none,none,Profilverwaltung öffnen + +[loginctl.desktop] +_k_friendly_name=loginctl kill-user jeremystartm +_launch=Meta+Shift+Q,none,loginctl kill-user jeremystartm + +[mediacontrol] +_k_friendly_name=Mediensteuerung +mediavolumedown=none,,Medienspieler leiser +mediavolumeup=none,,Medienspieler lauter +nextmedia=Media Next,Media Next,Nächstes Medium wiedergeben +pausemedia=Media Pause,Media Pause,Medienwiedergabe anhalten +playmedia=none,,Medienwiedergabe starten +playpausemedia=Media Play,Media Play,Medienwiedergabe starten/anhalten +previousmedia=Media Previous,Media Previous,Vorheriges Medium wiedergeben +stopmedia=Media Stop,Media Stop,Medienwiedergabe anhalten + +[org.kde.dolphin.desktop] +_k_friendly_name=Dolphin +_launch=Meta+S,Meta+E,Dolphin + +[org.kde.kcalc.desktop] +_k_friendly_name=KCalc +_launch=none,Launch (1),KCalc + +[org.kde.konsole.desktop] +NewTab=none,none,Ein neues Unterfenster öffnen +NewWindow=none,none,Ein neues Fenster öffnen +_k_friendly_name=Konsole +_launch=Meta+A,Ctrl+Alt+T,Konsole + +[org.kde.krunner.desktop] +RunClipboard=none,Alt+Shift+F2,Befehl mit dem Inhalt der Zwischenablage ausführen +_k_friendly_name=KRunner +_launch=Alt+Space,Alt+Space\tAlt+F2\tSearch,KRunner + +[org.kde.plasma.emojier.desktop] +_k_friendly_name=Emoji-Auswahl +_launch=Meta+.,Meta+.\tMeta+Ctrl+Alt+Shift+Space,Emoji-Auswahl + +[org.kde.spectacle.desktop] +ActiveWindowScreenShot=Meta+Print,Meta+Print,Aktives Fenster aufnehmen +CurrentMonitorScreenShot=none,none,Aktuellen Bildschirm aufnehmen +FullScreenScreenShot=Shift+Print,Shift+Print,Gesamte Arbeitsfläche aufnehmen +OpenWithoutScreenshot=none,none,Spectacle ohne Aufnahme starten +RectangularRegionScreenShot=Meta+Shift+Print,Meta+Shift+Print,Rechteckigen Bereich aufnehmen +WindowUnderCursorScreenShot=Meta+Ctrl+Print,Meta+Ctrl+Print,Fenster unter dem Mauszeiger aufnehmen +_k_friendly_name=Spectacle +_launch=Print,Print,Spectacle starten + +[org_kde_powerdevil] +Decrease Keyboard Brightness=Keyboard Brightness Down,Keyboard Brightness Down,Helligkeit der Tastatur-Hintergrundbeleuchtung verringern +Decrease Screen Brightness=Monitor Brightness Down,Monitor Brightness Down,Bildschirmhelligkeit verringern +Hibernate=none,Hibernate,Ruhezustand +Increase Keyboard Brightness=Keyboard Brightness Up,Keyboard Brightness Up,Helligkeit der Tastatur-Hintergrundbeleuchtung erhöhen +Increase Screen Brightness=Monitor Brightness Up,Monitor Brightness Up,Bildschirmhelligkeit erhöhen +PowerDown=Power Down,Power Down,Abschalten +PowerOff=Power Off,Power Off,Ausschalten +Sleep=none,Sleep,Standby-Modus +Toggle Keyboard Backlight=Keyboard Light On/Off,Keyboard Light On/Off,Hintergrundbeleuchtung der Tastatur umschalten +Turn Off Screen=none,none,Bildschirm ausschalten +_k_friendly_name=Energieverwaltung + +[plasmashell] +_k_friendly_name=Plasma +activate task manager entry 1=none,Meta+1,Fensterleisteneintrag 1 aktivieren +activate task manager entry 10=none,Meta+0,Fensterleisteneintrag 10 aktivieren +activate task manager entry 2=none,Meta+2,Fensterleisteneintrag 2 aktivieren +activate task manager entry 3=none,Meta+3,Fensterleisteneintrag 3 aktivieren +activate task manager entry 4=none,Meta+4,Fensterleisteneintrag 4 aktivieren +activate task manager entry 5=none,Meta+5,Fensterleisteneintrag 5 aktivieren +activate task manager entry 6=none,Meta+6,Fensterleisteneintrag 6 aktivieren +activate task manager entry 7=none,Meta+7,Fensterleisteneintrag 7 aktivieren +activate task manager entry 8=none,Meta+8,Fensterleisteneintrag 8 aktivieren +activate task manager entry 9=none,Meta+9,Fensterleisteneintrag 9 aktivieren +activate widget 27=none,none,Miniprogramm Anwendungsstarter aktivieren +activate widget 4=none,none,Miniprogramm Anwendungsstarter aktivieren +activate widget 61=none,none,Miniprogramm Fensterleiste nur mit Symbolen aktivieren +clear-history=none,,Bisherigen Inhalt der Zwischenablage löschen +clipboard_action=none,Meta+Ctrl+X,Automatisches Aufklappmenü für Aktionen +cycle-panels=none,Meta+Alt+P,Tastaturfokus zwischen Kontrollleisten umschalten +cycleNextAction=none,,Nächstes Element im Verlauf +cyclePrevAction=none,,Vorheriges Element im Verlauf +edit_clipboard=none,,Inhalt bearbeiten ... +manage activities=none,Meta+Q,Aktivitätenwechsler anzeigen +next activity=none,Meta+Tab,Zwischen Aktivitäten wechseln +previous activity=none,Meta+Shift+Tab,Zwischen Aktivitäten wechseln (Gegenrichtung) +repeat_action=none,Meta+Ctrl+R,Aktionen der aktuellen Zwischenablage manuell aufrufen +show dashboard=none,Ctrl+F12,Arbeitsfläche anzeigen +show-barcode=none,,Strichcode anzeigen ... +show-on-mouse-pos=none,Meta+V,Elemente an Mausposition anzeigen +stop current activity=none,Meta+S,Aktuelle Aktivität anhalten +switch to next activity=none,,Zur nächsten Aktivität wechseln +switch to previous activity=none,,Zur vorherigen Aktivität wechseln +toggle do not disturb=none,,Nicht stören umschalten + +[poweroff.desktop] +_k_friendly_name=poweroff +_launch=Meta+Shift+W,none,poweroff + +[reboot.desktop] +_k_friendly_name=reboot +_launch=Meta+Shift+E,none,reboot + +[systemsettings.desktop] +_k_friendly_name=Systemeinstellungen +_launch=none,Tools,Systemeinstellungen +kcm-kscreen=none,none,Anzeige-Einrichtung +kcm-lookandfeel=none,none,Globales Design +kcm-users=none,none,Benutzer +powerdevilprofilesconfig=none,none,Energiesparen +screenlocker=none,none,Bildschirmsperre + +[wacomtablet] +Map to fullscreen=none,Meta+Ctrl+F,Bildschirmfüllend abbilden +Map to screen 1=none,Meta+Ctrl+1,Auf Bildschirm 1 abbilden +Map to screen 2=none,Meta+Ctrl+2,Auf Bildschirm 2 abbilden +Next Profile=none,Meta+Ctrl+N,Nächstes Profil +Previous Profile=none,Meta+Ctrl+P,Voriges Profil +Toggle screen map selection=none,Meta+Ctrl+M,Zwischen allen Bildschirmen umschalten +Toggle stylus mode=none,Meta+Ctrl+S,Funktionsweise des Stift-Werkzeugs zwischen relativ/absolut umschalten +Toggle touch tool=none,Meta+Ctrl+T,Touch-Werkzeug aktivieren/deaktivieren +_k_friendly_name=Wacom-Tablett diff --git a/lone-files/kiorc b/lone-files/kiorc new file mode 100644 index 00000000..562c9ad9 --- /dev/null +++ b/lone-files/kiorc @@ -0,0 +1,7 @@ +[Confirmations] +ConfirmDelete=true +ConfirmEmptyTrash=true +ConfirmTrash=false + +[Executable scripts] +behaviourOnLaunch=execute diff --git a/lone-files/krunnerrc b/lone-files/krunnerrc new file mode 100644 index 00000000..20857db3 --- /dev/null +++ b/lone-files/krunnerrc @@ -0,0 +1,25 @@ +[General] +FreeFloating=true +HistoryEnabled=false +RetainPriorSearch=false + +[PlasmaRunnerManager] +migrated=true + +[Plugins] +DictionaryEnabled=false +appstreamEnabled=false +browserhistoryEnabled=false +browsertabsEnabled=false +desktopsessionsEnabled=false +helprunnerEnabled=false +katesessionsEnabled=false +konsoleprofilesEnabled=false +krunner_killEnabled=false +krunner_spellcheckEnabled=false +org.kde.activities2Enabled=false +org.kde.datetimeEnabled=false +org.kde.windowedwidgetsEnabled=false +recentdocumentsEnabled=false +webshortcutsEnabled=false +windowsEnabled=false diff --git a/lone-files/kservicemenurc b/lone-files/kservicemenurc new file mode 100644 index 00000000..40eaf35f --- /dev/null +++ b/lone-files/kservicemenurc @@ -0,0 +1,8 @@ +[Show] +compressfileitemaction=true +extractfileitemaction=true +forgetfileitemaction=true +kactivitymanagerd_fileitem_linking_plugin=true +runInKonsole=true +sharefileitemaction=true +tagsfileitemaction=true diff --git a/lone-files/ksplashrc b/lone-files/ksplashrc new file mode 100644 index 00000000..c252676b --- /dev/null +++ b/lone-files/ksplashrc @@ -0,0 +1,3 @@ +[KSplash] +Engine=none +Theme=None diff --git a/lone-files/ktimezonedrc b/lone-files/ktimezonedrc new file mode 100644 index 00000000..8a5b73eb --- /dev/null +++ b/lone-files/ktimezonedrc @@ -0,0 +1,4 @@ +[TimeZones] +LocalZone=Europe/Berlin +ZoneinfoDir=/usr/share/zoneinfo +Zonetab=/usr/share/zoneinfo/zone.tab diff --git a/lone-files/plasma-localerc b/lone-files/plasma-localerc new file mode 100644 index 00000000..98e6fb1c --- /dev/null +++ b/lone-files/plasma-localerc @@ -0,0 +1,2 @@ +[Formats] +LANG=de_DE.UTF-8 diff --git a/lone-files/plasma-org.kde.plasma.desktop-appletsrc b/lone-files/plasma-org.kde.plasma.desktop-appletsrc new file mode 100644 index 00000000..5b565d7d --- /dev/null +++ b/lone-files/plasma-org.kde.plasma.desktop-appletsrc @@ -0,0 +1,495 @@ +[ActionPlugins][0] +RightButton;NoModifier=org.kde.contextmenu +wheel:Vertical;NoModifier=org.kde.switchdesktop + +[ActionPlugins][1] +RightButton;NoModifier=org.kde.contextmenu + +[Containments][1] +ItemGeometries-1280x720= +ItemGeometries-1366x768= +ItemGeometries-1680x1050= +ItemGeometries-1920x1080= +ItemGeometries-2560x1440=Applet-71:0,1280,512,112,0; +ItemGeometriesHorizontal=Applet-71:0,1280,512,112,0; +activityId=d7d15086-7d92-470b-924f-df8f497fbac9 +formfactor=0 +immutability=1 +lastScreen=0 +location=0 +plugin=org.kde.plasma.folder +wallpaperplugin=org.kde.image + +[Containments][1][Applets][71] +immutability=1 +plugin=org.kde.Circle.Minimal.Music + +[Containments][1][Applets][71][Configuration][ConfigDialog] +DialogHeight=570 +DialogWidth=760 + +[Containments][1][Applets][71][Configuration][General] +fontFamily=FiraMono Nerd Font + +[Containments][1][ConfigDialog] +DialogHeight=903 +DialogWidth=1698 + +[Containments][1][Configuration] +PreloadWeight=26 + +[Containments][1][General] +ToolBoxButtonState=topcenter +ToolBoxButtonX=678 + +[Containments][1][Wallpaper][org.kde.image][General] +Image=/home/jeremystartm/.local/share/wallpapers/Utterly-Sweet/ +SlidePaths=/home/jay/.local/share/wallpapers/,/usr/share/wallpapers/ + +[Containments][2] +ItemGeometries-1680x1050= +ItemGeometries-1920x1080= +ItemGeometriesHorizontal= +activityId=d7d15086-7d92-470b-924f-df8f497fbac9 +formfactor=0 +immutability=1 +lastScreen=1 +location=0 +plugin=org.kde.plasma.folder +wallpaperplugin=org.kde.image + +[Containments][2][ConfigDialog] +DialogHeight=570 +DialogWidth=760 + +[Containments][2][Configuration] +PreloadWeight=26 + +[Containments][2][General] +ToolBoxButtonState=topcenter +ToolBoxButtonX=358 +ToolBoxButtonY=42 + +[Containments][2][Wallpaper][org.kde.image][General] +Image=/home/jeremystartm/.local/share/wallpapers/Utterly-Sweet/ +SlidePaths=/home/jeremystartm/.local/share/wallpapers/,/usr/share/wallpapers/ + +[Containments][32] +activityId= +formfactor=2 +immutability=1 +lastScreen=0 +location=3 +plugin=org.kde.plasma.private.systemtray +wallpaperplugin=org.kde.image + +[Containments][32][Applets][33] +immutability=1 +plugin=org.kde.plasma.clipboard + +[Containments][32][Applets][33][Configuration] +PreloadWeight=18 + +[Containments][32][Applets][34] +immutability=1 +plugin=org.kde.plasma.devicenotifier + +[Containments][32][Applets][34][Configuration] +PreloadWeight=18 + +[Containments][32][Applets][35] +immutability=1 +plugin=org.kde.plasma.manage-inputmethod + +[Containments][32][Applets][35][Configuration] +PreloadWeight=18 + +[Containments][32][Applets][36] +immutability=1 +plugin=org.kde.plasma.notifications + +[Containments][32][Applets][36][Configuration] +PreloadWeight=18 + +[Containments][32][Applets][37] +immutability=1 +plugin=org.kde.plasma.keyboardlayout + +[Containments][32][Applets][37][Configuration] +PreloadWeight=18 + +[Containments][32][Applets][38] +immutability=1 +plugin=org.kde.plasma.volume + +[Containments][32][Applets][38][Configuration] +PreloadWeight=18 + +[Containments][32][Applets][38][Configuration][General] +migrated=true + +[Containments][32][Applets][39] +immutability=1 +plugin=org.kde.plasma.keyboardindicator + +[Containments][32][Applets][39][Configuration] +PreloadWeight=18 + +[Containments][32][Applets][40] +immutability=1 +plugin=org.kde.kscreen + +[Containments][32][Applets][40][Configuration] +PreloadWeight=26 + +[Containments][32][Applets][41] +immutability=1 +plugin=org.kde.plasma.vault + +[Containments][32][Applets][41][Configuration] +PreloadWeight=26 + +[Containments][32][Applets][42] +immutability=1 +plugin=org.kde.plasma.nightcolorcontrol + +[Containments][32][Applets][42][Configuration] +PreloadWeight=0 + +[Containments][32][Applets][43] +immutability=1 +plugin=org.kde.plasma.battery + +[Containments][32][Applets][43][Configuration] +PreloadWeight=18 + +[Containments][32][Applets][44] +immutability=1 +plugin=org.kde.plasma.networkmanagement + +[Containments][32][Applets][44][Configuration] +PreloadWeight=2 + +[Containments][32][Applets][64] +immutability=1 +plugin=org.kde.plasma.mediacontroller + +[Containments][32][Applets][64][Configuration] +PreloadWeight=0 + +[Containments][32][Applets][69] +immutability=1 +plugin=org.kde.plasma.mediaSimple + +[Containments][32][Applets][69][Configuration] +PreloadWeight=0 + +[Containments][32][Configuration] +PreloadWeight=18 + +[Containments][32][General] +extraItems=org.kde.plasma.battery,org.kde.plasma.clipboard,org.kde.plasma.devicenotifier,org.kde.plasma.manage-inputmethod,org.kde.plasma.mediacontroller,org.kde.plasma.notifications,org.kde.plasma.keyboardlayout,org.kde.plasma.volume,org.kde.plasma.networkmanagement,org.kde.plasma.keyboardindicator,org.kde.plasma.nightcolorcontrol,org.kde.plasma.bluetooth,org.kde.kscreen,org.kde.plasma.vault,org.kde.plasma.mediaSimple +knownItems=org.kde.plasma.battery,org.kde.plasma.clipboard,org.kde.plasma.devicenotifier,org.kde.plasma.manage-inputmethod,org.kde.plasma.mediacontroller,org.kde.plasma.notifications,org.kde.plasma.keyboardlayout,org.kde.plasma.volume,org.kde.plasma.networkmanagement,org.kde.plasma.keyboardindicator,org.kde.plasma.nightcolorcontrol,org.kde.plasma.bluetooth,org.kde.kscreen,org.kde.plasma.vault,org.kde.plasma.mediaSimple + +[Containments][45] +activityId= +formfactor=2 +immutability=1 +lastScreen=0 +location=4 +plugin=org.kde.panel +wallpaperplugin=org.kde.image + +[Containments][45][Applets][46] +immutability=1 +plugin=AndromedaLauncher + +[Containments][45][Applets][46][Configuration] +PreloadWeight=100 + +[Containments][45][Applets][46][Configuration][ConfigDialog] +DialogHeight=570 +DialogWidth=760 + +[Containments][45][Applets][46][Configuration][General] +customButtonImage=distributor-logo-arch +enableGreeting=false +floating=true +launcherPosition=1 +useCustomButtonImage=true + +[Containments][45][Applets][47] +immutability=1 +plugin=org.kde.plasma.systemtray + +[Containments][45][Applets][47][Configuration] +PreloadWeight=100 +SystrayContainmentId=48 + +[Containments][45][Applets][61] +immutability=1 +plugin=org.kde.plasma.icontasks + +[Containments][45][Applets][61][Configuration] +PreloadWeight=26 + +[Containments][45][Applets][61][Configuration][ConfigDialog] +DialogHeight=570 +DialogWidth=760 + +[Containments][45][Applets][61][Configuration][General] +highlightWindows=false +launchers= +middleClickAction=Close +showOnlyMinimized=1 +wheelEnabled=false +wheelSkipMinimized=false + +[Containments][45][Applets][66] +immutability=1 +plugin=org.kde.plasma.digitalclock + +[Containments][45][Applets][66][Configuration] +PreloadWeight=92 +popupHeight=500 +popupWidth=900 + +[Containments][45][Applets][66][Configuration][Appearance] +dateDisplayFormat=BelowTime +displayTimezoneFormat=UTCOffset +enabledCalendarPlugins=/usr/lib/qt/plugins/plasmacalendarplugins/holidaysevents.so +showSeconds=true +showWeekNumbers=true +use24hFormat=2 + +[Containments][45][Applets][66][Configuration][ConfigDialog] +DialogHeight=570 +DialogWidth=760 + +[Containments][45][ConfigDialog] +DialogHeight=91 +DialogWidth=2560 + +[Containments][45][Configuration] +PreloadWeight=26 + +[Containments][45][General] +AppletOrder=46;61;47;66 + +[Containments][48] +activityId= +formfactor=2 +immutability=1 +lastScreen=0 +location=4 +plugin=org.kde.plasma.private.systemtray +popupHeight=624 +popupWidth=624 +wallpaperplugin=org.kde.image + +[Containments][48][Applets][49] +immutability=1 +plugin=org.kde.plasma.clipboard + +[Containments][48][Applets][49][Configuration] +PreloadWeight=100 + +[Containments][48][Applets][50] +immutability=1 +plugin=org.kde.plasma.devicenotifier + +[Containments][48][Applets][50][Configuration] +PreloadWeight=100 + +[Containments][48][Applets][50][Configuration][General] +popupOnNewDevice=false + +[Containments][48][Applets][51][Configuration] +PreloadWeight=42 + +[Containments][48][Applets][52] +immutability=1 +plugin=org.kde.plasma.notifications + +[Containments][48][Applets][52][Configuration] +PreloadWeight=92 + +[Containments][48][Applets][53][Configuration] +PreloadWeight=42 + +[Containments][48][Applets][54] +immutability=1 +plugin=org.kde.plasma.volume + +[Containments][48][Applets][54][Configuration] +PreloadWeight=100 + +[Containments][48][Applets][54][Configuration][General] +migrated=true + +[Containments][48][Applets][55][Configuration] +PreloadWeight=42 + +[Containments][48][Applets][56][Configuration] +PreloadWeight=42 + +[Containments][48][Applets][57][Configuration] +PreloadWeight=42 + +[Containments][48][Applets][58][Configuration] +PreloadWeight=42 + +[Containments][48][Applets][62] +immutability=1 +plugin=org.kde.kscreen + +[Containments][48][Applets][62][Configuration] +PreloadWeight=26 + +[Containments][48][Applets][63] +immutability=1 +plugin=org.kde.plasma.vault + +[Containments][48][Applets][63][Configuration] +PreloadWeight=18 + +[Containments][48][Applets][68] +immutability=1 +plugin=org.kde.plasma.mediaSimple + +[Containments][48][Applets][68][Configuration] +PreloadWeight=0 + +[Containments][48][ConfigDialog] +DialogHeight=570 +DialogWidth=760 + +[Containments][48][Configuration] +PreloadWeight=26 + +[Containments][48][General] +extraItems=org.kde.plasma.clipboard,org.kde.plasma.devicenotifier,org.kde.plasma.notifications,org.kde.plasma.volume,org.kde.plasma.bluetooth,org.kde.kscreen,org.kde.plasma.vault,org.kde.plasma.mediaSimple +hiddenItems=chrome_status_icon_1 +knownItems=org.kde.plasma.battery,org.kde.plasma.clipboard,org.kde.plasma.devicenotifier,org.kde.plasma.manage-inputmethod,org.kde.plasma.mediacontroller,org.kde.plasma.notifications,org.kde.plasma.keyboardlayout,org.kde.plasma.volume,org.kde.plasma.networkmanagement,org.kde.plasma.keyboardindicator,org.kde.plasma.nightcolorcontrol,org.kde.plasma.bluetooth,org.kde.kscreen,org.kde.plasma.vault,org.kde.plasma.mediaSimple +shownItems=vlc,org.kde.plasma.volume,org.kde.plasma.clipboard + +[Containments][8] +activityId= +formfactor=2 +immutability=1 +lastScreen=0 +location=4 +plugin=org.kde.plasma.private.systemtray +wallpaperplugin=org.kde.image + +[Containments][8][Applets][10] +immutability=1 +plugin=org.kde.plasma.devicenotifier + +[Containments][8][Applets][10][Configuration] +PreloadWeight=18 + +[Containments][8][Applets][11] +immutability=1 +plugin=org.kde.plasma.manage-inputmethod + +[Containments][8][Applets][11][Configuration] +PreloadWeight=18 + +[Containments][8][Applets][12] +immutability=1 +plugin=org.kde.plasma.notifications + +[Containments][8][Applets][12][Configuration] +PreloadWeight=18 + +[Containments][8][Applets][13] +immutability=1 +plugin=org.kde.plasma.keyboardlayout + +[Containments][8][Applets][13][Configuration] +PreloadWeight=18 + +[Containments][8][Applets][14] +immutability=1 +plugin=org.kde.plasma.volume + +[Containments][8][Applets][14][Configuration] +PreloadWeight=18 + +[Containments][8][Applets][14][Configuration][General] +migrated=true + +[Containments][8][Applets][15] +immutability=1 +plugin=org.kde.plasma.keyboardindicator + +[Containments][8][Applets][15][Configuration] +PreloadWeight=18 + +[Containments][8][Applets][18] +immutability=1 +plugin=org.kde.plasma.nightcolorcontrol + +[Containments][8][Applets][18][Configuration] +PreloadWeight=0 + +[Containments][8][Applets][19] +immutability=1 +plugin=org.kde.plasma.networkmanagement + +[Containments][8][Applets][19][Configuration] +PreloadWeight=2 + +[Containments][8][Applets][20] +immutability=1 +plugin=org.kde.plasma.battery + +[Containments][8][Applets][20][Configuration] +PreloadWeight=18 + +[Containments][8][Applets][62] +immutability=1 +plugin=org.kde.plasma.mediacontroller + +[Containments][8][Applets][62][Configuration] +PreloadWeight=0 + +[Containments][8][Applets][64] +immutability=1 +plugin=org.kde.kscreen + +[Containments][8][Applets][64][Configuration] +PreloadWeight=26 + +[Containments][8][Applets][65] +immutability=1 +plugin=org.kde.plasma.vault + +[Containments][8][Applets][65][Configuration] +PreloadWeight=26 + +[Containments][8][Applets][67] +immutability=1 +plugin=org.kde.plasma.mediaSimple + +[Containments][8][Applets][67][Configuration] +PreloadWeight=0 + +[Containments][8][Applets][9] +immutability=1 +plugin=org.kde.plasma.clipboard + +[Containments][8][Applets][9][Configuration] +PreloadWeight=18 + +[Containments][8][Configuration] +PreloadWeight=18 + +[Containments][8][General] +extraItems=org.kde.plasma.battery,org.kde.plasma.clipboard,org.kde.plasma.devicenotifier,org.kde.plasma.manage-inputmethod,org.kde.plasma.mediacontroller,org.kde.plasma.notifications,org.kde.plasma.keyboardlayout,org.kde.plasma.volume,org.kde.plasma.networkmanagement,org.kde.plasma.keyboardindicator,org.kde.plasma.nightcolorcontrol,org.kde.plasma.bluetooth,org.kde.kscreen,org.kde.plasma.vault,org.kde.plasma.mediaSimple +knownItems=org.kde.plasma.battery,org.kde.plasma.clipboard,org.kde.plasma.devicenotifier,org.kde.plasma.manage-inputmethod,org.kde.plasma.mediacontroller,org.kde.plasma.notifications,org.kde.plasma.keyboardlayout,org.kde.plasma.volume,org.kde.plasma.networkmanagement,org.kde.plasma.keyboardindicator,org.kde.plasma.nightcolorcontrol,org.kde.plasma.bluetooth,org.kde.kscreen,org.kde.plasma.vault,org.kde.plasma.mediaSimple + +[ScreenMapping] +itemsOnDisabledScreens= +screenMapping= diff --git a/uninstall.sh b/uninstall.sh index c52c1210..250a71c3 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -53,6 +53,18 @@ unlink ".local/share/icons" unlink ".fonts" unlink ".config/fontconfig" +# kde +unlink ".local/share/plasma" +unlink ".config/kdedefaults" +unlink ".config/kglobalshortcutsrc" +unlink ".config/kiorc" +unlink ".config/krunnerrc" +unlink ".config/kservicemenurc" +unlink ".config/ksplashrc" +unlink ".config/ktimezonedrc" +unlink ".config/plasma-localrc" +unlink ".config/plasma-org.kde.plasma.desktop-appletsrc" + # programs unlink ".config/konsolerc" unlink ".local/share/konsole"