419 lines
16 KiB
QML
419 lines
16 KiB
QML
/*
|
|
* SPDX-FileCopyrightText: 2024 Anton Kharuzhy <publicantroids@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
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 org.kde.plasma.extras as PlasmaExtras
|
|
import org.kde.plasma.plasmoid
|
|
import org.kde.taskmanager as TaskManager
|
|
import "utils.js" as Utils
|
|
import "config/effect/"
|
|
import "config/effect/effect.js" as EffectUtils
|
|
|
|
PlasmoidItem {
|
|
id: root
|
|
|
|
property TaskManager.TasksModel tasksModel
|
|
property real widgetHeight: (vertical ? width : height)
|
|
property real elementHeight: widgetHeight - plasmoid.configuration.widgetMargins * 2
|
|
property real buttonMargins: plasmoid.configuration.widgetButtonsMargins
|
|
property real buttonHeight: elementHeight
|
|
property real buttonWidth: (plasmoid.configuration.widgetButtonsAspectRatio) / 100 * (buttonHeight - buttonMargins * 2)
|
|
property var widgetAlignment: plasmoid.configuration.widgetHorizontalAlignment | plasmoid.configuration.widgetVerticalAlignment
|
|
property KWinConfig kWinConfig
|
|
property bool widgetHovered: widgetHoverHandler.hovered
|
|
property bool vertical: plasmoid.formFactor === PlasmaCore.Types.Vertical
|
|
property bool leftEdgeLocation: plasmoid.location === PlasmaCore.Types.LeftEdge
|
|
property bool hideWidget: !tasksModel.hasActiveWindow && plasmoid.configuration.widgetElementsDisabledMode === WidgetElement.DisabledMode.Hide
|
|
property bool editMode: Plasmoid.containment.corona?.editMode ?? false
|
|
|
|
signal invokeKWinShortcut(string shortcut)
|
|
signal widgetElementsLayoutUpdated
|
|
|
|
Plasmoid.constraintHints: Plasmoid.CanFillArea
|
|
Plasmoid.status: hideWidget ? PlasmaCore.Types.HiddenStatus : PlasmaCore.Types.ActiveStatus
|
|
Layout.fillWidth: !vertical && plasmoid.configuration.widgetFillWidth
|
|
Layout.fillHeight: vertical && plasmoid.configuration.widgetFillWidth
|
|
preferredRepresentation: fullRepresentation
|
|
onInvokeKWinShortcut: function (shortcut) {
|
|
if (tasksModel.hasActiveWindow)
|
|
tasksModel.activeWindow.actionCall(ActiveWindow.Action.Activate);
|
|
|
|
kWinConfig.invokeKWinShortcut(shortcut);
|
|
}
|
|
|
|
ContextualActions {}
|
|
|
|
Component {
|
|
id: widgetElementLoaderDelegate
|
|
|
|
Loader {
|
|
id: widgetElementLoader
|
|
|
|
required property int index
|
|
required property var modelData
|
|
property bool repeaterVisible: false
|
|
|
|
onLoaded: function () {
|
|
Utils.copyLayoutConstraint(item, widgetElementLoader);
|
|
widgetElementLoader.Layout.preferredWidthChanged.connect(root.widgetElementsLayoutUpdated);
|
|
item.modelData = modelData;
|
|
}
|
|
sourceComponent: {
|
|
switch (modelData.type) {
|
|
case WidgetElement.Type.WindowControlButton:
|
|
return windowControlButton;
|
|
case WidgetElement.Type.WindowTitle:
|
|
return windowTitle;
|
|
case WidgetElement.Type.WindowIcon:
|
|
return windowIcon;
|
|
case WidgetElement.Type.Spacer:
|
|
return spacerIcon;
|
|
}
|
|
}
|
|
|
|
Binding {
|
|
when: status === Loader.Ready
|
|
widgetElementLoader.visible: repeaterVisible && (plasmoid.configuration.widgetElementsDisabledMode === WidgetElement.DisabledMode.Hide ? item.enabled : true)
|
|
}
|
|
|
|
Binding {
|
|
function itemVisible(itemEnabled) {
|
|
switch (plasmoid.configuration.widgetElementsDisabledMode) {
|
|
case WidgetElement.DisabledMode.Hide:
|
|
return itemEnabled;
|
|
case WidgetElement.DisabledMode.HideKeepSpace:
|
|
return itemEnabled;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
when: status === Loader.Ready
|
|
target: item
|
|
property: "visible"
|
|
value: itemVisible(item.enabled)
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: windowControlButton
|
|
|
|
WindowControlButton {
|
|
id: windowControlButton
|
|
|
|
property var modelData
|
|
Layout.alignment: root.widgetAlignment
|
|
Layout.preferredWidth: root.buttonWidth
|
|
Layout.preferredHeight: root.buttonHeight
|
|
verticalPadding: root.buttonMargins
|
|
buttonType: modelData.windowControlButtonType
|
|
themeName: plasmoid.configuration.widgetButtonsAuroraeTheme
|
|
iconTheme: plasmoid.configuration.widgetButtonsIconsTheme
|
|
animationDuration: plasmoid.configuration.widgetButtonsAnimation
|
|
onActionCall: action => {
|
|
return tasksModel.activeWindow.actionCall(action);
|
|
}
|
|
enabled: tasksModel.hasActiveWindow && tasksModel.activeWindow.actionSupported(action) && (!plasmoid.configuration.disableButtonsForNotHoveredWidget || root.widgetHovered)
|
|
checked: tasksModel.hasActiveWindow && tasksModel.activeWindow.buttonChecked(modelData.windowControlButtonType)
|
|
active: tasksModel.hasActiveWindow && tasksModel.activeWindow.active
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: windowIcon
|
|
|
|
Kirigami.Icon {
|
|
property var modelData
|
|
|
|
height: root.elementHeight
|
|
width: height
|
|
Layout.alignment: root.widgetAlignment
|
|
Layout.preferredWidth: width
|
|
source: tasksModel.activeWindow.icon || "window"
|
|
enabled: tasksModel.hasActiveWindow && !!tasksModel.activeWindow.icon
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: spacerIcon
|
|
|
|
Rectangle {
|
|
property var modelData
|
|
|
|
height: root.elementHeight
|
|
width: height / 3
|
|
Layout.alignment: root.widgetAlignment
|
|
Layout.preferredWidth: width
|
|
color: "transparent"
|
|
enabled: tasksModel.hasActiveWindow
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: windowTitle
|
|
|
|
PlasmaComponents.Label {
|
|
id: windowTitleLabel
|
|
|
|
readonly property var horizontalAlignmentValues: [Text.AlignLeft, Text.AlignRight, Text.AlignHCenter, Text.AlignJustify]
|
|
readonly property var verticalAlignmentValues: [Text.AlignTop, Text.AlignBottom, Text.AlignVCenter]
|
|
|
|
property var modelData
|
|
property bool empty: text === undefined || text === ""
|
|
property bool hideEmpty: empty && plasmoid.configuration.windowTitleHideEmpty
|
|
property int windowTitleSource: plasmoid.configuration.overrideElementsMaximized && tasksModel.activeWindow.maximized ? plasmoid.configuration.windowTitleSourceMaximized : plasmoid.configuration.windowTitleSource
|
|
property var titleTextReplacements: []
|
|
|
|
Layout.minimumWidth: plasmoid.configuration.windowTitleMinimumWidth
|
|
Layout.maximumWidth: !hideEmpty ? plasmoid.configuration.windowTitleMaximumWidth : 0
|
|
Layout.alignment: root.widgetAlignment
|
|
Layout.fillWidth: plasmoid.configuration.widgetFillWidth
|
|
Layout.fillHeight: true
|
|
Layout.preferredWidth: textMetrics.advanceWidth + leftPadding + rightPadding + 1 // Magic number
|
|
text: titleText(windowTitleSource) || plasmoid.configuration.windowTitleUndefined
|
|
font.pointSize: plasmoid.configuration.windowTitleFontSize
|
|
font.bold: plasmoid.configuration.windowTitleFontBold
|
|
fontSizeMode: plasmoid.configuration.windowTitleFontSizeMode
|
|
maximumLineCount: 1
|
|
elide: Text.ElideRight
|
|
wrapMode: Text.WrapAnywhere
|
|
enabled: tasksModel.hasActiveWindow
|
|
horizontalAlignment: horizontalAlignmentValues[plasmoid.configuration.windowTitleHorizontalAlignment]
|
|
verticalAlignment: verticalAlignmentValues[plasmoid.configuration.windowTitleVerticalAlignment]
|
|
|
|
bottomPadding: !hideEmpty ? plasmoid.configuration.windowTitleMarginsBottom : 0
|
|
leftPadding: !hideEmpty ? plasmoid.configuration.windowTitleMarginsLeft : 0
|
|
rightPadding: !hideEmpty ? plasmoid.configuration.windowTitleMarginsRight : 0
|
|
topPadding: !hideEmpty ? plasmoid.configuration.windowTitleMarginsTop : 0
|
|
|
|
Accessible.role: Accessible.TitleBar
|
|
Accessible.name: text
|
|
|
|
TextMetrics {
|
|
id: textMetrics
|
|
font: windowTitleLabel.font
|
|
text: windowTitleLabel.text
|
|
}
|
|
|
|
Connections {
|
|
target: plasmoid.configuration
|
|
|
|
function onTitleReplacementsTypesChanged() {
|
|
updateTitleTextReplacements();
|
|
}
|
|
|
|
function onTitleReplacementsPatternsChanged() {
|
|
updateTitleTextReplacements();
|
|
}
|
|
|
|
function onTitleReplacementsTemplatesChanged() {
|
|
updateTitleTextReplacements();
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: updateTitleTextReplacements()
|
|
|
|
function titleText(windowTitleSource) {
|
|
let titleTextResult = "";
|
|
switch (windowTitleSource) {
|
|
case 0:
|
|
titleTextResult = tasksModel.activeWindow.appName;
|
|
break;
|
|
case 1:
|
|
titleTextResult = tasksModel.activeWindow.decoration;
|
|
break;
|
|
case 2:
|
|
titleTextResult = tasksModel.activeWindow.genericAppName;
|
|
break;
|
|
case 3:
|
|
titleTextResult = plasmoid.configuration.windowTitleUndefined;
|
|
break;
|
|
}
|
|
if (titleTextResult) {
|
|
titleTextResult = Utils.Replacement.applyReplacementList(titleTextResult, titleTextReplacements);
|
|
}
|
|
return titleTextResult;
|
|
}
|
|
|
|
function updateTitleTextReplacements() {
|
|
Qt.callLater(_updateTitleTextReplacements);
|
|
}
|
|
|
|
function _updateTitleTextReplacements() {
|
|
titleTextReplacements = Utils.Replacement.createReplacementList(plasmoid.configuration.titleReplacementsTypes, plasmoid.configuration.titleReplacementsPatterns, plasmoid.configuration.titleReplacementsTemplates);
|
|
}
|
|
}
|
|
}
|
|
|
|
kWinConfig: KWinConfig {
|
|
Component.onCompleted: updateKWinShortcutNames()
|
|
}
|
|
|
|
tasksModel: ActiveTasksModel {
|
|
id: tasksModel
|
|
}
|
|
|
|
HoverHandler {
|
|
id: widgetHoverHandler
|
|
enabled: plasmoid.configuration.disableButtonsForNotHoveredWidget
|
|
}
|
|
|
|
fullRepresentation: Item {
|
|
id: representationProxy
|
|
|
|
Layout.fillWidth: root.vertical ? null : plasmoid.configuration.widgetFillWidth
|
|
Layout.fillHeight: root.vertical ? plasmoid.configuration.widgetFillWidth : null
|
|
|
|
Layout.minimumWidth: root.vertical ? widgetRow.Layout.minimumHeight : widgetRow.Layout.minimumWidth
|
|
Layout.minimumHeight: root.vertical ? widgetRow.Layout.minimumWidth : widgetRow.Layout.minimumHeight
|
|
|
|
Layout.maximumWidth: root.vertical ? widgetRow.Layout.maximumHeight : widgetRow.Layout.maximumWidth
|
|
Layout.maximumHeight: root.vertical ? widgetRow.Layout.maximumWidth : widgetRow.Layout.maximumHeight
|
|
|
|
Layout.preferredWidth: root.vertical ? widgetRow.Layout.preferredHeight : widgetRow.Layout.preferredWidth
|
|
Layout.preferredHeight: root.vertical ? widgetRow.Layout.preferredWidth : widgetRow.Layout.preferredHeight
|
|
|
|
MouseHandlers {
|
|
Component.onCompleted: {
|
|
invokeKWinShortcut.connect(root.invokeKWinShortcut);
|
|
}
|
|
}
|
|
|
|
WidgetToolTip {
|
|
anchors.fill: parent
|
|
tasksModel: root.tasksModel
|
|
}
|
|
|
|
RowLayout {
|
|
id: widgetRow
|
|
|
|
spacing: plasmoid.configuration.widgetSpacing
|
|
anchors.left: parent.left
|
|
anchors.verticalCenter: root.vertical ? undefined : parent.verticalCenter
|
|
anchors.horizontalCenter: root.vertical ? parent.horizontalCenter : undefined
|
|
width: root.vertical ? representationProxy.height : representationProxy.width
|
|
height: root.vertical ? representationProxy.width : representationProxy.height
|
|
|
|
Accessible.role: Accessible.Grouping
|
|
Accessible.name: i18n("Application title bar")
|
|
|
|
transform: [
|
|
Rotation {
|
|
angle: root.vertical ? 90 : 0
|
|
origin.x: widgetHeight / 2 - plasmoid.configuration.widgetMargins / 2 // IDK why
|
|
origin.y: widgetHeight / 2 - plasmoid.configuration.widgetMargins / 2
|
|
},
|
|
Rotation {
|
|
angle: root.leftEdgeLocation ? 180 : 0
|
|
origin.x: width / 2
|
|
origin.y: height / 2
|
|
}
|
|
]
|
|
|
|
PlasmaComponents.Label {
|
|
id: editModePlaceholder
|
|
text: Plasmoid.metaData.name
|
|
visible: editMode
|
|
}
|
|
|
|
Repeater {
|
|
id: widgetElementsRepeater
|
|
property var elements: plasmoid.configuration.widgetElements
|
|
|
|
onElementsChanged: function () {
|
|
let array = [];
|
|
for (var i = 0; i < elements.length; i++) {
|
|
array.push(Utils.widgetElementModelFromName(elements[i]));
|
|
}
|
|
model = array;
|
|
}
|
|
model: []
|
|
delegate: widgetElementLoaderDelegate
|
|
visible: !plasmoid.configuration.overrideElementsMaximized || !tasksModel.activeWindow.maximized
|
|
onItemAdded: function (index, item) {
|
|
item.repeaterVisible = Qt.binding(function () {
|
|
return visible;
|
|
});
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
id: widgetElementsMaximizedRepeater
|
|
property var elements: plasmoid.configuration.overrideElementsMaximized ? plasmoid.configuration.widgetElementsMaximized : []
|
|
|
|
onElementsChanged: function () {
|
|
let array = [];
|
|
for (var i = 0; i < elements.length; i++) {
|
|
array.push(Utils.widgetElementModelFromName(elements[i]));
|
|
}
|
|
model = array;
|
|
}
|
|
model: []
|
|
delegate: widgetElementLoaderDelegate
|
|
visible: !widgetElementsRepeater.visible
|
|
onItemAdded: function (index, item) {
|
|
item.repeaterVisible = Qt.binding(function () {
|
|
return visible;
|
|
});
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: root
|
|
|
|
function onWidgetElementsLayoutUpdated() {
|
|
var preferredWidth = plasmoid.configuration.widgetFillWidth ? widgetRow.calculatePreferredWidth() : -1;
|
|
widgetRow.Layout.preferredWidth = preferredWidth;
|
|
}
|
|
}
|
|
|
|
function calculatePreferredWidth() {
|
|
var repeater = widgetElementsRepeater.visible ? widgetElementsRepeater : widgetElementsMaximizedRepeater;
|
|
var preferredWidth = (repeater.count - 1) * widgetRow.spacing;
|
|
for (var i = 0; i < repeater.count; i++) {
|
|
var item = repeater.itemAt(i);
|
|
preferredWidth += Utils.calculateItemPreferredWidth(item);
|
|
}
|
|
if (preferredWidth < widgetRow.Layout.minimumWidth) {
|
|
return widgetRow.Layout.minimumWidth;
|
|
} else if (preferredWidth > widgetRow.Layout.maximumWidth) {
|
|
return widgetRow.Layout.maximumWidth;
|
|
} else {
|
|
return preferredWidth;
|
|
}
|
|
}
|
|
}
|
|
|
|
WidgetEffectsRepeater {
|
|
id: effectsRepeater
|
|
}
|
|
|
|
Component.onCompleted: effectsRepeater.updateEffectRules()
|
|
|
|
Connections {
|
|
target: root.tasksModel
|
|
function onActiveWindowUpdated() {
|
|
effectsRepeater.updateEffectsState();
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: plasmoid.configuration
|
|
function onEffectRulesChanged() {
|
|
effectsRepeater.updateEffectRules();
|
|
}
|
|
function onEffectsChanged() {
|
|
effectsRepeater.updateEffectRules();
|
|
}
|
|
}
|
|
}
|
|
}
|