mirror of
https://gitgud.io/wackyideas/aerothemeplasma.git
synced 2026-06-19 03:45:50 +00:00
1682 lines
63 KiB
QML
1682 lines
63 KiB
QML
/*
|
|
SPDX-FileCopyrightText: 2012-2013 Eike Hein <hein@kde.org>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
import QtQuick 2.15
|
|
import QtQuick.Layouts
|
|
|
|
import org.kde.plasma.core as PlasmaCore
|
|
import org.kde.ksvg 1.0 as KSvg
|
|
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
|
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
|
import org.kde.kirigami 2.20 as Kirigami
|
|
import aeroshell.taskmanager as TaskManagerApplet
|
|
import org.kde.plasma.plasmoid 2.0
|
|
import Qt5Compat.GraphicalEffects
|
|
|
|
import "code/layoutmetrics.js" as LayoutMetrics
|
|
import "code/tools.js" as TaskTools
|
|
|
|
PlasmaCore.ToolTipArea {
|
|
id: task
|
|
|
|
// BEGIN TOOLTIP CODE
|
|
property real attentionAnimOpacity: attentionFrame.opacity > 0 ? 1 : attentionGlow.opacity
|
|
property Item taskThumbnail: tasksRoot.taskThumbnail
|
|
|
|
active: !jumpListOpen
|
|
mainItem: showPreviews ? taskThumbnail : null
|
|
mainText: showPreviews ? "" : model.display
|
|
location: Plasmoid.location
|
|
backgroundHints: showPreviews ? "StandardBackground" : "SolidBackground"
|
|
interactive: showPreviews
|
|
windowTitle: showPreviews ? "aeroshell-thumbnail" : ""
|
|
|
|
onContainsMouseChanged: (containsMouse) => {
|
|
if(tasksRoot.toolTipOpen && !showPreviews) {
|
|
task.hideImmediately();
|
|
tasksRoot.toolTipOpen = false;
|
|
}
|
|
if(tasksRoot.pinnedToolTipOpen && showPreviews) {
|
|
task.hideImmediately();
|
|
tasksRoot.pinnedToolTipOpen = false;
|
|
}
|
|
}
|
|
onToolTipVisibleChanged: (toolTipVisible) => {
|
|
if(!toolTipVisible) {
|
|
tasksRoot.toolTipOpen = false;
|
|
tasksRoot.pinnedToolTipOpen = false;
|
|
}
|
|
}
|
|
onAboutToShow: {
|
|
updateToolTipBindings();
|
|
if(showPreviews) tasksRoot.toolTipOpen = true;
|
|
if(!showPreviews) tasksRoot.pinnedToolTipOpen = true;
|
|
}
|
|
|
|
function updateToolTipBindings() {
|
|
taskThumbnail.parentTask = Qt.binding(() => task);
|
|
|
|
taskThumbnail.demandsAttention = Qt.binding(() => model.IsDemandingAttention);
|
|
taskThumbnail.minimized = Qt.binding(() => model.IsMinimized);
|
|
taskThumbnail.display = Qt.binding(() => model.display);
|
|
taskThumbnail.icon = Qt.binding(() => model.decoration);
|
|
taskThumbnail.active = Qt.binding(() => model.IsActive);
|
|
taskThumbnail.startup = Qt.binding(() => model.IsStartup)
|
|
taskThumbnail.windows = Qt.binding(() => model.WinIdList);
|
|
taskThumbnail.modelIndex = Qt.binding(() => task.modelIndex());
|
|
taskThumbnail.taskIndex = Qt.binding(() => model.index);
|
|
taskThumbnail.pidParent = Qt.binding(() => model.AppPid);
|
|
taskThumbnail.launcherUrl = Qt.binding(() => model.LauncherUrlWithoutIcon);
|
|
taskThumbnail.isGroupParent = Qt.binding(() => model.IsGroupParent);
|
|
taskThumbnail.taskHovered = Qt.binding(() => dragArea.containsMouse);
|
|
}
|
|
// END TOOLTIP CODE
|
|
|
|
activeFocusOnTab: true
|
|
|
|
// To achieve a bottom to top layout, the task manager is rotated by 180 degrees(see main.qml).
|
|
// This makes the tasks mirrored, so we mirror them again to fix that.
|
|
rotation: Plasmoid.configuration.reverseMode && Plasmoid.formFactor === PlasmaCore.Types.Vertical ? 180 : 0
|
|
|
|
implicitHeight: LayoutMetrics.preferredTaskHeight();
|
|
implicitWidth: {
|
|
if(tasksRoot.vertical) {
|
|
return tasksRoot.width;
|
|
} else {
|
|
if(tasksRoot.iconsOnly || model.IsLauncher || model.IsStartup) {
|
|
return LayoutMetrics.preferredMinLauncherWidth();
|
|
} else {
|
|
var minWidth = LayoutMetrics.preferredMinWidth();
|
|
var maxWidth = LayoutMetrics.preferredMaxWidth();
|
|
|
|
|
|
var taskCount = taskList.contentItem.visibleChildren.length;
|
|
if(taskCount <= 1) taskCount = taskList.count
|
|
if(taskCount < 0) taskCount = 0;
|
|
var launcherCount = tasksModel.logicalLauncherCount;
|
|
if(launcherCount === 0) launcherCount = 1;
|
|
var currentWidth = Math.floor((taskList.width - (LayoutMetrics.preferredMinLauncherWidth()+16) * (launcherCount)) / (taskList.count - tasksModel.logicalLauncherCount));
|
|
return Math.min(maxWidth, Math.max(minWidth, currentWidth));
|
|
}
|
|
}
|
|
}
|
|
Behavior on implicitWidth {
|
|
NumberAnimation { duration: 200; easing.type: Easing.OutQuad }
|
|
}
|
|
Behavior on implicitHeight {
|
|
NumberAnimation { duration: 200; easing.type: Easing.OutQuad }
|
|
}
|
|
|
|
SequentialAnimation {
|
|
id: addLabelsAnimation
|
|
NumberAnimation { target: task; properties: "opacity"; to: 1; duration: 200; easing.type: Easing.OutQuad }
|
|
PropertyAction { target: task; property: "visible"; value: true }
|
|
PropertyAction { target: task; property: "state"; value: "" }
|
|
}
|
|
SequentialAnimation {
|
|
id: removeLabelsAnimation
|
|
NumberAnimation { target: task; properties: "width"; to: 0; duration: 200; easing.type: Easing.OutQuad }
|
|
PropertyAction { target: task; property: "ListView.delayRemove"; value: false }
|
|
}
|
|
SequentialAnimation {
|
|
id: removeIconsAnimation
|
|
NumberAnimation { target: task; properties: "opacity"; to: 0; duration: 200; easing.type: Easing.OutQuad }
|
|
PropertyAction { target: task; property: "ListView.delayRemove"; value: false }
|
|
}
|
|
|
|
required property var model
|
|
required property int index
|
|
required property Item tasksRoot
|
|
|
|
readonly property int pid: model.AppPid
|
|
readonly property string appName: model.AppName
|
|
readonly property string appId: model.AppId.replace(/\.desktop/, '')
|
|
readonly property bool isIcon: tasksRoot.iconsOnly || model.IsLauncher
|
|
property bool isLauncher: model.IsLauncher
|
|
property bool isWindow: model.IsWindow
|
|
property int childCount: model.ChildCount
|
|
property int previousChildCount: 0
|
|
property alias labelText: label.text
|
|
property alias mouseArea: dragArea
|
|
property QtObject contextMenu: null
|
|
property QtObject jumpList: null // Pointer to the reimplemented context menu.
|
|
property bool jumpListOpen: jumpList !== null
|
|
property bool wasActive: false
|
|
|
|
property bool showPreviews: Plasmoid.configuration.showPreviews && !model.IsLauncher && model.IsWindow
|
|
|
|
onJumpListOpenChanged: {
|
|
if(jumpList !== null) {
|
|
Qt.callLater(() => { Plasmoid.setMouseGrab(true, jumpList); } );
|
|
} else {
|
|
task.wasActive = false;
|
|
}
|
|
if(jumpListOpen) {
|
|
task.hideImmediately();
|
|
tasksRoot.toolTipOpen = false;
|
|
tasksRoot.pinnedToolTipOpen = false;
|
|
}
|
|
}
|
|
readonly property bool smartLauncherEnabled: !model.IsStartup
|
|
property QtObject smartLauncherItem: null
|
|
property Item audioStreamIcon: null
|
|
property var audioStreams: []
|
|
property int audioStreamUsers: 0
|
|
property bool delayAudioStreamIndicator: false
|
|
property bool completed: false
|
|
readonly property bool hasAudioStream: audioStreams.length > 0
|
|
readonly property bool playing: hasAudioStream && audioStreams.some(function (item) {
|
|
return !item.corked
|
|
})
|
|
readonly property bool muted: hasAudioStream && audioStreams.every(function (item) {
|
|
return item.muted
|
|
})
|
|
|
|
readonly property bool highlighted: dragArea.containsMouse
|
|
|| (task.contextMenu && task.contextMenu.status === PlasmaExtras.Menu.Open)
|
|
|| (task.jumpList)
|
|
//|| tasksRoot.toolTipOpen && taskThumbnail?.taskIndex == model.index
|
|
|
|
readonly property bool animateLabel: (!model.IsStartup && !model.IsLauncher) && !tasksRoot.iconsOnly
|
|
readonly property bool shouldHideOnRemoval: model.IsStartup || model.IsLauncher
|
|
ListView.onRemove: {
|
|
if (tasksRoot.containsMouse && index != tasksModel.count &&
|
|
task.model.WinIdList.length > 0 &&
|
|
taskClosedWithMouseMiddleButton.indexOf(item.winIdList[0]) > -1) {
|
|
tasksRoot.needLayoutRefresh = true;
|
|
}
|
|
taskClosedWithMouseMiddleButton = [];
|
|
if(shouldHideOnRemoval) {
|
|
taskList.add = null;
|
|
taskList.resetAddTransition.start();
|
|
}
|
|
if(animateLabel) { // Closing animation for tasks with labels
|
|
taskList.displaced = null;
|
|
ListView.delayRemove = true;
|
|
taskList.resetTransition.start();
|
|
removeLabelsAnimation.start();
|
|
}
|
|
}
|
|
ListView.onAdd: {
|
|
if(model.IsStartup && !taskInLauncherList(appId)) {
|
|
task.implicitWidth = 0;
|
|
task.visible = false;
|
|
}
|
|
if(shouldHideOnRemoval) {
|
|
taskList.add = null;
|
|
taskList.resetAddTransition.start();
|
|
}
|
|
if(animateLabel) {
|
|
task.visible = false;
|
|
task.state = "animateLabels";
|
|
addLabelsAnimation.start();
|
|
}
|
|
layoutDelay.start()
|
|
}
|
|
states: [
|
|
State {
|
|
name: "animateLabels"
|
|
PropertyChanges { target: task; implicitWidth: 0 }
|
|
}
|
|
]
|
|
|
|
property alias leftTapHandler: leftTapHandler
|
|
|
|
Accessible.name: model.display
|
|
Accessible.description: {
|
|
if (!model.display) {
|
|
return "";
|
|
}
|
|
|
|
if (model.IsLauncher) {
|
|
return i18nc("@info:usagetip %1 application name", "Launch %1", model.display)
|
|
}
|
|
|
|
let smartLauncherDescription = "";
|
|
|
|
if (model.IsGroupParent) {
|
|
switch (Plasmoid.configuration.groupedTaskVisualization) {
|
|
case 0:
|
|
break; // Use the default description
|
|
case 1: {
|
|
if (Plasmoid.configuration.showToolTips) {
|
|
return `${i18nc("@info:usagetip %1 task name", "Show Task tooltip for %1", model.display)}; ${smartLauncherDescription}`;
|
|
}
|
|
// fallthrough
|
|
}
|
|
case 2: {
|
|
if (effectWatcher.registered) {
|
|
return `${i18nc("@info:usagetip %1 task name", "Show windows side by side for %1", model.display)}; ${smartLauncherDescription}`;
|
|
}
|
|
// fallthrough
|
|
}
|
|
default:
|
|
return `${i18nc("@info:usagetip %1 task name", "Open textual list of windows for %1", model.display)}; ${smartLauncherDescription}`;
|
|
}
|
|
}
|
|
|
|
return `${i18n("Activate %1", model.display)}; ${smartLauncherDescription}`;
|
|
}
|
|
Accessible.role: Accessible.Button
|
|
Accessible.onPressAction: leftTapHandler.leftClick()
|
|
|
|
onHighlightedChanged: {
|
|
// ensure it doesn't get stuck with a window highlighted
|
|
tasksRoot.cancelHighlightWindows();
|
|
}
|
|
|
|
onPidChanged: updateAudioStreams({delay: false})
|
|
onAppNameChanged: updateAudioStreams({delay: false})
|
|
|
|
onIsWindowChanged: {
|
|
if (model.IsWindow) {
|
|
taskInitComponent.createObject(task);
|
|
updateAudioStreams({delay: false});
|
|
}
|
|
}
|
|
|
|
onChildCountChanged: {
|
|
if (TaskTools.taskManagerInstanceCount < 2 && childCount > previousChildCount) {
|
|
tasksModel.requestPublishDelegateGeometry(modelIndex(), backend.globalRect(task), task);
|
|
}
|
|
|
|
previousChildCount = childCount;
|
|
containerRect.loadingNewInstance = false;
|
|
}
|
|
|
|
onIndexChanged: {
|
|
if (!tasksRoot.vertical
|
|
&& !Plasmoid.configuration.separateLaunchers) {
|
|
tasksRoot.requestLayout();
|
|
}
|
|
}
|
|
|
|
onSmartLauncherEnabledChanged: {
|
|
if (smartLauncherEnabled && !smartLauncherItem) {
|
|
const smartLauncher = Qt.createQmlObject(`
|
|
import aeroshell.taskmanager as TaskManagerApplet
|
|
|
|
TaskManagerApplet.SmartLauncherItem { }
|
|
`, task);
|
|
|
|
smartLauncher.launcherUrl = Qt.binding(() => model.LauncherUrlWithoutIcon);
|
|
|
|
smartLauncherItem = smartLauncher;
|
|
}
|
|
}
|
|
|
|
Keys.onMenuPressed: contextMenuTimer.start()
|
|
Keys.onReturnPressed: TaskTools.activateTask(modelIndex(), model, event.modifiers, task, Plasmoid, tasksRoot, effectWatcher.registered)
|
|
Keys.onEnterPressed: Keys.returnPressed(event);
|
|
Keys.onSpacePressed: Keys.returnPressed(event);
|
|
Keys.onUpPressed: Keys.leftPressed(event)
|
|
Keys.onDownPressed: Keys.rightPressed(event)
|
|
Keys.onLeftPressed: if ((event.modifiers & Qt.ControlModifier) && (event.modifiers & Qt.ShiftModifier)) {
|
|
tasksModel.move(task.index, task.index - 1);
|
|
} else {
|
|
event.accepted = false;
|
|
}
|
|
Keys.onRightPressed: if ((event.modifiers & Qt.ControlModifier) && (event.modifiers & Qt.ShiftModifier)) {
|
|
tasksModel.move(task.index, task.index + 1);
|
|
} else {
|
|
event.accepted = false;
|
|
}
|
|
|
|
function modelIndex() {
|
|
return tasksModel.makeModelIndex(index);
|
|
}
|
|
|
|
function showControlMenu(args) {
|
|
moreMenu.openRelative();
|
|
}
|
|
function showContextMenu(args) {
|
|
if(task.toolTipVisible) task.hideImmediately();
|
|
if(Plasmoid.configuration.disableJumplists) {
|
|
contextMenuTimer.showNormalMenu = true;
|
|
contextMenuTimer.start();
|
|
} else {
|
|
if(model.IsActive) task.wasActive = true;
|
|
var mIndex = modelIndex();
|
|
jumpList = tasksRoot.createJumpList(task, mIndex, args);
|
|
jumpList.menuDecoration = model.decoration;
|
|
jumpListDebouncer.start();
|
|
Qt.callLater(() => { jumpList.show(); tasksRoot.jumpListItem = jumpList; });
|
|
}
|
|
}
|
|
|
|
function showFallbackContextMenu(args) {
|
|
contextMenu = tasksRoot.createContextMenu(task, modelIndex(), args);
|
|
contextMenu.show();
|
|
}
|
|
property PlasmaExtras.Menu moreMenu: PlasmaExtras.Menu {
|
|
id: moreActionsMenu
|
|
visualParent: task
|
|
|
|
placement: {
|
|
if (Plasmoid.location === PlasmaCore.Types.LeftEdge) {
|
|
return PlasmaExtras.Menu.RightPosedTopAlignedPopup;
|
|
} else if (Plasmoid.location === PlasmaCore.Types.TopEdge) {
|
|
return PlasmaExtras.Menu.BottomPosedLeftAlignedPopup;
|
|
} else if (Plasmoid.location === PlasmaCore.Types.RightEdge) {
|
|
return PlasmaExtras.Menu.LeftPosedTopAlignedPopup;
|
|
} else {
|
|
return PlasmaExtras.Menu.TopPosedLeftAlignedPopup;
|
|
}
|
|
}
|
|
PlasmaExtras.MenuItem {
|
|
enabled: model.IsMovable //tasksMenu.get(atm.IsMovable)
|
|
|
|
text: i18n("&Move")
|
|
icon: "transform-move"
|
|
|
|
onClicked: tasksModel.requestMove(modelIndex())
|
|
}
|
|
|
|
PlasmaExtras.MenuItem {
|
|
enabled: model.IsResizable
|
|
|
|
text: i18n("Re&size")
|
|
icon: "transform-scale"
|
|
|
|
onClicked: tasksModel.requestResize(modelIndex())
|
|
}
|
|
|
|
PlasmaExtras.MenuItem {
|
|
visible: !model.IsLauncher && !model.IsStartup
|
|
|
|
enabled: model.IsMaximizable
|
|
|
|
checkable: true
|
|
checked: model.IsMaximized
|
|
|
|
text: i18n("Ma&ximize")
|
|
icon: "window-maximize"
|
|
|
|
onClicked: tasksModel.requestToggleMaximized(modelIndex())
|
|
}
|
|
|
|
PlasmaExtras.MenuItem {
|
|
visible: (!model.IsLauncher && !model.IsStartup)
|
|
|
|
enabled: model.IsMinimizable
|
|
|
|
checkable: true
|
|
checked: model.IsMinimized
|
|
|
|
text: i18n("Mi&nimize")
|
|
icon: "window-minimize"
|
|
|
|
onClicked: tasksModel.requestToggleMinimized(modelIndex())
|
|
}
|
|
|
|
PlasmaExtras.MenuItem {
|
|
checkable: true
|
|
checked: model.IsKeepAbove
|
|
|
|
text: i18n("Keep &Above Others")
|
|
icon: "window-keep-above"
|
|
|
|
onClicked: tasksModel.requestToggleKeepAbove(modelIndex())
|
|
}
|
|
|
|
PlasmaExtras.MenuItem {
|
|
checkable: true
|
|
checked: model.IsKeepBelow
|
|
|
|
text: i18n("Keep &Below Others")
|
|
icon: "window-keep-below"
|
|
|
|
onClicked: tasksModel.requestToggleKeepBelow(modelIndex())
|
|
}
|
|
|
|
PlasmaExtras.MenuItem {
|
|
enabled: model.IsFullScreenable
|
|
|
|
checkable: true
|
|
checked: model.IsFullScreen
|
|
|
|
text: i18n("&Fullscreen")
|
|
icon: "view-fullscreen"
|
|
|
|
onClicked: tasksModel.requestToggleFullScreen(modelIndex())
|
|
}
|
|
|
|
PlasmaExtras.MenuItem {
|
|
enabled: model.IsShadeable
|
|
visible: Qt.platform.pluginName !== "wayland"
|
|
|
|
checkable: true
|
|
checked: model.IsShaded
|
|
|
|
text: i18n("&Shade")
|
|
icon: "window-shade"
|
|
|
|
onClicked: tasksModel.requestToggleShaded(modelIndex())
|
|
}
|
|
|
|
PlasmaExtras.MenuItem {
|
|
separator: true
|
|
}
|
|
|
|
PlasmaExtras.MenuItem {
|
|
visible: (Plasmoid.configuration.groupingStrategy !== 0) && model.IsWindow
|
|
|
|
checkable: true
|
|
checked: model.IsGroupable
|
|
|
|
text: i18n("Allow this program to be grouped")
|
|
icon: "view-group"
|
|
|
|
onClicked: tasksModel.requestToggleGrouping(modelIndex())
|
|
}
|
|
PlasmaExtras.MenuItem {
|
|
id: closeWindowItem
|
|
visible: !model.IsLauncher && !model.IsStartup
|
|
|
|
enabled: model.IsClosable
|
|
|
|
text: model.IsGroupParent ? "Close all windows" : "Close window"
|
|
icon: "window-close"
|
|
|
|
onClicked: {
|
|
tasksModel.requestClose(modelIndex());
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
function updateAudioStreams(args) {
|
|
if (args) {
|
|
// When the task just appeared (e.g. virtual desktop switch), show the audio indicator
|
|
// right away. Only when audio streams change during the lifetime of this task, delay
|
|
// showing that to avoid distraction.
|
|
delayAudioStreamIndicator = !!args.delay;
|
|
}
|
|
|
|
var pa = pulseAudio.item;
|
|
if (!pa || !task.isWindow) {
|
|
task.audioStreams = [];
|
|
return;
|
|
}
|
|
|
|
// Check appid first for app using portal
|
|
// https://docs.pipewire.org/page_portal.html
|
|
var streams = pa.streamsForAppId(task.appId);
|
|
if (!streams.length) {
|
|
streams = pa.streamsForPid(model.AppPid);
|
|
if (streams.length) {
|
|
pa.registerPidMatch(model.AppName);
|
|
} else {
|
|
// We only want to fall back to appName matching if we never managed to map
|
|
// a PID to an audio stream window. Otherwise if you have two instances of
|
|
// an application, one playing and the other not, it will look up appName
|
|
// for the non-playing instance and erroneously show an indicator on both.
|
|
if (!pa.hasPidMatch(model.AppName)) {
|
|
streams = pa.streamsForAppName(model.AppName);
|
|
}
|
|
}
|
|
}
|
|
|
|
task.audioStreams = streams;
|
|
}
|
|
|
|
function acquireAudioStreams(args) {
|
|
if (!task.isWindow || !tasksRoot.acquirePulseAudioMonitoring()) {
|
|
task.audioStreams = [];
|
|
return false;
|
|
}
|
|
|
|
++audioStreamUsers;
|
|
updateAudioStreams(args);
|
|
return true;
|
|
}
|
|
|
|
function releaseAudioStreams() {
|
|
if (audioStreamUsers > 0) {
|
|
--audioStreamUsers;
|
|
tasksRoot.releasePulseAudioMonitoring();
|
|
}
|
|
}
|
|
|
|
function toggleMuted() {
|
|
updateAudioStreams({delay: false});
|
|
if (!hasAudioStream) {
|
|
return;
|
|
}
|
|
|
|
if (muted) {
|
|
task.audioStreams.forEach(function (item) { item.unmute(); });
|
|
} else {
|
|
task.audioStreams.forEach(function (item) { item.mute(); });
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: pulseAudio.item
|
|
ignoreUnknownSignals: true // Plasma-PA might not be available
|
|
function onStreamsChanged() {
|
|
if (task.audioStreamUsers > 0) {
|
|
task.updateAudioStreams({delay: true});
|
|
}
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: jumpListDebouncer
|
|
interval: 500
|
|
onTriggered: { }
|
|
}
|
|
TapHandler {
|
|
id: menuTapHandler
|
|
acceptedButtons: Qt.LeftButton
|
|
acceptedModifiers: Qt.NoModifier
|
|
acceptedDevices: PointerDevice.TouchScreen | PointerDevice.Stylus
|
|
onLongPressed: {
|
|
if(contextMenuTimer.showNormalMenu) {
|
|
if(model.IsStartup) return;
|
|
|
|
contextMenuTimer.showNormalMenu = false;
|
|
showFallbackContextMenu({showAllPlaces: true});
|
|
}
|
|
else {
|
|
if(model.IsStartup) return;
|
|
// When we're a launcher, there's no window controls, so we can show all
|
|
// places without the menu getting super huge.
|
|
if (model.IsLauncher) {
|
|
showFallbackContextMenu({showAllPlaces: true});
|
|
} else {
|
|
showControlMenu();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TapHandler {
|
|
acceptedButtons: Qt.RightButton
|
|
acceptedModifiers: Qt.NoModifier
|
|
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus
|
|
gesturePolicy: TapHandler.WithinBounds // Release grab when menu appears
|
|
onPressedChanged: {
|
|
if(model.IsStartup) return;
|
|
if(pressed && !jumpListDebouncer.running) {
|
|
if (model.IsLauncher) {
|
|
showContextMenu({showAllPlaces: true});
|
|
} else {
|
|
showContextMenu();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
TapHandler {
|
|
acceptedButtons: Qt.RightButton
|
|
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus
|
|
acceptedModifiers: Qt.ShiftModifier
|
|
gesturePolicy: TapHandler.WithinBounds // Release grab when menu appears
|
|
onPressedChanged: if (pressed && !jumpListDebouncer.running) contextMenuTimer.start()
|
|
}
|
|
|
|
Timer {
|
|
id: contextMenuTimer
|
|
property bool showNormalMenu: false
|
|
interval: 0
|
|
onTriggered: menuTapHandler.longPressed()
|
|
}
|
|
|
|
TapHandler {
|
|
id: leftTapHandler
|
|
acceptedButtons: Qt.LeftButton
|
|
onTapped: leftClick()
|
|
|
|
function leftClick() {
|
|
|
|
if(tasksRoot.pinnedToolTipOpen) {
|
|
task.hideImmediately();
|
|
tasksRoot.pinnedToolTipOpen = false;
|
|
}
|
|
|
|
TaskTools.activateTask(modelIndex(), model, point.modifiers, task, Plasmoid, tasksRoot, effectWatcher.registered);
|
|
}
|
|
}
|
|
|
|
TapHandler {
|
|
acceptedButtons: Qt.MiddleButton | Qt.BackButton | Qt.ForwardButton
|
|
onTapped: (eventPoint, button) => {
|
|
if (button === Qt.MiddleButton) {
|
|
if (Plasmoid.configuration.middleClickAction === TaskManagerApplet.Backend.NewInstance) {
|
|
tasksModel.requestNewInstance(modelIndex());
|
|
containerRect.loadingNewInstance = true;
|
|
} else if (Plasmoid.configuration.middleClickAction === TaskManagerApplet.Backend.Close) {
|
|
tasksRoot.taskClosedWithMouseMiddleButton = model.WinIdList.slice()
|
|
tasksModel.requestClose(modelIndex());
|
|
} else if (Plasmoid.configuration.middleClickAction === TaskManagerApplet.Backend.ToggleMinimized) {
|
|
tasksModel.requestToggleMinimized(modelIndex());
|
|
} else if (Plasmoid.configuration.middleClickAction === TaskManagerApplet.Backend.ToggleGrouping) {
|
|
tasksModel.requestToggleGrouping(modelIndex());
|
|
} else if (Plasmoid.configuration.middleClickAction === TaskManagerApplet.Backend.BringToCurrentDesktop) {
|
|
tasksModel.requestVirtualDesktops(modelIndex(), [virtualDesktopInfo.currentDesktop]);
|
|
}
|
|
} else if (button === Qt.BackButton || button === Qt.ForwardButton) {
|
|
const playerData = mpris2Source.playerForLauncherUrl(model.LauncherUrlWithoutIcon, model.AppPid);
|
|
if (playerData) {
|
|
if (button === Qt.BackButton) {
|
|
playerData.Previous();
|
|
} else {
|
|
playerData.Next();
|
|
}
|
|
} else {
|
|
eventPoint.accepted = false;
|
|
}
|
|
}
|
|
|
|
tasksRoot.cancelHighlightWindows();
|
|
}
|
|
}
|
|
Rectangle {
|
|
id: containerRect
|
|
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
width: task.width
|
|
height: task.height
|
|
|
|
color: "transparent"
|
|
|
|
Drag.active: dragArea.held
|
|
Drag.source: dragArea
|
|
Drag.hotSpot.x: width / 2
|
|
Drag.hotSpot.y: height / 2
|
|
|
|
property var previousState: ""
|
|
transitions: [
|
|
Transition {
|
|
from: "*"; to: "*";
|
|
NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad }
|
|
},
|
|
Transition {
|
|
from: "jumpListOpen"; to: "*";
|
|
NumberAnimation { property: "opacity"; target: glow; to: 0; easing.type: Easing.Linear; duration: 200 }
|
|
NumberAnimation { property: "opacity"; target: borderGradientRender; to: 0; easing.type: Easing.Linear; duration: 200 }
|
|
},
|
|
Transition {
|
|
from: "*"; to: "startup"
|
|
onRunningChanged: {
|
|
if(!running) {
|
|
animationGlow.opacity = 0;
|
|
glowAnimation.duration = 250;
|
|
}
|
|
}
|
|
NumberAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: 200 }
|
|
SequentialAnimation {
|
|
NumberAnimation {
|
|
target: animationGlow
|
|
property: "verticalRadius"
|
|
to: task.height * 1.5
|
|
duration: 367
|
|
easing.type: Easing.Linear
|
|
}
|
|
PropertyAction { target: glowAnimation; property: "duration"; value: 1000 }
|
|
ParallelAnimation {
|
|
NumberAnimation {
|
|
target: animationGlow
|
|
property: "verticalRadius"
|
|
to: task.height * 0.7
|
|
duration: 1000
|
|
easing.type: Easing.InOutQuad
|
|
}
|
|
NumberAnimation {
|
|
target: glow
|
|
property: "canShow"
|
|
to: 1
|
|
duration: 700
|
|
easing.type: Easing.Linear
|
|
}
|
|
|
|
}
|
|
PropertyAction { target: glowAnimation; property: "duration"; value: 250 }
|
|
}
|
|
SequentialAnimation {
|
|
id: startupAnimation
|
|
NumberAnimation {
|
|
target: animationGlow
|
|
property: "horizontalRadius"
|
|
to: task.width * 1.1
|
|
duration: 367
|
|
easing.type: Easing.Linear
|
|
}
|
|
ParallelAnimation {
|
|
NumberAnimation {
|
|
target: animationGlow
|
|
property: "opacity"
|
|
to: 0
|
|
duration: 1000
|
|
}
|
|
NumberAnimation {
|
|
target: animationGlow
|
|
property: "horizontalRadius"
|
|
to: task.width * 0.7
|
|
duration: 1000
|
|
easing.type: Easing.InOutQuad
|
|
}
|
|
}
|
|
NumberAnimation {
|
|
target: animationGlow
|
|
property: "opacity"
|
|
to: 0
|
|
duration: 3000
|
|
}
|
|
ParallelAnimation {
|
|
id: fadeOutFrame
|
|
PropertyAction { target: glow; property: "canShow"; value: model.IsStartup ? 0 : 1; }
|
|
NumberAnimation {
|
|
target: frame
|
|
property: "opacity"
|
|
to: model.IsStartup ? 0 : 1
|
|
duration: 500
|
|
easing.type: Easing.Linear
|
|
}
|
|
NumberAnimation {
|
|
target: animationGlow
|
|
property: "opacity"
|
|
to: 0
|
|
duration: 3000
|
|
}
|
|
}
|
|
}
|
|
},
|
|
Transition {
|
|
from: "*"; to: "loaded";
|
|
SequentialAnimation {
|
|
ParallelAnimation {
|
|
NumberAnimation {
|
|
target: animationBorderGradient
|
|
property: "horizontalRadius"
|
|
to: task.width * 1.5
|
|
duration: 367
|
|
easing.type: Easing.InQuart
|
|
}
|
|
NumberAnimation {
|
|
target: animationBorderGradient
|
|
property: "opacity"
|
|
to: 1
|
|
duration: 250
|
|
}
|
|
}
|
|
NumberAnimation {
|
|
target: animationBorderGradient
|
|
property: "horizontalRadius"
|
|
to: task.width * 0.5
|
|
duration: 367
|
|
easing.type: Easing.Linear
|
|
}
|
|
}
|
|
SequentialAnimation {
|
|
NumberAnimation {
|
|
target: animationBorderGradient
|
|
property: "verticalRadius"
|
|
to: task.height * 1.5
|
|
duration: 367
|
|
easing.type: Easing.InQuart
|
|
}
|
|
ParallelAnimation {
|
|
NumberAnimation {
|
|
target: animationBorderGradient
|
|
property: "opacity"
|
|
to: 0
|
|
duration: 250
|
|
}
|
|
NumberAnimation {
|
|
target: animationBorderGradient
|
|
property: "verticalRadius"
|
|
to: task.height * 0.5
|
|
duration: 367
|
|
easing.type: Easing.Linear
|
|
}
|
|
|
|
}
|
|
ScriptAction {
|
|
|
|
script: {
|
|
task.tasksRoot.animationManager.removeItem(task.appId)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
]
|
|
|
|
property bool loadingNewInstance: false
|
|
states: [
|
|
// Used for dragging
|
|
State {
|
|
name: "dragging"
|
|
when: dragArea.held
|
|
|
|
ParentChange {
|
|
target: containerRect
|
|
parent: tasksRoot
|
|
}
|
|
AnchorChanges {
|
|
target: containerRect
|
|
anchors {
|
|
top: undefined
|
|
left: undefined
|
|
}
|
|
}
|
|
},
|
|
State {
|
|
name: "jumpListOpen"
|
|
when: (jumpList !== null) && !Plasmoid.configuration.disableHottracking
|
|
PropertyChanges {
|
|
target: glow
|
|
opacity: 1
|
|
horizontalOffset: 0
|
|
}
|
|
PropertyChanges {
|
|
target: borderGradientRender
|
|
opacity: 1
|
|
horizontalOffset: 0
|
|
}
|
|
},
|
|
State {
|
|
name: "startup"
|
|
when: (model.IsStartup || containerRect.loadingNewInstance) && !Plasmoid.configuration.disableHottracking
|
|
PropertyChanges {
|
|
target: animationGlow
|
|
opacity: 1
|
|
horizontalOffset: 0
|
|
horizontalRadius: 0
|
|
verticalRadius: 0
|
|
}
|
|
PropertyChanges {
|
|
target: borderGradientRender
|
|
opacity: 0
|
|
horizontalOffset: 0
|
|
}
|
|
StateChangeScript {
|
|
script: {
|
|
task.tasksRoot.animationManager.addItem(task.appId);
|
|
}
|
|
}
|
|
},
|
|
State {
|
|
name: "loaded"
|
|
when: !(model.IsStartup || model.IsLauncher) && task.tasksRoot.animationManager.getItem(task.appId) && !Plasmoid.configuration.disableHottracking
|
|
PropertyChanges {
|
|
target: animationBorderGradient
|
|
opacity: 0
|
|
horizontalRadius: 0
|
|
verticalRadius: 0
|
|
}
|
|
PropertyChanges {
|
|
target: frame
|
|
opacity: 1
|
|
}
|
|
PropertyChanges {
|
|
target: glowAnimation
|
|
duration: 250
|
|
}
|
|
}
|
|
|
|
]
|
|
|
|
KSvg.FrameSvgItem {
|
|
id: launcherFrame
|
|
|
|
anchors {
|
|
fill: parent
|
|
}
|
|
|
|
imagePath: Qt.resolvedUrl("svgs/tabbar.svgz")
|
|
visible: model.IsLauncher// && !task.containsMouseFalsePositive
|
|
prefix: {
|
|
if(dragArea.held || dragArea.containsPress) return "pressed-tab";
|
|
else if(dragArea.containsMouse) return "active-tab";
|
|
else return "";
|
|
}
|
|
}
|
|
|
|
property color glowColor: "#33c2ff"
|
|
property color glowColorCenter: Qt.tint("#eaeaea", opacify(glowColor, 0.2))
|
|
property color attentionColor: "#ecc656"//"#e7de62"//"#FF7E00"
|
|
property color attentionColorCenter: Qt.tint("#fefefe", opacify(attentionColor, 0.2))
|
|
property color attentionColorEnd: "#ffe516";
|
|
|
|
function opacify(col, factor) {
|
|
return Qt.rgba(col.r, col.g, col.b, factor);
|
|
}
|
|
Rectangle {
|
|
id: borderGradient
|
|
anchors.fill: frame
|
|
anchors.margins: 1
|
|
color: "transparent"
|
|
border.color: "red"
|
|
border.width: 2
|
|
opacity: 0
|
|
radius: 3
|
|
}
|
|
RadialGradient {
|
|
id: animationGlow
|
|
anchors.fill: parent
|
|
anchors.margins: 2
|
|
visible: !Plasmoid.configuration.disableHottracking
|
|
//visible: model.IsStartup
|
|
opacity: 0//frame.isHovered && !dragArea.held ? 1 : 0
|
|
Behavior on opacity {
|
|
NumberAnimation { duration: 250; easing.type: Easing.Linear }
|
|
}
|
|
gradient: Gradient {
|
|
GradientStop { position: 0.0; color: containerRect.glowColorCenter }
|
|
GradientStop { position: 0.5; color: containerRect.opacify(containerRect.glowColor, 0.75) }
|
|
GradientStop { position: 0.75; color: containerRect.opacify(containerRect.glowColor, 0.40) }
|
|
GradientStop { position: 1; color: containerRect.opacify(containerRect.glowColor, 0.15) }
|
|
}
|
|
horizontalRadius: task.width * 1.2
|
|
verticalRadius: task.height * 1.1
|
|
verticalOffset: parent.height / 2
|
|
horizontalOffset: 0//dragArea.mouseX - task.width / 2
|
|
}
|
|
RadialGradient {
|
|
id: glow
|
|
anchors.fill: parent
|
|
anchors.margins: 2
|
|
visible: !model.IsLauncher && !Plasmoid.configuration.disableHottracking
|
|
property bool shouldShow: ((frame.isHovered && !dragArea.held && !(attentionFadeIn.running || attentionFadeOut.running)) ? 1 : 0) * canShow
|
|
opacity: shouldShow ? 1 : 0
|
|
property real canShow: containerRect.state === "startup" ? 0 : 1 // Used for the startup animation
|
|
|
|
onShouldShowChanged: {
|
|
opacity = Qt.binding(() => {return glow.shouldShow; });
|
|
}
|
|
Behavior on opacity {
|
|
NumberAnimation { id: glowAnimation; duration: 250; easing.type: Easing.Linear }
|
|
}
|
|
Behavior on horizontalOffset {
|
|
NumberAnimation { duration: containerRect.state === "jumpListOpen" ? 250 : 0; easing.type: Easing.Linear }
|
|
}
|
|
gradient: Gradient {
|
|
GradientStop { position: 0.0; color: containerRect.glowColorCenter }
|
|
GradientStop { position: 0.5; color: containerRect.opacify(containerRect.glowColor, 0.75) }
|
|
GradientStop { position: 0.75; color: containerRect.opacify(containerRect.glowColor, 0.40) }
|
|
GradientStop { position: 1; color: containerRect.opacify(containerRect.glowColor, 0.15) }
|
|
}
|
|
horizontalRadius: task.width * 1.2
|
|
verticalRadius: task.height * 1.1
|
|
verticalOffset: parent.height / 2
|
|
horizontalOffset: dragArea.mouseX - task.width / 2
|
|
}
|
|
RadialGradient {
|
|
id: animationBorderGradient
|
|
anchors.fill: borderGradient
|
|
source: borderGradient
|
|
visible: !Plasmoid.configuration.disableHottracking
|
|
opacity: 0
|
|
gradient: Gradient {
|
|
GradientStop { position: 0.0; color: containerRect.glowColorCenter }
|
|
GradientStop { position: 0.3; color: containerRect.glowColor }
|
|
}
|
|
verticalOffset: parent.height / 2
|
|
verticalRadius: task.height * 1.5
|
|
horizontalRadius: task.width * 1.5
|
|
horizontalOffset: 0//dragArea.mouseX - task.width / 2
|
|
}
|
|
RadialGradient {
|
|
id: borderGradientRender
|
|
anchors.fill: borderGradient
|
|
source: borderGradient
|
|
visible: !model.IsLauncher && !Plasmoid.configuration.disableHottracking
|
|
property bool shouldShow: (frame.isHovered && !dragArea.held && !(attentionFadeIn.running || attentionFadeOut.running)) ? 1 : 0
|
|
opacity: shouldShow ? 1 : 0
|
|
|
|
onShouldShowChanged: {
|
|
opacity = Qt.binding(() => {return borderGradientRender.shouldShow; });
|
|
}
|
|
Behavior on opacity {
|
|
NumberAnimation { duration: 250; easing.type: Easing.Linear }
|
|
}
|
|
Behavior on horizontalOffset {
|
|
NumberAnimation { duration: containerRect.state === "jumpListOpen" ? 250 : 0; easing.type: Easing.Linear }
|
|
}
|
|
gradient: Gradient {
|
|
GradientStop { position: 0.0; color: containerRect.glowColorCenter }
|
|
GradientStop { position: 0.5; color: containerRect.glowColor }
|
|
GradientStop { position: 1.0; color: containerRect.opacify(containerRect.glowColor, 0.1) }
|
|
}
|
|
verticalOffset: parent.height / 2
|
|
verticalRadius: task.height * 1.5
|
|
horizontalRadius: task.width * 1.5
|
|
horizontalOffset: dragArea.mouseX - task.width / 2
|
|
}
|
|
Rectangle {
|
|
id: attentionIndicator
|
|
anchors.fill: parent
|
|
visible: !Plasmoid.configuration.disableHottracking
|
|
anchors.rightMargin: (task.childCount !== 0) ? groupIndicator.margins.right : 0
|
|
property bool requiresAttention: model.IsDemandingAttention || (task.smartLauncherItem && task.smartLauncherItem.urgent)
|
|
color: "transparent"
|
|
Rectangle {
|
|
id: attentionBorder
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
color: "transparent"
|
|
border.color: "red"
|
|
border.width: 2
|
|
opacity: 0
|
|
radius: 3
|
|
}
|
|
RadialGradient {
|
|
id: attentionGlow
|
|
anchors.fill: parent
|
|
anchors.margins: 2
|
|
opacity: 0
|
|
/*Behavior on opacity {
|
|
NumberAnimation { duration: 250; easing.type: Easing.Linear }
|
|
}*/
|
|
gradient: Gradient {
|
|
GradientStop { position: 0.0; color: containerRect.attentionColorCenter }
|
|
GradientStop { position: 0.5; color: containerRect.attentionColor }
|
|
GradientStop { position: 1.0; color: containerRect.attentionColorEnd }
|
|
}
|
|
horizontalRadius: task.width * 1.2
|
|
verticalRadius: task.height * 1.1
|
|
verticalOffset: parent.height / 2
|
|
horizontalOffset: 0//dragArea.mouseX - task.width / 2
|
|
}
|
|
|
|
RadialGradient {
|
|
id: attentionBorderGradient
|
|
anchors.fill: attentionBorder
|
|
source: attentionBorder
|
|
opacity: 0
|
|
gradient: Gradient {
|
|
GradientStop { position: 0.0; color: containerRect.attentionColorCenter }
|
|
GradientStop { position: 0.6; color: Qt.lighter(containerRect.attentionColor, 1.1) }
|
|
GradientStop { position: 0.7; color: Qt.lighter(containerRect.attentionColorEnd, 1.2) }
|
|
}
|
|
verticalOffset: parent.height / 2
|
|
verticalRadius: task.height * 1.5
|
|
horizontalRadius: task.width * 1.5
|
|
horizontalOffset: 0//dragArea.mouseX - task.width / 2
|
|
}
|
|
transitions: [
|
|
Transition {
|
|
id: attentionFadeOut
|
|
from: "wantsAttention"; to: "*";
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "opacity"
|
|
from: 1
|
|
to: 0
|
|
easing.type: Easing.Linear
|
|
duration: 800
|
|
}
|
|
NumberAnimation {
|
|
target: attentionBorderGradient
|
|
property: "opacity"
|
|
from: 1
|
|
to: 0
|
|
easing.type: Easing.Linear
|
|
duration: 500
|
|
}
|
|
PropertyAction {
|
|
target: attentionFrame
|
|
property: "opacity"
|
|
value: 0
|
|
}
|
|
},
|
|
Transition {
|
|
id: attentionFadeIn
|
|
from: "*"; to: "wantsAttention";
|
|
SequentialAnimation {
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "opacity"
|
|
to: 1
|
|
easing.type: Easing.Linear
|
|
duration: 100
|
|
}
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "opacity"
|
|
from: 1
|
|
to: 0
|
|
loops: 7
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: [ 0.68, 0.0, 0.65, 0.0, 1.0, 1.0 ]
|
|
duration: 1400
|
|
}
|
|
PropertyAction {
|
|
target: attentionGlow
|
|
property: "opacity"
|
|
value: 1
|
|
}
|
|
SequentialAnimation {
|
|
loops: 2
|
|
ParallelAnimation {
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "opacity"
|
|
from: 1
|
|
to: 0.33
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "horizontalRadius"
|
|
from: task.width * 1.2
|
|
to: task.width * 0.75
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "verticalRadius"
|
|
from: task.height * 1.1
|
|
to: task.height * 0.66
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
|
|
}
|
|
ParallelAnimation {
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "opacity"
|
|
from: 0.33
|
|
to: 1
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "horizontalRadius"
|
|
to: task.width * 1.2
|
|
from: task.width * 0.75
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "verticalRadius"
|
|
to: task.height * 1.1
|
|
from: task.height * 0.66
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
|
|
}
|
|
}
|
|
ParallelAnimation {
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "opacity"
|
|
to: 0
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "horizontalRadius"
|
|
to: task.width * 0.75
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
NumberAnimation {
|
|
target: attentionGlow
|
|
property: "verticalRadius"
|
|
to: task.height * 0.66
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
SequentialAnimation {
|
|
NumberAnimation {
|
|
target: attentionBorderGradient
|
|
property: "opacity"
|
|
to: 1
|
|
easing.type: Easing.Linear
|
|
duration: 100
|
|
}
|
|
NumberAnimation {
|
|
target: attentionBorderGradient
|
|
property: "opacity"
|
|
from: 1
|
|
to: 0
|
|
loops: 7
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: [ 0.68, 0.0, 0.65, 0.0, 1.0, 1.0 ]
|
|
duration: 1400
|
|
}
|
|
PropertyAction {
|
|
target: attentionBorderGradient
|
|
property: "opacity"
|
|
value: 1
|
|
}
|
|
SequentialAnimation {
|
|
loops: 2
|
|
NumberAnimation {
|
|
target: attentionBorderGradient
|
|
property: "opacity"
|
|
from: 1
|
|
to: 0.15
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
NumberAnimation {
|
|
target: attentionBorderGradient
|
|
property: "opacity"
|
|
from: 0.15
|
|
to: 1
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
}
|
|
ParallelAnimation {
|
|
NumberAnimation {
|
|
target: attentionBorderGradient
|
|
property: "opacity"
|
|
to: 0
|
|
duration: 3000
|
|
easing.type: Easing.Linear
|
|
}
|
|
NumberAnimation {
|
|
target: attentionFrame
|
|
property: "opacity"
|
|
to: 1
|
|
duration: 3000
|
|
easing.type: Easing.InCubic
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
]
|
|
states: [
|
|
State {
|
|
name: "wantsAttention"
|
|
when: attentionIndicator.requiresAttention
|
|
PropertyChanges {
|
|
target: attentionGlow
|
|
opacity: 0
|
|
}
|
|
|
|
}
|
|
]
|
|
KSvg.FrameSvgItem {
|
|
id: attentionFrame
|
|
anchors.fill: parent
|
|
imagePath: Qt.resolvedUrl("svgs/tasks.svg")
|
|
prefix: "attention"
|
|
opacity: 0
|
|
}
|
|
}
|
|
KSvg.FrameSvgItem {
|
|
id: frame
|
|
|
|
anchors {
|
|
fill: parent
|
|
rightMargin: (task.childCount !== 0) ? groupIndicator.margins.right : 0
|
|
}
|
|
imagePath: Qt.resolvedUrl("svgs/tasks.svg")
|
|
property bool isHovered: ((task.highlighted) && Plasmoid.configuration.taskHoverEffect)
|
|
property bool isActive: model.IsActive || dragArea.containsPress || dragArea.held || task.wasActive
|
|
property string basePrefix: {
|
|
if(model.IsLauncher) return "";
|
|
if(attentionIndicator.requiresAttention && Plasmoid.configuration.disableHottracking) return "attention";
|
|
if((isActive || jumpListOpen) && !(attentionIndicator.requiresAttention || attentionFadeOut.running)) return "active";
|
|
return "normal";
|
|
}
|
|
prefix: (basePrefix + ((isHovered && !attentionIndicator.requiresAttention) ? "-hover" : ""))
|
|
|
|
KSvg.FrameSvgItem {
|
|
id: groupIndicator
|
|
imagePath: Qt.resolvedUrl("svgs/tasks.svg")
|
|
anchors.fill: parent
|
|
anchors.rightMargin: -groupIndicator.margins.right
|
|
prefix: {
|
|
if(task.childCount == 0) return "";
|
|
var result = "group";
|
|
if(frame.isActive) result = "active-" + result;
|
|
if(task.childCount > 2) {
|
|
result += "3";
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Loader {
|
|
id: taskProgressOverlayLoader
|
|
|
|
anchors.fill: frame
|
|
anchors.margins: -1
|
|
asynchronous: true
|
|
active: model.IsWindow && task.smartLauncherItem && task.smartLauncherItem.progressVisible
|
|
|
|
source: "TaskProgressOverlay.qml"
|
|
|
|
z: -1
|
|
}
|
|
|
|
RowLayout {
|
|
spacing: Kirigami.Units.smallSpacing
|
|
anchors.fill: frame
|
|
anchors.margins: Kirigami.Units.smallSpacing
|
|
anchors.rightMargin: (!label.visible ? Kirigami.Units.smallSpacing : Kirigami.Units.largeSpacing) - ((dragArea.containsPress || dragArea.held) ? 1 : 0)
|
|
anchors.leftMargin: !label.visible ? Kirigami.Units.smallSpacing : Kirigami.Units.mediumSpacing
|
|
Kirigami.Icon {
|
|
id: iconBox
|
|
property int iconSize: {
|
|
if(tasksRoot.height <= 30) {
|
|
return Kirigami.Units.iconSizes.small;
|
|
}
|
|
return Kirigami.Units.iconSizes.medium;
|
|
}
|
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
|
|
Layout.minimumWidth: iconSize
|
|
Layout.maximumWidth: iconSize
|
|
Layout.minimumHeight: iconSize
|
|
Layout.maximumHeight: iconSize
|
|
|
|
Layout.leftMargin: (label.visible ? Kirigami.Units.smallSpacing : 0) + ((dragArea.containsPress || dragArea.held) ? 1 : 0)
|
|
Layout.topMargin: ((dragArea.containsPress || dragArea.held) ? 1 : 0)
|
|
source: model.decoration
|
|
antialiasing: false
|
|
|
|
onSourceChanged: {
|
|
containerRect.glowColor = Plasmoid.getDominantColor(iconBox.source);
|
|
badge.badgeColor = containerRect.glowColor
|
|
}
|
|
|
|
Badge {
|
|
id: badge
|
|
visible: task.smartLauncherItem && task.smartLauncherItem.countVisible
|
|
number: task.smartLauncherItem.count
|
|
anchors.top: parent.top
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: (tasksRoot.height <= 30) ? (-Kirigami.Units.largeSpacing + (label.visible ? Kirigami.Units.smallSpacing : 0)) : -Kirigami.Units.smallSpacing
|
|
anchors.topMargin: (tasksRoot.height <= 30) ? -Kirigami.Units.smallSpacing : 0
|
|
Component.onCompleted: {
|
|
badgeColor = containerRect.glowColor
|
|
}
|
|
}
|
|
}
|
|
|
|
PlasmaComponents3.Label {
|
|
id: label
|
|
|
|
visible: (!iconsOnly && !model.IsLauncher
|
|
&& (parent.width - iconBox.height - Kirigami.Units.smallSpacing) >= LayoutMetrics.spaceRequiredToShowText())
|
|
Layout.topMargin: ((dragArea.containsPress || dragArea.held) ? 1 : 0)
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
wrapMode: (maximumLineCount == 1) ? Text.NoWrap : Text.Wrap
|
|
elide: Text.ElideRight
|
|
textFormat: Text.PlainText
|
|
verticalAlignment: Text.AlignVCenter
|
|
maximumLineCount: 1//Plasmoid.configuration.maxTextLines || undefined
|
|
style: Text.Outline
|
|
styleColor: "#02ffffff"
|
|
|
|
Accessible.ignored: true
|
|
|
|
// use State to avoid unnecessary re-evaluation when the label is invisible
|
|
states: State {
|
|
name: "labelVisible"
|
|
when: label.visible
|
|
|
|
PropertyChanges {
|
|
target: label
|
|
text: model.display
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
ParallelAnimation {
|
|
id: backAnim
|
|
NumberAnimation { id: backAnimX; target: containerRect; property: "x"; easing.type: Easing.OutQuad }
|
|
NumberAnimation { id: backAnimY; target: containerRect; property: "y"; easing.type: Easing.OutQuad }
|
|
}
|
|
Timer {
|
|
id: resetDrag
|
|
interval: 250
|
|
onTriggered: {
|
|
dragArea.held = false;
|
|
dragArea.dragThreshold = Qt.point(-1,-1);
|
|
//containerRect.parent = task;
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: dragArea
|
|
property alias taskIndex: task.index
|
|
hoverEnabled: true
|
|
enabled: ((tasksRoot.jumpListItem === jumpList) || (tasksRoot.jumpListItem === null))
|
|
propagateComposedEvents: true
|
|
anchors.fill: parent
|
|
anchors.margins: -1
|
|
|
|
onCanceled: {
|
|
if(held) {
|
|
sendItemBack();
|
|
}
|
|
}
|
|
onContainsMouseChanged: {
|
|
if(containsMouse) {
|
|
if(task.toolTipVisible && !model.IsLauncher) {
|
|
if(taskThumbnail.pinned && !model.IsLauncher) return;
|
|
if(!taskThumbnail.pinned && model.IsLauncher) return;
|
|
task.updateToolTipBindings();
|
|
}
|
|
}
|
|
}
|
|
property bool held: false
|
|
property point beginDrag
|
|
property point currentDrag
|
|
|
|
property point dragThreshold: Qt.point(-1,-1);
|
|
|
|
onHeldChanged: {
|
|
if(held) {
|
|
tasksRoot.setRequestedInhibitDnd(true);
|
|
tasksRoot.dragItem = task;
|
|
tasksRoot.dragSource = task;
|
|
dragHelper.Drag.mimeData = {
|
|
"text/x-orgkdeplasmataskmanager_taskurl": backend.tryDecodeApplicationsUrl(model.LauncherUrlWithoutIcon).toString(),
|
|
[model.MimeType]: model.MimeData,
|
|
"application/x-orgkdeplasmataskmanager_taskbuttonitem": model.MimeData,
|
|
};
|
|
} else {
|
|
tasksRoot.setRequestedInhibitDnd(false);
|
|
tasksRoot.dragItem = null;
|
|
}
|
|
|
|
}
|
|
drag.smoothed: false
|
|
drag.threshold: 0
|
|
drag.minimumX: 0
|
|
drag.minimumY: 0
|
|
drag.maximumX: tasks.width - task.width
|
|
drag.maximumY: tasks.height - task.height
|
|
drag.target: held ? containerRect : undefined
|
|
drag.axis: {
|
|
var result = Drag.XAxis | Drag.YAxis
|
|
return result;
|
|
}
|
|
onPressed: event => {
|
|
dragArea.beginDrag = Qt.point(task.x, task.y);
|
|
dragThreshold = Qt.point(mouseX, mouseY);
|
|
}
|
|
onExited: {
|
|
if((dragThreshold.x !== -1 && dragThreshold.y !== -1)) {
|
|
held = true;
|
|
}
|
|
}
|
|
onEntered: {
|
|
//if(!held) Plasmoid.sendMouseEvent(dragArea);
|
|
}
|
|
onPositionChanged: {
|
|
if(dragArea.containsPress && (dragThreshold.x !== -1 && dragThreshold.y !== -1)) {
|
|
if(Math.abs(dragThreshold.x - mouseX) > 10 || Math.abs(dragThreshold.y - mouseY) > 10) {
|
|
held = true;
|
|
}
|
|
}
|
|
currentDrag = Qt.point(containerRect.x, containerRect.y);
|
|
}
|
|
function sendItemBack() {
|
|
beginDrag = Qt.point(task.x, task.y);
|
|
backAnimX.from = currentDrag.x //- taskList.contentX;
|
|
backAnimX.to = beginDrag.x - taskList.contentX;
|
|
backAnimY.from = currentDrag.y// - taskList.contentY;
|
|
backAnimY.to = beginDrag.y - taskList.contentY;
|
|
backAnim.start();
|
|
resetDrag.start();
|
|
dragThreshold = Qt.point(-1,-1);
|
|
}
|
|
onReleased: event => {
|
|
if(held) {
|
|
sendItemBack();
|
|
} else {
|
|
leftTapHandler.leftClick();
|
|
dragThreshold = Qt.point(-1,-1);
|
|
}
|
|
event.accepted = false;
|
|
}
|
|
}
|
|
DropArea {
|
|
id: dropArea
|
|
visible: tasksRoot.dragItem !== null;
|
|
anchors {
|
|
fill: parent
|
|
margins: 2
|
|
}
|
|
onExited: {
|
|
dragArea.beginDrag = Qt.point(dragArea.x, dragArea.y);
|
|
}
|
|
onEntered: (drag) => {
|
|
if(drag.source.taskIndex === task.index) return;
|
|
tasksModel.move(drag.source.taskIndex, task.index);
|
|
}
|
|
}
|
|
|
|
DropArea {
|
|
signal urlsDropped(var urls)
|
|
|
|
visible: !dropArea.visible // just to make sure it doesn't conflict with the dragging droparea
|
|
|
|
anchors.fill: parent
|
|
|
|
onPositionChanged: {
|
|
if(model.ChildCount == 0) {
|
|
if(task.toolTipVisible) {
|
|
taskThumbnail.dragDrop = false;
|
|
}
|
|
}
|
|
activationTimer.restart();
|
|
}
|
|
|
|
onExited: {
|
|
if(task.toolTipVisible) {
|
|
taskThumbnail.dragDrop = false;
|
|
}
|
|
activationTimer.stop();
|
|
}
|
|
|
|
onDropped: event => {
|
|
// Reject internal drops.
|
|
if (event.formats.indexOf("application/x-orgkdeplasmataskmanager_taskbuttonitem") >= 0) {
|
|
event.accepted = false;
|
|
return;
|
|
}
|
|
|
|
// Reject plasmoid drops.
|
|
if (event.formats.indexOf("text/x-plasmoidservicename") >= 0) {
|
|
event.accepted = false;
|
|
return;
|
|
}
|
|
|
|
if (event.hasUrls) {
|
|
urlsDropped(event.urls);
|
|
return;
|
|
}
|
|
}
|
|
|
|
onUrlsDropped: (urls) => {
|
|
// If all dropped URLs point to application desktop files, we'll add a launcher for each of them.
|
|
var createLaunchers = urls.every(function (item) {
|
|
return backend.isApplication(item)
|
|
});
|
|
|
|
if (createLaunchers) {
|
|
return;
|
|
}
|
|
|
|
// Otherwise we'll just start a new instance of the application with the URLs as argument,
|
|
// as you probably don't expect some of your files to open in the app and others to spawn launchers.
|
|
if(model.ChildCount == 0) {
|
|
tasksModel.requestOpenUrls(task.modelIndex(), urls);
|
|
} else if(model.ChildCount > 0) {
|
|
if(task.toolTipVisible) {
|
|
taskThumbnail.dragDrop = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: activationTimer
|
|
|
|
interval: 250
|
|
repeat: false
|
|
|
|
onTriggered: {
|
|
if(task.model.ChildCount > 0) {
|
|
if(!task.toolTipVisible) {
|
|
task.showToolTip();
|
|
taskThumbnail.dragDrop = true;
|
|
updateToolTipBindings();
|
|
}
|
|
}
|
|
else {
|
|
if(task.toolTipVisible) {
|
|
taskThumbnail.dragDrop = false;
|
|
}
|
|
tasksModel.requestActivate(modelIndex());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
if (model.IsWindow && pulseAudio.item) {
|
|
updateAudioStreams({delay: false});
|
|
}
|
|
|
|
if (!model.IsWindow) {
|
|
taskInitComponent.createObject(task);
|
|
}
|
|
completed = true;
|
|
|
|
taskThumbnail = tasksRoot.taskThumbnail;
|
|
}
|
|
|
|
Component.onDestruction: {
|
|
while (audioStreamUsers > 0) {
|
|
releaseAudioStreams();
|
|
}
|
|
}
|
|
}
|