plasmoides KDE Store/GitHub (gnome-pager, kMenu, kvitals, windowtitle, claude, launchpad)

This commit is contained in:
Josevi
2026-07-08 20:47:59 +02:00
parent ca606377ee
commit dd3b0f6ae8
136 changed files with 20239 additions and 0 deletions
@@ -0,0 +1,21 @@
import QtQuick
import org.kde.plasma.configuration
ConfigModel {
ConfigCategory {
name: i18n("Appearance")
icon: "preferences-desktop-display-color"
source: "config/ConfigAppearance.qml"
}
ConfigCategory {
name: i18n("Behavior")
icon: "preferences-desktop"
source: "config/ConfigBehavior.qml"
}
ConfigCategory {
name: i18n("Substitutions")
icon: "edit-find-replace"
source: "config/ConfigSubstitutions.qml"
}
}
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name=""/>
<group name="Appearance">
<entry name="firstSpace" type="Int"><default>0</default></entry>
<entry name="midSpace" type="Int"><default>0</default></entry>
<entry name="lastSpace" type="Int"><default>0</default></entry>
<entry name="lengthKind" type="Int"><default>0</default></entry>
<entry name="fontSize" type="Int"><default>12</default></entry>
<entry name="iconSize" type="Int"><default>24</default></entry>
<entry name="fixedLength" type="Int"><default>400</default></entry>
<entry name="minLength" type="Int"><default>100</default></entry>
<entry name="customSize" type="Int"><default>24</default></entry>
<entry name="elidePos" type="Int"><default>3</default></entry>
<entry name="txt" type="String"><default>%a - %w</default></entry>
<entry name="altTxt" type="String"><default>%q</default></entry>
<entry name="txtSameFound" type="String"><default>%a</default></entry>
<entry name="customIcon" type="String"><default>kde-symbolic</default></entry>
<entry name="isBold" type="Bool"><default>false</default></entry>
<entry name="isItalic" type="Bool"><default>false</default></entry>
<entry name="isCaps" type="Bool"><default>false</default></entry>
<entry name="visible" type="Bool"><default>true</default></entry>
<entry name="fillThickness" type="Bool"><default>false</default></entry>
<entry name="noIcon" type="Bool"><default>false</default></entry>
<entry name="activityIcon" type="Bool"><default>true</default></entry>
<entry name="horizontalAlignment" type="Int"><default>1</default></entry>
<entry name="hideWhenUnavailable" type="Bool"><default>false</default></entry>
</group>
<group name="Behavior">
<entry name="filterByScreen" type="Bool"><default>false</default></entry>
<entry name="filterByMaximized" type="Bool"><default>false</default></entry>
<entry name="showTooltip" type="Bool"><default>true</default></entry>
<entry name="maxminAllowed" type="Bool"><default>true</default></entry>
<entry name="closeAllowed" type="Bool"><default>true</default></entry>
<entry name="scrollAllowed" type="Bool"><default>true</default></entry>
</group>
<group name="Substitutions">
<entry name="subsMatchApp" type="StringList"><default>"Telegram Desktop","Gimp-.*","soffice.bin","Spotify.*","Kate.*"</default></entry>
<entry name="subsMatchTitle" type="StringList"><default>".*",".*",".*",".*",".*"</default></entry>
<entry name="subsReplace" type="StringList"><default>"Telegram","Gimp","LibreOffice","Spotify","Kate : %w"</default></entry>
</group>
</kcfg>
@@ -0,0 +1,51 @@
function clean(item)
{
if (item.length>=2 && item.indexOf('"')===0 && item.lastIndexOf('"')===item.length-1) return item.substring(1, item.length-1);
else return item;
}
function match(pat,str){
let rgx = new RegExp(clean(pat))
return rgx.test(str)
}
function sub(str){
return str
.replace("%a",activeTaskItem?.appName??"")
.replace("%w",activeTaskItem?.title??"")
.replace("%q",fullActivityInfo?.name??"")
}
function substitute() {
let minSize = Math.min(cfg.subsMatchApp.length, cfg.subsReplace.length,cfg.subsMatchTitle.length)
let appName=activeTaskItem.appName, title=activeTaskItem.title
let text= appName === title ? cfg.txtSameFound : cfg.txt
for(let i=0; i<minSize; i++){
if(match(cfg.subsMatchApp[i],appName) && match(cfg.subsMatchTitle[i],title)){
text = clean(cfg.subsReplace[i])
}
}
return sub(text)
}
function altSubstitute() {
return cfg.altTxt.replace("%q",fullActivityInfo.name)
}
function getText() {
if(isActiveWindowMaximized) return Tools.substitute()
else if(cfg.filterByMaximized) return Tools.altSubstitute()
else if(existsWindowActive) return Tools.substitute()
else return Tools.altSubstitute()
}
function getIcon() {
if((existsWindowActive&&!cfg.filterByMaximized)||(cfg.filterByMaximized&&isActiveWindowMaximized)) return activeTaskItem.icon
else if(cfg.noIcon) return ""
else if(cfg.activityIcon) return fullActivityInfo.icon
else return cfg.customIcon
}
function getElide(val) {
switch(val) {
case 0: return Text.ElideNone
case 1: return Text.ElideLeft
case 2: return Text.ElideMiddle
case 3: return Text.ElideRight
}
}
@@ -0,0 +1,51 @@
import QtQuick
import org.kde.plasma.core
import org.kde.plasma.plasmoid
MouseArea {
id: actionsArea
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
anchors.fill: parent
property bool wheelIsBlocked: false
onClicked: function(event){
if(existsWindowActive && event.button === Qt.MiddleButton && cfg.closeAllowed)
windowInfoLoader.item.requestClose();
}
onDoubleClicked: {
if(existsWindowActive && cfg.maxminAllowed)
windowInfoLoader.item.toggleMaximized();
}
onWheel: function(wheel) {
if (wheelIsBlocked || !cfg.scrollAllowed) return;
wheelIsBlocked = true;
scrollDelayer.start();
var delta = 0;
if (wheel.angleDelta.y>=0 && wheel.angleDelta.x>=0) delta = Math.max(wheel.angleDelta.y, wheel.angleDelta.x) / 8;
else delta = Math.min(wheel.angleDelta.y, wheel.angleDelta.x) / 8;
var ctrlPressed = (wheel.modifiers & Qt.ControlModifier);
if (delta>10) {
if (!ctrlPressed) windowInfoLoader.item.activateNextPrevTask(true);
else if (windowInfoLoader.item.activeTaskItem && !windowInfoLoader.item.activeTaskItem.isMaximized) windowInfoLoader.item.toggleMaximized();
} else if (delta<-10) {
if (!ctrlPressed) {
if (windowInfoLoader.item.activeTaskItem
&& !windowInfoLoader.item.activeTaskItem.isMinimized
&& windowInfoLoader.item.activeTaskItem.isMaximized) // Maximized
windowInfoLoader.item.activeTaskItem.toggleMaximized();
else if (windowInfoLoader.item.activeTaskItem
&& !windowInfoLoader.item.activeTaskItem.isMinimized
&& !windowInfoLoader.item.activeTaskItem.isMaximized) // UnMaximized
windowInfoLoader.item.activeTaskItem.toggleMinimized();
} else if (windowInfoLoader.item.activeTaskItem
&& windowInfoLoader.item.activeTaskItem.isMaximized)
windowInfoLoader.item.activeTaskItem.toggleMaximized();
}
}
// To optimize scrolling for touchpads
Timer{
id: scrollDelayer
interval: 200
onTriggered: actionsArea.wheelIsBlocked = false;
}
}
@@ -0,0 +1,11 @@
import QtQuick
import QtQuick.Layouts
//Custom item to make the code look cleaner
Item {
required property real length
Layout.minimumWidth: isVertical?root.width :length
Layout.maximumWidth: isVertical?root.width :length
Layout.minimumHeight:!isVertical?root.height:length
Layout.maximumHeight:!isVertical?root.height:length
}
@@ -0,0 +1,219 @@
import QtQuick
import QtQml.Models
import org.kde.taskmanager as TaskManager
Item {
id: plasmaTasksItem
readonly property bool existsWindowActive: root.activeTaskItem && tasksRepeater.count > 0 && activeTaskItem.isActive
property Item activeTaskItem: null
TaskManager.TasksModel {
id: tasksModel
sortMode: TaskManager.TasksModel.SortVirtualDesktop
groupMode: TaskManager.TasksModel.GroupDisabled
screenGeometry: root.screenGeometry
activity: activityInfo.currentActivity
virtualDesktop: virtualDesktopInfo.currentDesktop
filterByScreen: plasmoid.configuration.filterByScreen
filterByVirtualDesktop: true
filterByActivity: true
}
Item{
id: taskList
Repeater{
id: tasksRepeater
model: tasksModel
Item{
id: task
readonly property string appName: modelAppName !== "" ? modelAppName : discoveredAppName
readonly property bool isMinimized: IsMinimized === true ? true : false
readonly property bool isMaximized: IsMaximized === true ? true : false
readonly property bool isActive: IsActive === true ? true : false
readonly property bool isOnAllDesktops: IsOnAllVirtualDesktops === true ? true : false
property var icon: decoration
readonly property string modelAppName: AppName
readonly property string modelDisplay: display
property string title: ""
property string discoveredAppName: ""
readonly property var m: model
function cleanupTitle() {
var text = display;
var t = modelDisplay;
var sep = t.lastIndexOf(" —– ");
var spacer = 4;
if (sep === -1) {
sep = t.lastIndexOf(" -- ");
spacer = 4;
}
if (sep === -1) {
sep = t.lastIndexOf(" -- ");
spacer = 4;
}
if (sep === -1) {
sep = t.lastIndexOf(" — ");
spacer = 3;
}
if (sep === -1) {
sep = t.lastIndexOf(" - ");
spacer = 3;
}
var dTitle = "";
var dAppName = "";
if (sep>-1) {
dTitle = text.substring(0, sep);
discoveredAppName = text.substring(sep+spacer, text.length);
//if title starts with application name, swap the found records
if (dTitle.startsWith(modelAppName)) {
var firstPart = dTitle;
dTitle = discoveredAppName;
discoveredAppName = firstPart;
}
}
if (sep>-1) {
title = dTitle;
} else {
title = t;
}
}
onIsActiveChanged: {
if (isActive) {
if(plasmoid.configuration.showOnlyOnMaximize && !task.isMaximized)
plasmaTasksItem.activeTaskItem = null;
else
plasmaTasksItem.activeTaskItem = task;
}
}
onIsMaximizedChanged: {
if(plasmoid.configuration.showOnlyOnMaximize && isActive)
plasmaTasksItem.activeTaskItem = task.isMaximized ? task : null;
}
onModelAppNameChanged: task.cleanupTitle()
onModelDisplayChanged: task.cleanupTitle()
Component.onCompleted: task.cleanupTitle()
Component.onDestruction: {
if (plasmaTasksItem.lastActiveTaskItem === task) {
plasmaTasksItem.lastActiveTaskItem = null;
}
}
function modelIndex(){
return tasksModel.makeModelIndex(index);
}
function toggleMaximized() {
tasksModel.requestToggleMaximized(modelIndex());
}
function toggleMinimized() {
tasksModel.requestToggleMinimized(modelIndex());
}
function requestClose() {
tasksModel.requestClose(modelIndex());
}
function togglePinToAllDesktops() {
tasksModel.requestVirtualDesktop(modelIndex(), 0);
}
function toggleKeepAbove(){
tasksModel.requestToggleKeepAbove(modelIndex());
}
}
}
}
//! Functionality
function toggleMaximized() {
if (activeTaskItem) {
activeTaskItem.toggleMaximized();
}
}
function toggleMinimized() {
if (activeTaskItem)
activeTaskItem.toggleMinimized();
}
function requestClose() {
if (activeTaskItem)
activeTaskItem.requestClose();
}
function togglePinToAllDesktops() {
if (activeTaskItem) {
activeTaskItem.togglePinToAllDesktops();
}
}
function toggleKeepAbove(){
if (activeTaskItem) {
activeTaskItem.toggleKeepAbove();
}
}
//! Cycle Through Tasks
function activateNextPrevTask(next) {
var taskIndexList = [];
var activeTaskIndex = tasksModel.activeTask;
for (var i = 0; i < taskList.children.length - 1; ++i) {
var task = taskList.children[i];
var modelIndex = task.modelIndex(i);
if (task.m.IsLauncher !== true && task.m.IsStartup !== true) {
if (task.m.IsGroupParent === true) {
for (var j = 0; j < tasksModel.rowCount(modelIndex); ++j) {
taskIndexList.push(tasksModel.makeModelIndex(i, j));
}
} else {
taskIndexList.push(modelIndex);
}
}
}
if (!taskIndexList.length) {
return;
}
var target = taskIndexList[0];
for (var i = 0; i < taskIndexList.length; ++i) {
if (taskIndexList[i] === activeTaskIndex)
{
if (next && i < (taskIndexList.length - 1)) {
target = taskIndexList[i + 1];
} else if (!next) {
if (i) {
target = taskIndexList[i - 1];
} else {
target = taskIndexList[taskIndexList.length - 1];
}
}
break;
}
}
tasksModel.requestActivate(target);
}
}
@@ -0,0 +1,100 @@
import QtQuick
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.plasma.components as PlasmaComponents
import org.kde.plasma.core as PlasmaCore
import "../tools/Tools.js" as Tools
GridLayout {
columns: isVertical?1:7
anchors.fill: parent
rowSpacing: 0
columnSpacing: 0
Layout.maximumWidth: parent.width
Layout.maximumHeight: parent.height
// Calculated label length for fixed/max/minMax modes.
// For minimum-only (kind 3), the label grows freely, so we use implicitWidth.
property real labelLen : {
let neededInViewLen = cfg.firstSpace + cfg.midSpace + cfg.lastSpace + cfg.lastSpace
neededInViewLen += isVertical ? iconItem.height : iconItem.width
return cfg.fixedLength - neededInViewLen
}
Item {
Layout.fillWidth: (cfg.horizontalAlignment === 1 || cfg.horizontalAlignment === 2) && !isVertical
Layout.fillHeight: (cfg.horizontalAlignment === 1 || cfg.horizontalAlignment === 2) && isVertical
}
CItem {length: cfg.firstSpace}
Item {
id: iconItem
Layout.minimumWidth : isVertical ? parent.width : height
Layout.minimumHeight : isVertical ? width : parent.height
Layout.maximumWidth : Layout.minimumWidth
Layout.maximumHeight : Layout.minimumHeight
visible : cfg.visible
property int thickness: isVertical ? parent.width : parent.height
Kirigami.Icon {
anchors {
fill : parent
topMargin : !isVertical ? thickMargin : 0
bottomMargin : !isVertical ? thickMargin : 0
leftMargin : isVertical ? thickMargin : 0
rightMargin : isVertical ? thickMargin : 0
}
source: root.icon
readonly property int thickMargin: cfg.fillThickness ? 0 : (parent.thickness - iconSize) / 2
readonly property int iconSize : cfg.fillThickness ? parent.thickness : Math.min(parent.thickness, cfg.customSize)
}
}
CItem {length: cfg.midSpace}
CItem{
// lengthKind:
// 0 = contents (free) → label width = implicitWidth
// 1 = fixed → label width = labelLen (from fixedLength)
// 2 = maximum → label width = min(implicitWidth, labelLen)
// 3 = minimum → label grows freely; min enforced by root Layout
// 4 = min + max → label width = min(implicitWidth, labelLen)
length : {
if (cfg.lengthKind === 0) return label.implicitWidth
else if (cfg.lengthKind === 1) return labelLen
else if (cfg.lengthKind === 2) return Math.min(label.implicitWidth, labelLen)
else if (cfg.lengthKind === 3) return label.implicitWidth
else return Math.min(label.implicitWidth, labelLen)
}
clip: true
PlasmaComponents.Label {
id : label
horizontalAlignment : {
if (isVertical) return Text.AlignHCenter;
if (cfg.horizontalAlignment === 0) return Text.AlignLeft;
if (cfg.horizontalAlignment === 2) return Text.AlignRight;
return Text.AlignHCenter;
}
verticalAlignment : Text.AlignVCenter
text : root.text
color : Kirigami.Theme.textColor
elide : Tools.getElide(cfg.elidePos)
width : {
if (cfg.lengthKind === 0) return label.implicitWidth
else if (cfg.lengthKind === 1) return labelLen
else if (cfg.lengthKind === 2) return Math.min(label.implicitWidth, labelLen)
else if (cfg.lengthKind === 3) return label.implicitWidth
else return Math.min(label.implicitWidth, labelLen)
}
rotation : isVertical?plasmoid.location===PlasmaCore.Types.LeftEdge?-90:90:0
anchors.centerIn : parent
font {
capitalization : cfg.isCaps ? Font.Capitalize : Font.MixedCase
bold : cfg.isBold
italic : cfg.isItalic
pixelSize : cfg.fontSize
}
}
}
CItem {length:cfg.lastSpace}
Item {
Layout.fillWidth: (cfg.horizontalAlignment === 0 || cfg.horizontalAlignment === 1) && !isVertical
Layout.fillHeight: (cfg.horizontalAlignment === 0 || cfg.horizontalAlignment === 1) && isVertical
}
}
@@ -0,0 +1,260 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami as Kirigami
import org.kde.plasma.components as PC3
import org.kde.iconthemes as KIconThemes
import org.kde.ksvg as KSvg
import "../../tools/Tools.js" as Tools
Kirigami.ScrollablePage {
id: root
readonly property alias cfg_firstSpace: firstSpace.value
readonly property alias cfg_midSpace: midSpace.value
readonly property alias cfg_lastSpace: lastSpace.value
readonly property alias cfg_txt: txt.text
readonly property alias cfg_altTxt: altTxt.text
readonly property alias cfg_isBold: boldChk.checked
readonly property alias cfg_isItalic: italicChk.checked
readonly property alias cfg_isCaps: capsChk.checked
readonly property alias cfg_fontSize: fontSize.value
readonly property alias cfg_visible: iconChk.checked
readonly property alias cfg_lengthKind: lengthKind.currentIndex
readonly property alias cfg_fixedLength: fixedLength.value
readonly property alias cfg_minLength: minLength.value
readonly property alias cfg_fillThickness: fillThickness.checked
readonly property alias cfg_noIcon: noIcon.checked
readonly property alias cfg_activityIcon: activityIcon.checked
readonly property alias cfg_customIcon: iconDialog.value
readonly property alias cfg_txtSameFound: txtSameFound.text
readonly property alias cfg_customSize: customSize.value
readonly property alias cfg_elidePos: elidePos.currentIndex
readonly property alias cfg_horizontalAlignment: alignmentCombo.currentIndex
readonly property alias cfg_hideWhenUnavailable: hideWhenUnavailableChk.checked
// lengthKind reference:
// 0 = Based on contents
// 1 = Fixed Length
// 2 = Maximum Length
// 3 = Minimum Length (new)
// 4 = Min + Max Length (new)
readonly property bool needsFixedLen: lengthKind.currentIndex === 1 || lengthKind.currentIndex === 2 || lengthKind.currentIndex === 4
readonly property bool needsMinLen: lengthKind.currentIndex === 3 || lengthKind.currentIndex === 4
header : MockWidget{}
Kirigami.FormLayout {
Layout.fillWidth: true
Kirigami.Separator {
Kirigami.FormData.isSection: true
Kirigami.FormData.label: "Text"
}
RowLayout {
Kirigami.FormData.label: i18n("When title available:")
PC3.TextField { id: txt }
PC3.ToolButton {
icon.name: "documentinfo"
PC3.ToolTip{ text: i18n("This pattern will be shown when a window is active.<p>
<b><i>Substitutions:</i></b><p>
%a - Application Name<p>
%w - Window Title<p>
%q - Activity Info<p>
Use HTML tags for bold, italic and multi-line text") }
}
}
RowLayout {
Kirigami.FormData.label: i18n("When Application Name and Window Title are same:")
PC3.TextField { id: txtSameFound }
PC3.ToolButton {
icon.name: "documentinfo"
PC3.ToolTip{ text: i18n("To prevent results like:<p>Neovide - Neovide") }
}
}
RowLayout{
Kirigami.FormData.label: i18n("When title unavailable:")
PC3.TextField {
id: altTxt
text: "%q"
}
PC3.ToolButton {
icon.name: "documentinfo"
PC3.ToolTip{ text: i18n("This pattern will be shown when no window is active.<p>
<b>Substitutions:</b><p>
%q - Activity Info<p>
Use HTML tags for bold, italic and multi-line text") }
}
}
PC3.CheckBox {
id: hideWhenUnavailableChk
Kirigami.FormData.label: i18n("Hide widget:")
text: i18n("When title unavailable")
}
RowLayout {
Kirigami.FormData.label: i18n("Text Formatting:")
PC3.SpinBox{
id: fontSize
from: 8
to: 64
}
PC3.ToolButton{
id: boldChk
checkable: true
icon.name: "format-text-bold"
display: AbstractButton.IconOnly
text: i18n("Bold")
height: Kirigami.Units.smallSpacing
PC3.ToolTip{ text: i18n("<b>Bold</b>") }
}
PC3.ToolButton{
id: italicChk
checkable: true
display: AbstractButton.IconOnly
text: i18n("Italic")
icon.name: "format-text-italic"
height: Kirigami.Units.smallSpacing
PC3.ToolTip{ text: i18n("<i>Italic</i>") }
}
PC3.ToolButton{
id: capsChk
checkable: true
icon.name: "format-text-capitalize"
text: i18n("Capitalize")
display: AbstractButton.IconOnly
height: Kirigami.Units.smallSpacing
PC3.ToolTip{ text: i18n("<b>C</b>apitalize <b>F</b>irst <b>L</b>etters") }
}
}
PC3.ComboBox {
id: elidePos
Kirigami.FormData.label: i18n("Elide Position:")
model: ["None","Left","Middle","Right"]
// Elide only makes sense when text can be truncated (fixed/max/minMax)
visible: needsFixedLen
}
Kirigami.Separator {
Kirigami.FormData.isSection: true
Kirigami.FormData.label: "Icon"
}
PC3.CheckBox {
id: iconChk
Kirigami.FormData.label: i18n("Visible:")
}
RowLayout {
Kirigami.FormData.label: i18n("Size:")
RadioButton{
id: customThickness
text: i18n("Custom Size")
icon.name:"image-resize-symbolic"
checked: !fillThickness.checked
}
RadioButton{
id: fillThickness
text: i18n("Fill Thickness")
icon.name: "panel-fit-height"
}
}
PC3.SpinBox{
id: customSize
from: 8
to: 50
enabled: customThickness.checked
}
RowLayout {
Kirigami.FormData.label: i18n("Placeholder icon:")
RadioButton{
id: customIcon
text: i18n("Custom Icon")
icon.name:"dialog-icon-preview"
checked: !activityIcon.checked && !noIcon.checked
}
RadioButton{
id: activityIcon
text: i18n("Activity Icon")
icon.name: "activities"
}
RadioButton{
id: noIcon
text: i18n("Preserve Space")
icon.name: "edit-none"
}
}
IconDialog{
id: iconDialog
visible: customIcon.checked
}
Kirigami.Separator {
Kirigami.FormData.isSection: true
Kirigami.FormData.label: "Size & Margins"
}
PC3.ComboBox {
id: lengthKind
Kirigami.FormData.label: i18n("Length:")
model: [
i18n("Based on contents"),
i18n("Fixed Length"),
i18n("Maximum Length"),
i18n("Minimum Length"),
i18n("Min + Max Length")
]
}
// Fixed / Maximum length slider (kinds 1, 2, 4)
RowLayout{
Kirigami.FormData.label: needsFixedLen && needsMinLen
? i18n("Maximum length:")
: i18n("Custom length:")
visible: needsFixedLen
PC3.Slider{
id: fixedLength
from: 24
to: 1500
stepSize: 1
}
PC3.Label{
text: fixedLength.value + " px."
}
}
// Minimum length slider (kinds 3, 4)
RowLayout{
Kirigami.FormData.label: i18n("Minimum length:")
visible: needsMinLen
PC3.Slider{
id: minLength
from: 0
to: 1500
stepSize: 1
}
PC3.Label{
text: minLength.value + " px."
}
}
PC3.ComboBox {
id: alignmentCombo
Kirigami.FormData.label: i18n("Text Alignment:")
model: [i18n("Left"), i18n("Center"), i18n("Right")]
visible: needsFixedLen
}
PC3.SpinBox {
id: firstSpace
Kirigami.FormData.label: i18n("Space before icon:")
from: 0
to: 999
}
PC3.SpinBox {
id: midSpace
Kirigami.FormData.label: i18n("Space between icon and text:")
from: 0
to: 999
}
PC3.SpinBox {
id: lastSpace
Kirigami.FormData.label: i18n("Space after text:")
from: 0
to: 999
}
}
}
@@ -0,0 +1,52 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.plasmoid
import org.kde.plasma.components as PC3
import org.kde.kirigami as Kirigami
Kirigami.ScrollablePage {
readonly property alias cfg_filterByScreen: filterByScreenChk.checked
readonly property alias cfg_filterByMaximized: filterByMaximizedChk.checked
readonly property alias cfg_showTooltip: showTooltipChk.checked
readonly property alias cfg_maxminAllowed: maxminAllowed.checked
readonly property alias cfg_closeAllowed: closeAllowed.checked
readonly property alias cfg_scrollAllowed: scrollAllowed.checked
Kirigami.FormLayout {
Kirigami.Separator {
Kirigami.FormData.isSection: true
Kirigami.FormData.label: "Info Filtering"
}
PC3.CheckBox{
id: filterByScreenChk
Kirigami.FormData.label: i18n("Show only from current screen:")
}
PC3.CheckBox{
id: filterByMaximizedChk
Kirigami.FormData.label: i18n("Show only when maximized:")
}
Kirigami.Separator {
Kirigami.FormData.isSection: true
Kirigami.FormData.label: "Gestures"
}
PC3.CheckBox{
id: showTooltipChk
Kirigami.FormData.label: i18n("Show tooltip on hover:")
}
PC3.CheckBox{
id: maxminAllowed
Kirigami.FormData.label: i18n("Double-Click to maximize/minimize:")
}
PC3.CheckBox{
id: closeAllowed
Kirigami.FormData.label: i18n("Middle-Click to close:")
}
PC3.CheckBox{
id: scrollAllowed
Kirigami.FormData.label: i18n("Scroll through tasks:")
}
}
}
@@ -0,0 +1,49 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami as Kirigami
import org.kde.plasma.components as PC3
import org.kde.iconthemes as KIconThemes
import org.kde.ksvg as KSvg
Kirigami.ScrollablePage {
id: subsPage
function textAreaToList(text) { return text.split('\n') }
function listToText(list) { return list.join('\n') }
readonly property alias cfg_subsMatchApp : subsPage.nameMatches
readonly property alias cfg_subsMatchTitle: subsPage.titleMatches
readonly property alias cfg_subsReplace : subsPage.replacements
property var nameMatches
property var titleMatches
property var replacements
header:Kirigami.InlineMessage {
Layout.fillWidth: true
text: i18n("Length of lists is not equal")
visible: !(nameMatches.length == titleMatches.length && titleMatches.length == replacements.length)
type: Kirigami.MessageType.Warning
}
// TODO: Clean this, not the most elegant way to handle it!
RowLayout{
SubsBox{
id: nameMatch
heading: i18n("Application Name Match")
subsAllowed: false
list: nameMatches
onListChanged: nameMatches = list
}
SubsBox{
id: titleMatch
heading: i18n("Window Title Match")
subsAllowed: false
list: titleMatches
onListChanged: titleMatches = list
}
SubsBox{
id: replace
heading: i18n("Replacement")
list: replacements
onListChanged: replacements = list
}
}
}
@@ -0,0 +1,54 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami as Kirigami
import org.kde.plasma.components as PlasmaComponents
import org.kde.iconthemes as KIconThemes
import org.kde.ksvg as KSvg
RowLayout {
property alias value: placeHolderIcon.source
Button {
implicitWidth: previewFrame.width + Kirigami.Units.smallSpacing * 2
implicitHeight: previewFrame.height + Kirigami.Units.smallSpacing * 2
onPressed: iconMenu.opened ? iconMenu.close() : iconMenu.open()
KIconThemes.IconDialog {
id: iconDialog
onIconNameChanged: value = iconName
}
KSvg.FrameSvgItem {
id: previewFrame
anchors.centerIn: parent
imagePath: "widgets/panel-background"
width: Kirigami.Units.iconSizes.large + fixedMargins.left + fixedMargins.right
height: Kirigami.Units.iconSizes.large + fixedMargins.top + fixedMargins.bottom
Kirigami.Icon {
id: placeHolderIcon
anchors.centerIn: parent
width: Kirigami.Units.iconSizes.large
height: width
source: "kde-symbolic"
}
}
Menu {
id:iconMenu
y: parent.height
MenuItem {
text: i18nc("@item:inmenu Open icon chooser dialog", "Choose…")
icon.name: "document-open-folder"
Accessible.description: i18nc("@info:whatsthis", "Choose an icon for Application Launcher")
onClicked: iconDialog.open()
}
MenuItem {
text: i18nc("@item:inmenu Reset icon to default", "Reset to default icon")
icon.name: "kt-restore-defaults"
onClicked: value = "kde-symbolic"
}
}
}
PlasmaComponents.Label{
text:`"${value}"`
}
}
@@ -0,0 +1,113 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami as Kirigami
import org.kde.plasma.components as PlasmaComponents
import org.kde.iconthemes as KIconThemes
import org.kde.ksvg as KSvg
import org.kde.plasma.plasmoid as Plasmoid
import "../../tools/Tools.js" as Tools
Item {
id: root
readonly property int floatingMargins: Kirigami.Units.largeSpacing
readonly property int panelHeight: 44
property bool active: true
height: Math.max(20, Math.max(icon.implicitHeight,txt.implicitHeight))+26
Layout.fillWidth: true
KSvg.FrameSvgItem {
anchors.fill: parent
anchors.topMargin: -margins.top
anchors.leftMargin: -margins.left
anchors.rightMargin: -margins.right
anchors.bottomMargin: -margins.bottom
imagePath: "solid/widgets/panel-background"
prefix: "shadow"
}
Item {
height: root.panelHeight
anchors.fill: root
anchors.margins: root.floatingMargins
clip: true
KSvg.FrameSvgItem {
anchors.fill: parent
imagePath: "widgets/panel-background"
enabledBorders: "AllBorders"
}
RowLayout {
anchors.fill: parent
anchors.leftMargin: Kirigami.Units.largeSpacing
anchors.rightMargin: Kirigami.Units.largeSpacing
spacing: 0
Item{
Layout.minimumWidth: cfg_firstSpace
Layout.maximumWidth: cfg_firstSpace
}
Item {
id: icon
Layout.minimumWidth : height
Layout.minimumHeight : parent.height
Layout.maximumWidth : Layout.minimumWidth
Layout.maximumHeight : Layout.minimumHeight
visible : cfg_visible
property int thickness: parent.height
Kirigami.Icon {
anchors {
fill : parent
topMargin : thickMargin
bottomMargin : thickMargin
}
source: root.active?"kate":
cfg_noIcon?"":
cfg_activityIcon?"activities":cfg_customIcon
readonly property int thickMargin: cfg_fillThickness ? 0 : (parent.thickness - iconSize) / 2
readonly property int iconSize : cfg_fillThickness ? parent.thickness : Math.min(parent.thickness, cfg_customSize)
}
}
Item{
Layout.minimumWidth: cfg_midSpace
Layout.maximumWidth: cfg_midSpace
}
PlasmaComponents.Label {
id: txt
text : active
? cfg_txt.replace("%a","Kate").replace("%w","main.qml").replace("%q","Default")
: cfg_altTxt.replace("%q","ActivityName")
color : Kirigami.Theme.textColor
verticalAlignment : Text.AlignVCenter
elide : Tools.getElide(cfg_elidePos)
// Preview all 5 length kinds correctly
Layout.minimumWidth : {
if (cfg_lengthKind === 0) return implicitWidth
else if (cfg_lengthKind === 1) return cfg_fixedLength
else if (cfg_lengthKind === 2) return Math.min(implicitWidth, cfg_fixedLength)
else if (cfg_lengthKind === 3) return Math.max(implicitWidth, cfg_minLength)
else return Math.min(Math.max(implicitWidth, cfg_minLength), cfg_fixedLength)
}
Layout.maximumWidth : Layout.minimumWidth
font {
capitalization : cfg_isCaps
bold : cfg_isBold
italic : cfg_isItalic
pixelSize : cfg_fontSize
}
}
Item{
Layout.minimumWidth: cfg_lastSpace
Layout.maximumWidth: cfg_lastSpace
}
Item{
Layout.fillWidth: true
}
PlasmaComponents.ToolButton {
id: activeSwitch
icon.name: "exchange-positions"
PlasmaComponents.ToolTip{ text: i18n(active?"With active window":"With no active window") }
onClicked: active = !active
}
}
}
}
@@ -0,0 +1,33 @@
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.components as PC3
import org.kde.kirigami as Kirigami
ColumnLayout{
required property var list
property alias heading: head.text
property alias subsAllowed: subsInfo.visible
RowLayout{
Kirigami.Heading{
id: head
level: 2
}
PC3.ToolButton{
id: subsInfo
icon.name: "documentinfo"
PC3.ToolTip { text: i18n("<b>Substitutions allowed:</b><p>%a: Application Name<p>%w: Window Title<p>%q : Activity Name") }
}
}
PC3.TextArea{
Layout.fillWidth: true
Layout.fillHeight: true
text: listToText(list)
onTextChanged: list = textAreaToList(text)
Flickable {
onContentYChanged: {
replace.flickableItem.contentY = flickableItem.contentY
titleMatch.flickableItem.contentY = flickableItem.contentY
}
}
}
}
@@ -0,0 +1,183 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import org.kde.plasma.plasmoid
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components as PlasmaComponents
import org.kde.taskmanager as TaskManager
import org.kde.kirigami as Kirigami
import org.kde.activities as Activities
import "../tools/Tools.js" as Tools
PlasmoidItem {
id: root
clip: true
Plasmoid.constraintHints: Plasmoid.CanFillArea
preferredRepresentation: fullRepresentation
readonly property bool isVertical: plasmoid.formFactor === PlasmaCore.Types.Vertical
readonly property bool existsWindowActive: windowInfoLoader.item && windowInfoLoader.item.existsWindowActive
readonly property bool isActiveWindowPinned: existsWindowActive && activeTaskItem.isOnAllDesktops
readonly property bool isActiveWindowMaximized: existsWindowActive && activeTaskItem.isMaximized
readonly property var cfg: plasmoid.configuration
property Item activeTaskItem: windowInfoLoader.item.activeTaskItem
property var icon: Tools.getIcon()
property string text: Tools.getText()
Plasmoid.status: (cfg.hideWhenUnavailable && (!existsWindowActive || root.text === "")) ? PlasmaCore.Types.HiddenStatus : PlasmaCore.Types.ActiveStatus
states: [
State{
name: "editMode"
when: Plasmoid.containment.corona?.editMode?true:false
PropertyChanges{
target: root
text: "Edit Mode"
icon: "document-edit"
Layout.minimumWidth: isVertical?parent.width:titleLayout.implicitWidth
Layout.maximumWidth: Layout.minimumWidth
Layout.minimumHeight: isVertical?titleLayout.implicitHeight:parent.height
Layout.maximumHeight: Layout.minimumHeight
}
},
// --- Horizontal states ---
State{
name: "contentsLength"
when: cfg.lengthKind === 0 && !isVertical
PropertyChanges{
target: root
Layout.minimumWidth: titleLayout.implicitWidth
Layout.maximumWidth: Layout.minimumWidth
Layout.fillHeight: true
}
},
State{
name: "fixedLength"
when: cfg.lengthKind === 1 && !isVertical
PropertyChanges{
target: root
Layout.minimumWidth: cfg.fixedLength
Layout.maximumWidth: cfg.fixedLength
Layout.fillHeight: true
}
},
State{
name: "maximumLength"
when: cfg.lengthKind === 2 && !isVertical
PropertyChanges{
target: root
Layout.minimumWidth: Math.min(cfg.fixedLength, titleLayout.implicitWidth)
Layout.maximumWidth: Math.min(cfg.fixedLength, titleLayout.implicitWidth)
Layout.fillHeight: true
}
},
State{
name: "minimumLength"
when: cfg.lengthKind === 3 && !isVertical
PropertyChanges{
target: root
Layout.minimumWidth: Math.max(cfg.minLength, titleLayout.implicitWidth)
Layout.maximumWidth: Math.max(cfg.minLength, titleLayout.implicitWidth)
Layout.fillHeight: true
}
},
State{
name: "minMaxLength"
when: cfg.lengthKind === 4 && !isVertical
PropertyChanges{
target: root
Layout.minimumWidth: Math.max(cfg.minLength, Math.min(cfg.fixedLength, titleLayout.implicitWidth))
Layout.maximumWidth: Math.max(cfg.minLength, Math.min(cfg.fixedLength, titleLayout.implicitWidth))
Layout.fillHeight: true
}
},
// --- Vertical states ---
State{
name: "contentsLengthVert"
when: cfg.lengthKind === 0 && isVertical
PropertyChanges{
target: root
Layout.minimumHeight: titleLayout.implicitHeight
Layout.maximumHeight: Layout.minimumHeight
Layout.fillWidth: true
}
},
State{
name: "fixedLengthVert"
when: cfg.lengthKind === 1 && isVertical
PropertyChanges{
target: root
Layout.minimumHeight: cfg.fixedLength
Layout.maximumHeight: cfg.fixedLength
Layout.fillWidth: true
}
},
State{
name: "maximumLengthVert"
when: cfg.lengthKind === 2 && isVertical
PropertyChanges{
target: root
Layout.minimumHeight: Math.min(cfg.fixedLength, titleLayout.implicitHeight)
Layout.maximumHeight: Math.min(cfg.fixedLength, titleLayout.implicitHeight)
Layout.fillWidth: true
}
},
State{
name: "minimumLengthVert"
when: cfg.lengthKind === 3 && isVertical
PropertyChanges{
target: root
Layout.minimumHeight: Math.max(cfg.minLength, titleLayout.implicitHeight)
Layout.maximumHeight: Math.max(cfg.minLength, titleLayout.implicitHeight)
Layout.fillWidth: true
}
},
State{
name: "minMaxLengthVert"
when: cfg.lengthKind === 4 && isVertical
PropertyChanges{
target: root
Layout.minimumHeight: Math.max(cfg.minLength, Math.min(cfg.fixedLength, titleLayout.implicitHeight))
Layout.maximumHeight: Math.max(cfg.minLength, Math.min(cfg.fixedLength, titleLayout.implicitHeight))
Layout.fillWidth: true
}
}
]
TaskManager.ActivityInfo { id: activityInfo }
Activities.ActivityInfo { id: fullActivityInfo; activityId: ":current" }
TaskManager.VirtualDesktopInfo { id: virtualDesktopInfo }
Loader {
id: windowInfoLoader
sourceComponent: plasmaTasksModel
Component{
id: plasmaTasksModel
PlasmaTasksModel{}
}
}
Title { id: titleLayout }
ActionsMouseArea{}
PlasmaCore.ToolTipArea {
anchors.fill: parent
active: text !== ""
interactive: true
location: plasmoid.location
visible: cfg.showTooltip
mainItem: RowLayout {
spacing: Kirigami.Units.largeSpacing
Layout.margins: Kirigami.Units.smallSpacing
Kirigami.Icon {
source: root.icon
}
PlasmaComponents.Label {
id: fullText
elide:Text.ElideRight
Layout.fillWidth: true
Layout.fillHeight: true
verticalAlignment: Text.AlignVCenter
text:root.text
}
}
}
}