Added small taskbar support, fixed some bugs and strange behavior in SevenTasks.
|
@ -86,7 +86,7 @@ This only applies to regular windows (most windows with server-side decorations)
|
|||
|
||||
## Configuration menu <a name="config"></a>
|
||||
|
||||
The accent color can be edited in real time through the configuration menu. Internally, the color is stored in the RGB color model as that's what OpenGL expects during rendering. The color mixer window is designed to look and function like Windows 7's Personalization menu, and includes the accent colors found on Windows 7, which were directly pulled from the following registry key:
|
||||
The accent color can be edited in real time through the configuration menu. Real time editing was made possible through the use of [QSharedMemory](https://doc.qt.io/qt-6/qsharedmemory.html) and calling the ```reconfigure()``` method through qdbus whenever a change occurs. Internally, the color is stored in the RGB color model as that's what OpenGL expects during rendering. The color mixer window is designed to look and function like Windows 7's Personalization menu, and includes the accent colors found on Windows 7, which were directly pulled from the following registry key:
|
||||
|
||||
|
||||
```[ HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM\ColorizationColor ]```
|
||||
|
|
|
@ -26,6 +26,21 @@ The first notable thing about SevenStart is the use of animated icons or "orbs"
|
|||
|
||||
In earlier versions of SevenStart, only two images were used, but now three images are used due to upstream updates causing subtle timing issues that would cause undesirable visual effects. Using three images did end up allowing SevenStart to replicate the effects of Vista and 7's Start menu more accurately. By default, SevenStart uses internal icons if no external icons are provided in the configuration window.
|
||||
|
||||
Users can also force the orb to have a constant size, which allows the orb to stick out of the panel if the panel's height is lower than the orb's height. This allows the user to have a small panel with the orb protruding out of the panel, much like Windows 7 and Vista. The implementation is very similar to the user icon sticking out of the menu, which is described in more detail below. This implementation introduces a couple of problems:
|
||||
|
||||
1. Right clicking on this dialog window won't open the standard context menu as expected, as it actually isn't part of the compact or full representation.
|
||||
2. When compositing is disabled, even with the NoBackground hint, this dialog window will simply be drawn with an opaque, black background.
|
||||
|
||||
The first problem is solved by implementing a separate context menu that pulls the appropriate actions from [ContainmentInterface](https://api.kde.org/frameworks/plasma-framework/html/classContainmentInterface.html) and [AppletInterface](https://api.kde.org/frameworks/plasma-framework/html/classAppletInterface.html), which is actually the ```plasmoid``` object.
|
||||
|
||||
Potential solutions to the second problem are far less trivial, as all of them require some sort of compromise. The potential solutions are:
|
||||
|
||||
1. Reverting to the regular orb while compositing is disabled, which is embedded within the panel, and/or resizing the orb back to its unaltered scale. This solution is aesthetically not pleasing at all, and it pretty much defeats the purpose of even enabling this feature to begin with.
|
||||
2. Adding a compiled component to this plasmoid, which would expose more Qt and KDE API methods that can define an opacity mask around the orb. The downside to this solution is that a compiled component reduces portability and makes the installation process slightly more complicated. To see how such an implementation would work however, see this [link](https://github.com/ryanmcalister/donutwindow).
|
||||
3. Applying an opacity mask through an already existing SVG file which can be applied to the dialog window. The downside to this solution is that it feels pretty much like a hack/workaround, and because it uses the provided frameworks in an unintended way.
|
||||
|
||||
This implementation goes for the third solution, which takes advantage of the solid appearance variant found in Plasma themes. The dialog window loads in a completely transparent tooltip SVG that has a customized opacity mask that is created based on the orb texture. This does mean that if the user wants to have a different kind of orb texture that's not spherical in shape, they would also need to provide a correct SVG that represents the opacity mask of the orb. See the source code for more implementation details.
|
||||
|
||||
Another notable thing about the compact representation is that it is used in an unusual way compared to how plasmoids are generally designed to behave. Plasmoids have two representations:
|
||||
|
||||
1. Compact representation, which is used when the plasmoid is in a panel.
|
||||
|
@ -88,3 +103,6 @@ Files:
|
|||
|OftenUsedView.qml|Used to display recently opened programs.|
|
||||
|SidePanelItemDelegate.qml|Displays and holds information about the sidebar menu entries.|
|
||||
|ApplicationsView.qml|Used to display all applications installed on the system.|
|
||||
|StartOrb.qml|Dialog window representing the orb that is used for the small taskbar layout.|
|
||||
|FloatingOrb.qml|The actual orb button that handles the visual animations and functionality.|
|
||||
|ContextMenu.qml|Reimplemented context menu for StartOrb to bypass Dialog limitations.|
|
||||
|
|
|
@ -34,6 +34,8 @@ Regular textures are used for all other windows (plasmoids, OSD popups, task swi
|
|||
|
||||
The opaque appearance state aims to be a recreation of Aero Basic (WIP). Currently, only plasmoids using solid textures and the window manager don't comply with the aesthetic, but everything else does. A potential solution is to detect a change in compositing in plasmoids that use solid textures, change the dialog type to ```NoBackground``` and display a custom texture as the background while compositing is disabled. A similar solution can also be applied to the window manager.
|
||||
|
||||
Another important note is that the tooltip SVG used in the solid appearance is now used as a workaround to allow orb transparency in SevenStart. For more information, go to [SevenStart](../Software/Plasmoids/SevenStart.md)'s documentation.
|
||||
|
||||
### Icons
|
||||
|
||||
This theme also features a small set of icons used mainly by plasmoids like the system tray. Most of these icons are simply just scaled down variants of icons taken from Breeze, while other icons are taken directly from the main icon theme of this project.
|
||||
|
@ -54,7 +56,7 @@ The "Unique" column describes if the file itself is exclusive to Seven-Black.
|
|||
|panel-background.svg |widgets/ |Default taskbar texture. |Y |Y |N |
|
||||
|tooltip.svg |widgets/ |Default tooltip texture. |Y |Y |N |
|
||||
|button-close.svg |widgets/ |Close button icon used in SevenTasks. |N |N |Y |
|
||||
|menuitem.svg |widgets/ |Texture used for menu items in SevenStart and SevenTasks|N |N |Y |
|
||||
|menuitem.svg |widgets/ |Texture used for menu items in SevenStart and SevenTasks.|N |N |Y |
|
||||
|showdesktop.svg |widgets/ |Texture used for the Show desktop plasmoid. |N |N |Y |
|
||||
|sidebaritem.svg |widgets/ |Texture used for sidebar entries in SevenStart. |N |N |Y |
|
||||
|startmenu-buttons.svg |widgets/ |Texture used for the shut down button in SevenStart.|N |N |Y |
|
||||
|
@ -70,6 +72,7 @@ The "Unique" column describes if the file itself is exclusive to Seven-Black.
|
|||
|panel-background.svg |opaque/widgets/|Used when compositing is disabled. |N |Y |N |
|
||||
|tooltip.svg |opaque/widgets/|Used when compositing is disabled. |N |Y |N |
|
||||
|background.svg |solid/dialogs/ |Used by the system tray and date and time plasmoid. |Y |Y |N |
|
||||
|tooltip.svg |solid/widgets/ |Used to provide an opacity mask to SevenStart's orb. |Y |Y |N |
|
||||
|
||||
## Nonstandard SVGs <a name="svgs"></a>
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ Starting off with the simplest modifications, this is a list of recommended sett
|
|||
- Under KWin Scripts:
|
||||
- Enable 'MinimizeAll'
|
||||
|
||||
When editing Plasma's bottom panel, make sure its width is set to 40 pixels.
|
||||
When editing Plasma's bottom panel, make sure its width is set to 40 pixels (30 if using a small panel).
|
||||
|
||||
### KDE Plasma Theme <a name="plasma-theme"></a>
|
||||
|
||||
|
|
3693
Plasma/KDE_Plasma_Theme/Seven-Black/solid/widgets/tooltip.svg
Executable file
After Width: | Height: | Size: 168 KiB |
|
@ -12,6 +12,9 @@
|
|||
<entry name="useCustomButtonImage" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="stickOutOrb" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="customButtonImage" type="Url">
|
||||
<default></default>
|
||||
</entry>
|
||||
|
|
|
@ -22,10 +22,10 @@ import QtQuick.Layouts 1.1
|
|||
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.kwindowsystem 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property var screenGeometry: plasmoid.screenGeometry
|
||||
readonly property bool inPanel: (plasmoid.location == PlasmaCore.Types.TopEdge
|
||||
|| plasmoid.location == PlasmaCore.Types.RightEdge
|
||||
|
@ -33,23 +33,28 @@ Item {
|
|||
|| plasmoid.location == PlasmaCore.Types.LeftEdge)
|
||||
readonly property bool vertical: (plasmoid.formFactor == PlasmaCore.Types.Vertical)
|
||||
readonly property bool useCustomButtonImage: (plasmoid.configuration.useCustomButtonImage)
|
||||
|
||||
// Should the orb be rendered in its own dialog window so that it can stick out of the panel?
|
||||
readonly property bool stickOutOrb: plasmoid.configuration.stickOutOrb && inPanel && !editMode
|
||||
property QtObject dashWindow: null
|
||||
property QtObject orb: null
|
||||
property QtObject contextMenu: null
|
||||
|
||||
Plasmoid.status: dashWindow && dashWindow.visible ? PlasmaCore.Types.RequiresAttentionStatus : PlasmaCore.Types.PassiveStatus
|
||||
|
||||
onWidthChanged: updateSizeHints()
|
||||
onHeightChanged: updateSizeHints()
|
||||
|
||||
clip: true
|
||||
function updateSizeHints() {
|
||||
if (useCustomButtonImage) {
|
||||
if (vertical) {
|
||||
var scaledHeight = Math.floor(parent.width * (buttonIcon.implicitHeight / buttonIcon.implicitWidth));
|
||||
var scaledHeight = Math.floor(parent.width * (floatingOrbPanel.buttonIcon.implicitHeight / floatingOrbPanel.buttonIcon.implicitWidth));
|
||||
root.Layout.minimumHeight = scaledHeight;
|
||||
root.Layout.maximumHeight = scaledHeight;
|
||||
root.Layout.minimumWidth = units.iconSizes.small;
|
||||
root.Layout.maximumWidth = inPanel ? units.iconSizeHints.panel : -1;
|
||||
} else {
|
||||
var scaledWidth = Math.floor(parent.height * (buttonIcon.implicitWidth / buttonIcon.implicitHeight));
|
||||
var scaledWidth = Math.floor(parent.height * (floatingOrbPanel.buttonIcon.implicitWidth / floatingOrbPanel.buttonIcon.implicitHeight));
|
||||
root.Layout.minimumWidth = scaledWidth;
|
||||
root.Layout.maximumWidth = scaledWidth;
|
||||
root.Layout.minimumHeight = units.iconSizes.small;
|
||||
|
@ -61,15 +66,89 @@ Item {
|
|||
root.Layout.minimumHeight = units.iconSizes.small
|
||||
root.Layout.maximumHeight = inPanel ? units.iconSizeHints.panel : -1;
|
||||
}
|
||||
if(stickOutOrb && orb) {
|
||||
root.Layout.minimumWidth = orb.width + panelSvg.margins.right*(compositing ? 0 : 1);
|
||||
root.Layout.maximumWidth = orb.width + panelSvg.margins.right*(compositing ? 0 : 1);
|
||||
root.Layout.minimumHeight = orb.height;
|
||||
root.Layout.maximumHeight = orb.height;
|
||||
}
|
||||
}
|
||||
|
||||
onStickOutOrbChanged: {
|
||||
updateSizeHints();
|
||||
positionOrb();
|
||||
}
|
||||
|
||||
|
||||
/* The following code gets the ContainmentInterface instance which is used for two things:
|
||||
* 1. Getting context menu actions for entering edit mode and adding plasmoids
|
||||
* 2. Keeping track on when edit mode is enabled. This allows us to hide the StartOrb
|
||||
* object so the user can actually highlight and select this plasmoid during edit mode.
|
||||
*/
|
||||
property var containmentInterface: null
|
||||
readonly property bool editMode: containmentInterface ? containmentInterface.editMode : false
|
||||
onParentChanged: {
|
||||
if (parent) {
|
||||
for (var obj = root, depth = 0; !!obj; obj = obj.parent, depth++) {
|
||||
if (obj.toString().startsWith('ContainmentInterface')) {
|
||||
// desktop containment / plasmoidviewer
|
||||
// Note: This doesn't always work. FolderViewDropArea may not yet have
|
||||
// ContainmentInterface as a parent when this loop runs.
|
||||
if (typeof obj['editMode'] === 'boolean') {
|
||||
root.containmentInterface = obj
|
||||
break
|
||||
}
|
||||
} else if (obj.toString().startsWith('DeclarativeDropArea')) {
|
||||
// panel containment
|
||||
if (typeof obj['Plasmoid'] !== 'undefined' && obj['Plasmoid'].toString().startsWith('ContainmentInterface')) {
|
||||
if (typeof obj['Plasmoid']['editMode'] === 'boolean') {
|
||||
root.containmentInterface = obj.Plasmoid
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: units.iconSizeHints
|
||||
|
||||
function onPanelChanged() { updateSizeHints(); }
|
||||
}
|
||||
property bool compositing: kwindowsystem.compositingActive
|
||||
|
||||
// If the url is empty (default value), then use the fallback url.
|
||||
/* We want to change the background hint for the orb dialog window depending
|
||||
* on the compositing state. In this case, 0 refers to NoBackground, while
|
||||
* 2 refers to SolidBackground.
|
||||
*/
|
||||
onCompositingChanged: {
|
||||
if(compositing) {
|
||||
orb.backgroundHints = 0;
|
||||
} else {
|
||||
orb.backgroundHints = 2;
|
||||
}
|
||||
updateSizeHints();
|
||||
positionOrb();
|
||||
|
||||
// Add a little padding to the orb.
|
||||
if(compositing)
|
||||
orb.x += panelSvg.margins.left;
|
||||
}
|
||||
|
||||
function positionOrb() {
|
||||
var pos = plasmoid.mapToGlobal(kicker.x, kicker.y); // Gets the global position of this plasmoid, in screen coordinates.
|
||||
orb.width = floatingOrbPanel.buttonIcon.implicitWidth + panelSvg.margins.left;
|
||||
orb.height = floatingOrbPanel.buttonIcon.implicitHeight;
|
||||
orb.x = pos.x;
|
||||
orb.y = pos.y + panelSvg.margins.bottom;
|
||||
|
||||
// Keep the orb positioned exactly on the bottom if it is rendered out of bounds (beyond the screen geometry)
|
||||
if(orb.y + orb.height > plasmoid.screenGeometry.height) {
|
||||
orb.y -= orb.y + orb.height - plasmoid.screenGeometry.height;
|
||||
}
|
||||
}
|
||||
// If the url is empty (default value), then use the fallback url. Otherwise, return the url path relative to
|
||||
// the location of the source code.
|
||||
function getResolvedUrl(url, fallback) {
|
||||
if(url.toString() === "") {
|
||||
return Qt.resolvedUrl(fallback);
|
||||
|
@ -78,6 +157,12 @@ Item {
|
|||
}
|
||||
property int opacityDuration: 250
|
||||
|
||||
function createContextMenu(pos) {
|
||||
contextMenu = Qt.createQmlObject("ContextMenu {}", root);
|
||||
contextMenu.fillActions();
|
||||
contextMenu.show();
|
||||
}
|
||||
|
||||
/*
|
||||
* Three IconItems are used in order to achieve the same look and feel as Windows 7's
|
||||
* orbs. When the menu is closed, hovering over the orb results in the hovered icon
|
||||
|
@ -85,73 +170,48 @@ Item {
|
|||
* visibility, where the normal and hovered icons are invisible, and the pressed icon
|
||||
* is visible.
|
||||
*
|
||||
* These icons will by default try to fill up as much space as they can in the compact
|
||||
* representation.
|
||||
* When they're bounded by the panel, these icons will by default try to fill up as
|
||||
* much space as they can in the compact representation while preserving their aspect
|
||||
* ratio.
|
||||
*/
|
||||
PlasmaCore.IconItem {
|
||||
id: buttonIcon
|
||||
|
||||
FloatingOrb {
|
||||
id: floatingOrbPanel
|
||||
visible: (!stickOutOrb)
|
||||
anchors.fill: parent
|
||||
opacity: 1
|
||||
readonly property double aspectRatio: (vertical ? implicitHeight / implicitWidth
|
||||
: implicitWidth / implicitHeight)
|
||||
|
||||
source: getResolvedUrl(plasmoid.configuration.customButtonImage, "orbs/normal.png")
|
||||
|
||||
smooth: true
|
||||
roundToIconSize: !useCustomButtonImage || aspectRatio === 1
|
||||
onSourceChanged: updateSizeHints()
|
||||
}
|
||||
PlasmaCore.IconItem {
|
||||
id: buttonIconPressed
|
||||
anchors.fill: parent
|
||||
opacity: 1
|
||||
visible: dashWindow.visible
|
||||
readonly property double aspectRatio: (vertical ? implicitHeight / implicitWidth
|
||||
: implicitWidth / implicitHeight)
|
||||
|
||||
source: getResolvedUrl(plasmoid.configuration.customButtonImageActive, "orbs/selected.png") //
|
||||
|
||||
smooth: true
|
||||
roundToIconSize: !useCustomButtonImage || aspectRatio === 1
|
||||
onSourceChanged: updateSizeHints()
|
||||
}
|
||||
PlasmaCore.IconItem {
|
||||
id: buttonIconHovered
|
||||
z: 1
|
||||
source: getResolvedUrl(plasmoid.configuration.customButtonImageHover, "orbs/hovered.png");
|
||||
opacity: mouseArea.containsMouse
|
||||
visible: !dashWindow.visible
|
||||
anchors.fill: parent
|
||||
readonly property double aspectRatio: (vertical ? implicitHeight / implicitWidth
|
||||
: implicitWidth / implicitHeight)
|
||||
smooth: true
|
||||
Behavior on opacity {
|
||||
NumberAnimation { properties: "opacity"; easing.type: Easing.InOutQuad; duration: opacityDuration }
|
||||
}
|
||||
// A custom icon could also be rectangular. However, if a square, custom, icon is given, assume it
|
||||
// to be an icon and round it to the nearest icon size again to avoid scaling artifacts.
|
||||
roundToIconSize: !useCustomButtonImage || aspectRatio === 1
|
||||
|
||||
onSourceChanged: updateSizeHints()
|
||||
objectName: "innerorb"
|
||||
}
|
||||
|
||||
// Clicking on the plasmoid or activating it in any way causes the Full representation
|
||||
// to show/hide.
|
||||
// Covers the entire compact representation just in case the orb dialog doesn't cover
|
||||
// the entire area by itself.
|
||||
MouseArea
|
||||
{
|
||||
id: mouseArea
|
||||
id: mouseAreaCompositingOff
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
visible: stickOutOrb
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: {
|
||||
dashWindow.visible = !dashWindow.visible;
|
||||
dashWindow.showingAllPrograms = false;
|
||||
if(mouse.button == Qt.RightButton) {
|
||||
var pos = plasmoid.mapToGlobal(mouse.x, mouse.y);
|
||||
createContextMenu(pos);
|
||||
|
||||
|
||||
} else {
|
||||
dashWindow.visible = !dashWindow.visible;
|
||||
dashWindow.showingAllPrograms = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
dashWindow = Qt.createQmlObject("MenuRepresentation {}", root);
|
||||
orb = Qt.createQmlObject("StartOrb {}", root);
|
||||
plasmoid.activated.connect(function() {
|
||||
dashWindow.visible = !dashWindow.visible;
|
||||
dashWindow.showingAllPrograms = false;
|
||||
});
|
||||
positionOrb();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ Item {
|
|||
|
||||
property alias cfg_appNameFormat: appNameFormat.currentIndex
|
||||
property alias cfg_switchCategoriesOnHover: switchCategoriesOnHover.checked
|
||||
property alias cfg_stickOutOrb: stickOutOrb.checked
|
||||
|
||||
property alias cfg_useExtraRunners: useExtraRunners.checked
|
||||
|
||||
|
@ -61,7 +62,7 @@ Item {
|
|||
spacing: units.smallSpacing
|
||||
|
||||
Label {
|
||||
text: i18n("Icon:")
|
||||
text: i18n("Orb:")
|
||||
}
|
||||
|
||||
IconPicker {
|
||||
|
@ -73,7 +74,7 @@ Item {
|
|||
|
||||
}
|
||||
Label {
|
||||
text: i18n("Hover Icon:")
|
||||
text: i18n("Hover Orb:")
|
||||
}
|
||||
IconPicker {
|
||||
id: iconPickerHover
|
||||
|
@ -84,7 +85,7 @@ Item {
|
|||
|
||||
}
|
||||
Label {
|
||||
text: i18n("Active Icon:")
|
||||
text: i18n("Clicked Orb:")
|
||||
}
|
||||
IconPicker {
|
||||
id: iconPickerActive
|
||||
|
@ -123,6 +124,11 @@ Item {
|
|||
|
||||
text: i18n("Switch categories on hover")
|
||||
}
|
||||
CheckBox {
|
||||
id: stickOutOrb
|
||||
|
||||
text: i18n("Force constant orb size")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
|
||||
|
||||
PlasmaComponents.ContextMenu {
|
||||
id: menu
|
||||
|
||||
placement: {
|
||||
if (plasmoid.location === PlasmaCore.Types.LeftEdge) {
|
||||
return PlasmaCore.Types.RightPosedTopAlignedPopup;
|
||||
} else if (plasmoid.location === PlasmaCore.Types.TopEdge) {
|
||||
return PlasmaCore.Types.BottomPosedLeftAlignedPopup;
|
||||
} else if (plasmoid.location === PlasmaCore.Types.RightEdge) {
|
||||
return PlasmaCore.Types.LeftPosedTopAlignedPopup;
|
||||
} else {
|
||||
return PlasmaCore.Types.TopPosedLeftAlignedPopup;
|
||||
}
|
||||
}
|
||||
|
||||
minimumWidth: root.width
|
||||
function show() {
|
||||
openRelative();
|
||||
}
|
||||
|
||||
function newMenuItem(parent) {
|
||||
return Qt.createQmlObject(`
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
|
||||
PlasmaComponents.MenuItem { }
|
||||
`, parent);
|
||||
}
|
||||
|
||||
function newSeparator(parent) {
|
||||
return Qt.createQmlObject(`
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
|
||||
PlasmaComponents.MenuItem { separator: true }
|
||||
`, parent);
|
||||
}
|
||||
function fillItem(item, action) {
|
||||
item.text = action.text;
|
||||
item.icon = action.icon;
|
||||
item.visible = action.visible;
|
||||
item.objectName = action.objectName;
|
||||
item.clicked.connect(function() {
|
||||
action.trigger();
|
||||
});
|
||||
addMenuItem(item);
|
||||
}
|
||||
function fillActions() {
|
||||
plasmoid.prepareContextualActions();
|
||||
for(var index = 0; index < plasmoid.contextualActions.length; index++) {
|
||||
var action = plasmoid.contextualActions[index];
|
||||
var item = newMenuItem(menu);
|
||||
fillItem(item, action);
|
||||
}
|
||||
var action = plasmoid.action("alternatives");
|
||||
if(action && action.enabled) {
|
||||
var item = newMenuItem(menu);
|
||||
fillItem(item, action);
|
||||
}
|
||||
|
||||
item = newMenuItem(menu);
|
||||
action = plasmoid.action("configure");
|
||||
fillItem(item, action);
|
||||
|
||||
item = newSeparator(menu);
|
||||
addMenuItem(item);
|
||||
|
||||
action = containmentInterface.action("add widgets");
|
||||
if(action) {
|
||||
item = newMenuItem(menu);
|
||||
fillItem(item, action);
|
||||
};
|
||||
|
||||
action = containmentInterface.action("configure");
|
||||
if(action) {
|
||||
item = newMenuItem(menu);
|
||||
fillItem(item, action);
|
||||
};
|
||||
|
||||
}
|
||||
onStatusChanged: {
|
||||
if (status == PlasmaComponents.DialogStatus.Closed) {
|
||||
menu.destroy();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Window 2.1
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
|
||||
import org.kde.plasma.private.kicker 0.1 as Kicker
|
||||
import org.kde.kcoreaddons 1.0 as KCoreAddons // kuser
|
||||
import org.kde.plasma.private.shell 2.0
|
||||
|
||||
import org.kde.kwindowsystem 1.0
|
||||
import org.kde.kquickcontrolsaddons 2.0
|
||||
import org.kde.plasma.private.quicklaunch 1.0
|
||||
|
||||
import org.kde.kirigami 2.13 as Kirigami
|
||||
import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons
|
||||
|
||||
import org.kde.kwindowsystem 1.0
|
||||
import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons
|
||||
|
||||
|
||||
Item {
|
||||
id: floatingOrb
|
||||
width: buttonIcon.implicitWidth
|
||||
height: buttonIcon.implicitHeight
|
||||
property alias buttonIcon: buttonIcon
|
||||
property alias buttonIconPressed: buttonIconPressed
|
||||
property alias buttonIconHovered: buttonIconHovered
|
||||
property alias mouseArea: mouseArea
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
id: buttonIcon
|
||||
anchors.fill: parent
|
||||
opacity: 1
|
||||
readonly property double aspectRatio: (vertical ? implicitHeight / implicitWidth
|
||||
: implicitWidth / implicitHeight)
|
||||
|
||||
source: getResolvedUrl(plasmoid.configuration.customButtonImage, "orbs/normal.png")
|
||||
smooth: true
|
||||
roundToIconSize: !useCustomButtonImage || aspectRatio === 1
|
||||
onSourceChanged: updateSizeHints()
|
||||
}
|
||||
PlasmaCore.IconItem {
|
||||
id: buttonIconPressed
|
||||
anchors.fill: parent
|
||||
opacity: 1
|
||||
visible: dashWindow.visible
|
||||
readonly property double aspectRatio: (vertical ? implicitHeight / implicitWidth
|
||||
: implicitWidth / implicitHeight)
|
||||
|
||||
source: getResolvedUrl(plasmoid.configuration.customButtonImageActive, "orbs/selected.png") //
|
||||
|
||||
smooth: true
|
||||
roundToIconSize: !useCustomButtonImage || aspectRatio === 1
|
||||
onSourceChanged: updateSizeHints()
|
||||
}
|
||||
PlasmaCore.IconItem {
|
||||
id: buttonIconHovered
|
||||
z: 1
|
||||
source: getResolvedUrl(plasmoid.configuration.customButtonImageHover, "orbs/hovered.png");
|
||||
opacity: mouseArea.containsMouse || mouseAreaCompositingOff.containsMouse
|
||||
visible: !dashWindow.visible
|
||||
anchors.fill: parent
|
||||
readonly property double aspectRatio: (vertical ? implicitHeight / implicitWidth
|
||||
: implicitWidth / implicitHeight)
|
||||
smooth: true
|
||||
Behavior on opacity {
|
||||
NumberAnimation { properties: "opacity"; easing.type: Easing.InOutQuad; duration: opacityDuration }
|
||||
}
|
||||
// A custom icon could also be rectangular. However, if a square, custom, icon is given, assume it
|
||||
// to be an icon and round it to the nearest icon size again to avoid scaling artifacts.
|
||||
roundToIconSize: !useCustomButtonImage || aspectRatio === 1
|
||||
|
||||
onSourceChanged: updateSizeHints()
|
||||
}
|
||||
|
||||
MouseArea
|
||||
{
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: {
|
||||
if(mouse.button == Qt.RightButton) {
|
||||
var pos = plasmoid.mapToGlobal(mouse.x, mouse.y);
|
||||
createContextMenu(pos);
|
||||
|
||||
|
||||
} else {
|
||||
dashWindow.visible = !dashWindow.visible;
|
||||
dashWindow.showingAllPrograms = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -126,7 +126,10 @@ PlasmaExtras.ScrollArea {
|
|||
delegate: Item {
|
||||
width: itemColumn.width
|
||||
height: gridViewLabel.height + gridView.height + (index == repeater.count - 1 ? 0 : units.smallSpacing)
|
||||
visible: repeater.model.modelForRow(index).count > 0
|
||||
visible: {
|
||||
if(!repeater.model.modelForRow(index)) return false;
|
||||
return repeater.model.modelForRow(index).count > 0
|
||||
}
|
||||
|
||||
property alias currentIndex: gridView.currentIndex
|
||||
property alias count: gridView.count
|
||||
|
@ -143,7 +146,10 @@ PlasmaExtras.ScrollArea {
|
|||
color: "#1d3287";
|
||||
level: 4
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
text: repeater.model.modelForRow(index).description + " (" + repeater.model.modelForRow(index).count +")"
|
||||
text: {
|
||||
if(!repeater.model.modelForRow(index)) return "";
|
||||
return repeater.model.modelForRow(index).description + " (" + repeater.model.modelForRow(index).count +")";
|
||||
}
|
||||
}
|
||||
|
||||
//Line that extends from the header to the right of the search view.
|
||||
|
|
|
@ -65,6 +65,7 @@ ListModel {
|
|||
}
|
||||
|
||||
function parseModel(appList, model, path) {
|
||||
// console.log(path, model, model.description, model.count);
|
||||
for (var i = 0; i < model.count; i++) {
|
||||
var item = model.modelForRow(i);
|
||||
if (!item) {
|
||||
|
@ -72,8 +73,10 @@ ListModel {
|
|||
}
|
||||
var itemPath = (path || []).concat(i);
|
||||
if (item && item.hasChildren) {
|
||||
// console.log(item)
|
||||
parseModel(appList, item, itemPath);
|
||||
} else {
|
||||
// console.log(itemPath, item, item.description);
|
||||
appList.push(item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ import org.kde.plasma.private.quicklaunch 1.0
|
|||
import org.kde.kirigami 2.13 as Kirigami
|
||||
import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons
|
||||
|
||||
import org.kde.kwindowsystem 1.0
|
||||
|
||||
|
||||
|
||||
PlasmaCore.Dialog {
|
||||
|
@ -61,7 +61,7 @@ PlasmaCore.Dialog {
|
|||
property bool searching: (searchField.text != "")
|
||||
property bool showingAllPrograms: false
|
||||
property bool firstTimePopup: false // To make sure the user icon is displayed properly.
|
||||
property bool compositingEnabled: kwindowsystem.compositingActive
|
||||
|
||||
|
||||
property int slideAnimationDuration: 105
|
||||
|
||||
|
@ -182,7 +182,7 @@ PlasmaCore.Dialog {
|
|||
focus: true
|
||||
clip: true
|
||||
|
||||
KWindowSystem { id: kwindowsystem } // Used for detecting compositing changes.
|
||||
|
||||
KCoreAddons.KUser { id: kuser } // Used for getting the username and icon.
|
||||
Logic { id: logic } // Probably useful.
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ Item {
|
|||
if (!searchField.text) {
|
||||
repeaterModelIndex = 0;
|
||||
runnerGrid.repeater.currentModelIndex = 0;
|
||||
runnerModel.model = null;
|
||||
if(runnerModel.model) runnerModel.model = null;
|
||||
} else {
|
||||
if(runnerGrid.count != 0) {
|
||||
runnerGrid.repeater.currentModelIndex = 0;
|
||||
|
@ -72,6 +72,7 @@ Item {
|
|||
if(!focus) repeaterModelIndex = runnerGrid.repeater.currentModelIndex;
|
||||
else {
|
||||
runnerGrid.repeater.currentModelIndex = repeaterModelIndex;
|
||||
console.log("home.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Window 2.1
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
|
||||
import org.kde.plasma.private.kicker 0.1 as Kicker
|
||||
import org.kde.kcoreaddons 1.0 as KCoreAddons // kuser
|
||||
import org.kde.plasma.private.shell 2.0
|
||||
|
||||
import org.kde.kwindowsystem 1.0
|
||||
import org.kde.kquickcontrolsaddons 2.0
|
||||
import org.kde.plasma.private.quicklaunch 1.0
|
||||
|
||||
import org.kde.kirigami 2.13 as Kirigami
|
||||
import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons
|
||||
|
||||
import org.kde.kwindowsystem 1.0
|
||||
import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons
|
||||
|
||||
/*
|
||||
* This is the Dialog that displays the Start menu orb when it sticks out
|
||||
* of the panel. In principle, it works in almost the same way as the
|
||||
* Start menu user icon, in fact most of the code is directly copied from
|
||||
* there.
|
||||
*
|
||||
* With this approach, two important problems come up:
|
||||
* 1. Right clicking on this dialog window won't open the standard
|
||||
* context menu as expected, as it actually isn't part of the
|
||||
* compact or full representation.
|
||||
* 2. When compositing is disabled, even with the NoBackground hint, this
|
||||
* dialog window will simply be drawn with an opaque, black background.
|
||||
*
|
||||
* This source code tackles both problems in such a way to avoid having to
|
||||
* introduce a compiled component of the plasmoid, which would greatly
|
||||
* reduce its portability and ease of installation. The downside of this
|
||||
* approach is that the solution to the second problem leaves us bound to
|
||||
* the Seven-Black Plasma theme, as it uses the SVG file found in
|
||||
*
|
||||
* /solid/widgets/tooltip.svg
|
||||
*
|
||||
* However, this can be circumvented by copying this file over to any other
|
||||
* theme, as this is probably the *least* used SVG texture in KDE, if not
|
||||
* completely unused. This SVG file contains only the opacity and input
|
||||
* mask of the dialog window, which gets applied when X11 compositing is
|
||||
* disabled. Another slight limitation to this approach is that the
|
||||
* possible choice of menu orbs is limited to perfect spheres in this
|
||||
* particular configuration. This can be corrected if the opacity mask is
|
||||
* changed in the SVG file, meaning that installing custom orbs might
|
||||
* potentially be a two-step process now.
|
||||
*
|
||||
* Compared to the popup avatar, this dialog window should NOT have any
|
||||
* visualParent set, as it causes inexplicable behavior where the orb
|
||||
* moves away. I have no idea why it does that.
|
||||
*
|
||||
* This has been developed only for the bottom/south oriented panel, and
|
||||
* other orientations should receive support when I begin giving pretty
|
||||
* much *everything* else support for other orientations.
|
||||
*
|
||||
*/
|
||||
|
||||
PlasmaCore.Dialog {
|
||||
id: iconUser
|
||||
flags: Qt.WindowStaysOnTopHint | Qt.Popup | Qt.X11BypassWindowManagerHint // To prevent the icon from animating its opacity when its visibility is changed
|
||||
type: "Tooltip" // Crucial to making this work under no compositing. See above for details.
|
||||
location: "Floating"
|
||||
|
||||
// Positions are defined when the plasmoid has been fully loaded, to prevent undefined behavior.
|
||||
x: 0
|
||||
y: 0
|
||||
onYChanged: { // Tries to circumvent possible inexplicable changes in position. Currently doesn't seem to run in practice anymore, as it has most likely been fixed by keeping the visualParent undefined.
|
||||
var pos = plasmoid.mapToGlobal(kicker.x, kicker.y);
|
||||
if(iconUser.y - pos.y < 0) {
|
||||
iconUser.y -= iconUser.y - pos.y + panelSvg.margins.bottom*2 + panelSvg.margins.top*2;
|
||||
}
|
||||
}
|
||||
backgroundHints: PlasmaCore.Types.SolidBackground
|
||||
visible: root.visible && stickOutOrb
|
||||
opacity: iconUser.visible // To prevent even more NP-hard unpredictable behavior
|
||||
|
||||
// The actual orb button, this dialog window is just a container for it.
|
||||
mainItem: FloatingOrb {
|
||||
id: floatingOrbIcon
|
||||
}
|
||||
Component.onCompleted: {
|
||||
/*
|
||||
* When compositing is enabled, we want to simply use the NoBackground
|
||||
* hint to render a fully transparent, blur-free window. If we used the
|
||||
* same opacity mask for both cases, blur would be applied behind the
|
||||
* orb, which would also by extension render reflections and colorize
|
||||
* the entire area as well.
|
||||
*/
|
||||
iconUser.backgroundHints = compositing ? 0 : 2;
|
||||
}
|
||||
}
|
|
@ -24,6 +24,8 @@ import org.kde.plasma.plasmoid 2.0
|
|||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
import org.kde.plasma.private.kicker 0.1 as Kicker
|
||||
import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons
|
||||
import org.kde.kwindowsystem 1.0
|
||||
|
||||
Item {
|
||||
id: kicker
|
||||
|
@ -33,6 +35,7 @@ Item {
|
|||
anchors.fill: parent
|
||||
property bool isDash: false
|
||||
property Item dragSource: null
|
||||
clip: true
|
||||
|
||||
// With this we can make the compact representation be any
|
||||
// item we want.
|
||||
|
@ -42,6 +45,7 @@ Item {
|
|||
|
||||
property QtObject globalFavorites: rootModel.favoritesModel
|
||||
property QtObject systemFavorites: rootModel.systemFavoritesModel
|
||||
property bool compositingEnabled: kwindowsystem.compositingActive
|
||||
|
||||
// Runs KMenuEdit.
|
||||
function action_menuedit() {
|
||||
|
@ -82,7 +86,7 @@ Item {
|
|||
}
|
||||
signal exited(string cmd, int exitCode, int exitStatus, string stdout, string stderr)
|
||||
}
|
||||
|
||||
KWindowSystem { id: kwindowsystem } // Used for detecting compositing changes.
|
||||
Kicker.RootModel {
|
||||
id: rootModel
|
||||
|
||||
|
@ -230,5 +234,6 @@ Item {
|
|||
rootModel.refreshed.connect(reset);
|
||||
|
||||
dragHelper.dropped.connect(resetDragSource);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
@ -58,6 +58,7 @@ MouseArea {
|
|||
property real taskHeight: 0
|
||||
property string previousState: ""
|
||||
property bool rightClickDragging: false
|
||||
property bool toolTipOpen: false
|
||||
|
||||
property Item audioStreamOverlay
|
||||
property var audioStreams: []
|
||||
|
@ -153,6 +154,7 @@ MouseArea {
|
|||
}
|
||||
hoverEnabled = true;
|
||||
taskList.updateHoverFunc();
|
||||
toolTipArea.tooltipClicked = true;
|
||||
}
|
||||
|
||||
onContainsMouseChanged: {
|
||||
|
@ -176,6 +178,7 @@ MouseArea {
|
|||
hoverEnabled = true;
|
||||
|
||||
updateMousePosition(ma.mouseX);
|
||||
toolTipArea.tooltipClicked = true;
|
||||
|
||||
}
|
||||
|
||||
|
@ -226,6 +229,9 @@ MouseArea {
|
|||
if (plasmoid.configuration.showToolTips && toolTipArea.active) {
|
||||
hideToolTipTemporarily();
|
||||
}
|
||||
/*if(childCount >= 2 && plasmoid.configuration.showToolTips && toolTipArea.active) {
|
||||
toolTipArea.tooltipClicked = !toolTipArea.tooltipClicked;
|
||||
}*/
|
||||
TaskTools.activateTask(modelIndex(), model, mouse.modifiers, task);
|
||||
|
||||
} else if (mouse.button === Qt.BackButton || mouse.button === Qt.ForwardButton) {
|
||||
|
@ -452,7 +458,7 @@ MouseArea {
|
|||
opacity: 0.6
|
||||
visible: childCount >= 3 ? true : false
|
||||
anchors.rightMargin: PlasmaCore.Units.smallSpacing
|
||||
enabledBorders: Plasma.FrameSvg.EnabledBorders.RightBorder
|
||||
enabledBorders: PlasmaCore.FrameSvg.RightBorder
|
||||
|
||||
}
|
||||
|
||||
|
@ -711,8 +717,8 @@ MouseArea {
|
|||
PlasmaCore.ToolTipArea {
|
||||
id: toolTipArea
|
||||
z: -1
|
||||
//backgroundHints: "SolidBackground"
|
||||
MouseArea {
|
||||
|
||||
MouseArea {
|
||||
id: ma
|
||||
hoverEnabled: true
|
||||
propagateComposedEvents: true
|
||||
|
@ -720,34 +726,32 @@ MouseArea {
|
|||
onPositionChanged: {
|
||||
task.updateMousePosition(ma.mouseX);
|
||||
task.positionChanged(mouse);
|
||||
//var xtr = toolTipArea.backgroundHints();
|
||||
|
||||
}
|
||||
onContainsMouseChanged: {
|
||||
|
||||
task.updateMousePosition(ma.mouseX);
|
||||
//task.onContainsMouseChanged();
|
||||
//toolTipArea.onContainsMouseChanged();
|
||||
//mouse.accepted = false;
|
||||
}
|
||||
onPressed: mouse.accepted = false;
|
||||
onReleased: mouse.accepted = false;
|
||||
onWheel: wheel.accepted = false;
|
||||
//onExited: { hoverGradient.horizontalOffset = 0;
|
||||
//task.onExited();
|
||||
//}
|
||||
}
|
||||
anchors.fill: parent
|
||||
location: plasmoid.location
|
||||
|
||||
active: !inPopup && !groupDialog.visible && plasmoid.configuration.showToolTips
|
||||
property bool tooltipClicked: true
|
||||
active: !inPopup && !groupDialog.visible && (plasmoid.configuration.showToolTips || tasks.toolTipOpenedByClick === toolTipArea)
|
||||
interactive: model.IsWindow === true
|
||||
|
||||
mainItem: (model.IsWindow === true) ? openWindowToolTipDelegate : pinnedAppToolTipDelegate
|
||||
property alias mainToolTip: toolTipArea.mainItem
|
||||
onToolTipVisibleChanged: {
|
||||
task.toolTipOpen = toolTipVisible;
|
||||
if(!toolTipVisible) {
|
||||
tasks.toolTipOpenedByClick = null;
|
||||
} else {
|
||||
tasks.toolTipAreaItem = toolTipArea;
|
||||
}
|
||||
|
||||
}
|
||||
onContainsMouseChanged: {
|
||||
|
||||
updateMousePosition(ma.mouseX);
|
||||
if (containsMouse) {
|
||||
mainItem.parentTask = task;
|
||||
|
@ -802,6 +806,9 @@ MouseArea {
|
|||
mainItem.smartLauncherCount = Qt.binding(function() {
|
||||
return mainItem.smartLauncherCountVisible ? task.smartLauncherItem.count : 0;
|
||||
});
|
||||
tasks.toolTipAreaItem = toolTipArea;
|
||||
} else {
|
||||
tasks.toolTipOpenedByClick = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,11 @@ function activateTask(index, model, modifiers, task) {
|
|||
else if (plasmoid.configuration.showToolTips
|
||||
&& plasmoid.configuration.groupedTaskVisualization === 1
|
||||
) {
|
||||
task.showToolTip();
|
||||
if(tasks.toolTipOpenedByClick) tasks.toolTipOpenedByClick.hideImmediately();
|
||||
else {
|
||||
tasks.toolTipOpenedByClick = task.toolTipAreaItem;
|
||||
task.showToolTip();
|
||||
}
|
||||
}
|
||||
|
||||
// Option 3: show Present Windows for all child tasks
|
||||
|
|
|
@ -27,7 +27,8 @@ MouseArea {
|
|||
// This property tells the plasmoid to render labels next to task icons.
|
||||
// Previously, this property was determined by the value of (plasmoid.pluginName === "org.kde.plasma.icontasks")
|
||||
property bool iconsOnly: !plasmoid.configuration.labelVisible
|
||||
|
||||
property var toolTipOpenedByClick: null
|
||||
property var toolTipAreaItem: null
|
||||
//property QtObject contextMenuComponent: Qt.createComponent("ContextMenu.qml");
|
||||
property QtObject tasksMenuComponent: Qt.createComponent("TasksMenu.qml");
|
||||
property QtObject pulseAudioComponent: Qt.createComponent("PulseAudio.qml");
|
||||
|
@ -60,6 +61,7 @@ MouseArea {
|
|||
|
||||
signal requestLayout
|
||||
signal windowsHovered(variant winIds, bool hovered)
|
||||
signal activateWindowView(variant winIds)
|
||||
signal presentWindows(variant winIds)
|
||||
|
||||
states: State {
|
||||
|
@ -511,10 +513,12 @@ MouseArea {
|
|||
// With this, we can update each task icon pretty much globally.
|
||||
function updateHoverFunc() {
|
||||
for(var i = 0; i < taskRepeater.count; i++) {
|
||||
taskRepeater.itemAt(i).updateHoverColor();
|
||||
if(taskRepeater.itemAt(i)) {
|
||||
taskRepeater.itemAt(i).updateHoverColor();
|
||||
}
|
||||
}
|
||||
tasks.state = "";
|
||||
console.log("Updated hovers");
|
||||
//console.log("Updated hovers");
|
||||
}
|
||||
|
||||
Timer {
|
||||
|
@ -604,7 +608,8 @@ MouseArea {
|
|||
tasks.requestLayout.connect(layoutTimer.restart);
|
||||
tasks.requestLayout.connect(iconGeometryTimer.restart);
|
||||
tasks.windowsHovered.connect(backend.windowsHovered);
|
||||
tasks.presentWindows.connect(backend.presentWindows);
|
||||
//tasks.presentWindows.connect(backend.presentWindows);
|
||||
tasks.activateWindowView.connect(backend.activateWindowView);
|
||||
dragHelper.dropped.connect(resetDragSource);
|
||||
taskList.updateHoverFunc();
|
||||
}
|
||||
|
|
|
@ -1,774 +0,0 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2012-2016 Eike Hein <hein@kde.org>
|
||||
SPDX-FileCopyrightText: 2016 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
|
||||
import org.kde.taskmanager 0.1 as TaskManager
|
||||
|
||||
import "code/layout.js" as LayoutManager
|
||||
|
||||
PlasmaComponents.ContextMenu {
|
||||
id: menu
|
||||
|
||||
property QtObject backend
|
||||
property QtObject mpris2Source
|
||||
property var modelIndex
|
||||
readonly property var atm: TaskManager.AbstractTasksModel
|
||||
|
||||
property bool showAllPlaces: false
|
||||
|
||||
|
||||
placement: {
|
||||
if (plasmoid.location === PlasmaCore.Types.LeftEdge) {
|
||||
return PlasmaCore.Types.RightPosedTopAlignedPopup;
|
||||
} else if (plasmoid.location === PlasmaCore.Types.TopEdge) {
|
||||
return PlasmaCore.Types.BottomPosedLeftAlignedPopup;
|
||||
} else if (plasmoid.location === PlasmaCore.Types.RightEdge) {
|
||||
return PlasmaCore.Types.LeftPosedTopAlignedPopup;
|
||||
} else {
|
||||
return PlasmaCore.Types.TopPosedLeftAlignedPopup;
|
||||
}
|
||||
}
|
||||
|
||||
minimumWidth: visualParent.width
|
||||
//We have all of the above
|
||||
|
||||
//Might be important, at least the opening part
|
||||
onStatusChanged: {
|
||||
if (visualParent && get(atm.LauncherUrlWithoutIcon) != "" && status == PlasmaComponents.DialogStatus.Open) {
|
||||
activitiesDesktopsMenu.refresh();
|
||||
|
||||
} else if (status == PlasmaComponents.DialogStatus.Closed) {
|
||||
menu.destroy();
|
||||
backend.ungrabMouse(visualParent);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// Cannot have "Connections" as child of PlasmaCoponents.ContextMenu.
|
||||
backend.showAllPlaces.connect(showContextMenuWithAllPlaces);
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
backend.showAllPlaces.disconnect(showContextMenuWithAllPlaces);
|
||||
}
|
||||
|
||||
function showContextMenuWithAllPlaces() {
|
||||
visualParent.showContextMenu({showAllPlaces: true});
|
||||
}
|
||||
|
||||
function get(modelProp) {
|
||||
return tasksModel.data(modelIndex, modelProp)
|
||||
}
|
||||
|
||||
function show() {
|
||||
loadDynamicLaunchActions(get(atm.LauncherUrlWithoutIcon));
|
||||
openRelative();
|
||||
}
|
||||
|
||||
function newMenuItem(parent) {
|
||||
return Qt.createQmlObject(`
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
|
||||
PlasmaComponents.MenuItem {}
|
||||
`, parent);
|
||||
}
|
||||
|
||||
function newSeparator(parent) {
|
||||
return Qt.createQmlObject(`
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
|
||||
PlasmaComponents.MenuItem { separator: true }
|
||||
`, parent);
|
||||
}
|
||||
|
||||
function loadDynamicLaunchActions(launcherUrl) {
|
||||
var sections = [
|
||||
{
|
||||
title: i18n("Places"),
|
||||
group: "places",
|
||||
actions: backend.placesActions(launcherUrl, showAllPlaces, menu)
|
||||
},
|
||||
{
|
||||
title: i18n("Recent Files"),
|
||||
group: "recents",
|
||||
actions: backend.recentDocumentActions(launcherUrl, menu)
|
||||
},
|
||||
{
|
||||
title: i18n("Actions"),
|
||||
group: "actions",
|
||||
actions: backend.jumpListActions(launcherUrl, menu)
|
||||
}
|
||||
]
|
||||
|
||||
// C++ can override section heading by returning a QString as first action
|
||||
sections.forEach((section) => {
|
||||
if (typeof section.actions[0] === "string") {
|
||||
section.title = section.actions.shift(); // take first
|
||||
}
|
||||
});
|
||||
|
||||
// QMenu does not limit its width automatically. Even if we set a maximumWidth
|
||||
// it would just cut off text rather than eliding. So we do this manually.
|
||||
var textMetrics = Qt.createQmlObject("import QtQuick 2.4; TextMetrics {}", menu);
|
||||
var maximumWidth = LayoutManager.maximumContextMenuTextWidth();
|
||||
|
||||
sections.forEach(function (section) {
|
||||
if (section["actions"].length > 0 || section["group"] == "actions") {
|
||||
// Don't add the "Actions" header if the menu has nothing but actions
|
||||
// in it, because then it's redundant (all menus have actions)
|
||||
if (
|
||||
(section["group"] != "actions") ||
|
||||
(section["group"] == "actions" && (sections[0]["actions"].length > 0 || sections[1]["actions"].length > 0))
|
||||
) {
|
||||
var sectionHeader = newMenuItem(menu);
|
||||
sectionHeader.text = section["title"];
|
||||
sectionHeader.section = true;
|
||||
menu.addMenuItem(sectionHeader, startNewInstanceItem);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < section["actions"].length; ++i) {
|
||||
var item = newMenuItem(menu);
|
||||
item.action = section["actions"][i];
|
||||
|
||||
// Crude way of manually eliding...
|
||||
var elided = false;
|
||||
textMetrics.text = Qt.binding(function() {
|
||||
return item.action.text;
|
||||
});
|
||||
|
||||
while (textMetrics.width > maximumWidth) {
|
||||
item.action.text = item.action.text.slice(0, -1);
|
||||
elided = true;
|
||||
}
|
||||
|
||||
if (elided) {
|
||||
item.action.text += "…";
|
||||
}
|
||||
|
||||
menu.addMenuItem(item, startNewInstanceItem);
|
||||
}
|
||||
});
|
||||
|
||||
// Add Media Player control actions
|
||||
var sourceName = mpris2Source.sourceNameForLauncherUrl(launcherUrl, get(atm.AppPid));
|
||||
|
||||
if (sourceName && !(get(atm.WinIdList) !== undefined && get(atm.WinIdList).length > 1)) {
|
||||
var playerData = mpris2Source.data[sourceName]
|
||||
|
||||
if (playerData.CanControl) {
|
||||
var playing = (playerData.PlaybackStatus === "Playing");
|
||||
var menuItem = menu.newMenuItem(menu);
|
||||
menuItem.text = i18nc("Play previous track", "Previous Track");
|
||||
menuItem.icon = "media-skip-backward";
|
||||
menuItem.enabled = Qt.binding(function() {
|
||||
return playerData.CanGoPrevious;
|
||||
});
|
||||
menuItem.clicked.connect(function() {
|
||||
mpris2Source.goPrevious(sourceName);
|
||||
});
|
||||
menu.addMenuItem(menuItem, startNewInstanceItem);
|
||||
|
||||
menuItem = menu.newMenuItem(menu);
|
||||
// PlasmaCore Menu doesn't actually handle icons or labels changing at runtime...
|
||||
menuItem.text = Qt.binding(function() {
|
||||
// if CanPause, toggle the menu entry between Play & Pause, otherwise always use Play
|
||||
return playing && playerData.CanPause ? i18nc("Pause playback", "Pause") : i18nc("Start playback", "Play");
|
||||
});
|
||||
menuItem.icon = Qt.binding(function() {
|
||||
return playing && playerData.CanPause ? "media-playback-pause" : "media-playback-start";
|
||||
});
|
||||
menuItem.enabled = Qt.binding(function() {
|
||||
return playing ? playerData.CanPause : playerData.CanPlay;
|
||||
});
|
||||
menuItem.clicked.connect(function() {
|
||||
if (playing) {
|
||||
mpris2Source.pause(sourceName);
|
||||
} else {
|
||||
mpris2Source.play(sourceName);
|
||||
}
|
||||
});
|
||||
menu.addMenuItem(menuItem, startNewInstanceItem);
|
||||
|
||||
menuItem = menu.newMenuItem(menu);
|
||||
menuItem.text = i18nc("Play next track", "Next Track");
|
||||
menuItem.icon = "media-skip-forward";
|
||||
menuItem.enabled = Qt.binding(function() {
|
||||
return playerData.CanGoNext;
|
||||
});
|
||||
menuItem.clicked.connect(function() {
|
||||
mpris2Source.goNext(sourceName);
|
||||
});
|
||||
menu.addMenuItem(menuItem, startNewInstanceItem);
|
||||
|
||||
menuItem = menu.newMenuItem(menu);
|
||||
menuItem.text = i18nc("Stop playback", "Stop");
|
||||
menuItem.icon = "media-playback-stop";
|
||||
menuItem.enabled = Qt.binding(function() {
|
||||
return playerData.PlaybackStatus !== "Stopped";
|
||||
});
|
||||
menuItem.clicked.connect(function() {
|
||||
mpris2Source.stop(sourceName);
|
||||
});
|
||||
menu.addMenuItem(menuItem, startNewInstanceItem);
|
||||
|
||||
// Technically media controls and audio streams are separate but for the user they're
|
||||
// semantically related, don't add a separator inbetween.
|
||||
if (!menu.visualParent.hasAudioStream) {
|
||||
menu.addMenuItem(newSeparator(menu), startNewInstanceItem);
|
||||
}
|
||||
|
||||
// If we don't have a window associated with the player but we can quit
|
||||
// it through MPRIS we'll offer a "Quit" option instead of "Close"
|
||||
if (!closeWindowItem.visible && playerData.CanQuit) {
|
||||
menuItem = menu.newMenuItem(menu);
|
||||
menuItem.text = i18nc("Quit media player app", "Quit");
|
||||
menuItem.icon = "application-exit";
|
||||
menuItem.visible = Qt.binding(function() {
|
||||
return !closeWindowItem.visible;
|
||||
});
|
||||
menuItem.clicked.connect(function() {
|
||||
mpris2Source.quit(sourceName);
|
||||
});
|
||||
menu.addMenuItem(menuItem);
|
||||
}
|
||||
|
||||
// If we don't have a window associated with the player but we can raise
|
||||
// it through MPRIS we'll offer a "Restore" option
|
||||
if (get(atm.IsLauncher) === true && !startNewInstanceItem.visible && playerData.CanRaise) {
|
||||
menuItem = menu.newMenuItem(menu);
|
||||
menuItem.text = i18nc("Open or bring to the front window of media player app", "Restore");
|
||||
menuItem.icon = playerData["Desktop Icon Name"];
|
||||
menuItem.visible = Qt.binding(function() {
|
||||
return !startNewInstanceItem.visible;
|
||||
});
|
||||
menuItem.clicked.connect(function() {
|
||||
mpris2Source.raise(sourceName);
|
||||
});
|
||||
menu.addMenuItem(menuItem, startNewInstanceItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We allow mute/unmute whenever an application has a stream, regardless of whether it
|
||||
// is actually playing sound.
|
||||
// This way you can unmute, e.g. a telephony app, even after the conversation has ended,
|
||||
// so you still have it ringing later on.
|
||||
if (menu.visualParent.hasAudioStream) {
|
||||
var muteItem = menu.newMenuItem(menu);
|
||||
muteItem.checkable = true;
|
||||
muteItem.checked = Qt.binding(function() {
|
||||
return menu.visualParent && menu.visualParent.muted;
|
||||
});
|
||||
muteItem.clicked.connect(function() {
|
||||
menu.visualParent.toggleMuted();
|
||||
});
|
||||
muteItem.text = i18n("Mute");
|
||||
muteItem.icon = "audio-volume-muted";
|
||||
menu.addMenuItem(muteItem, startNewInstanceItem);
|
||||
|
||||
menu.addMenuItem(newSeparator(menu), startNewInstanceItem);
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
id: startNewInstanceItem
|
||||
visible: get(atm.CanLaunchNewInstance)
|
||||
text: i18n("Open New Window")
|
||||
icon: "window-new"
|
||||
|
||||
onClicked: tasksModel.requestNewInstance(modelIndex)
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
id: virtualDesktopsMenuItem
|
||||
|
||||
visible: virtualDesktopInfo.numberOfDesktops > 1
|
||||
&& (visualParent && get(atm.IsLauncher) !== true
|
||||
&& get(atm.IsStartup) !== true
|
||||
&& get(atm.IsVirtualDesktopsChangeable) === true)
|
||||
|
||||
enabled: visible
|
||||
|
||||
text: i18n("Move to &Desktop")
|
||||
icon: "virtual-desktops"
|
||||
|
||||
Connections {
|
||||
target: virtualDesktopInfo
|
||||
|
||||
function onNumberOfDesktopsChanged() {Qt.callLater(virtualDesktopsMenu.refresh)}
|
||||
function onDesktopIdsChanged() {Qt.callLater(virtualDesktopsMenu.refresh)}
|
||||
function onDesktopNamesChanged() {Qt.callLater(virtualDesktopsMenu.refresh)}
|
||||
}
|
||||
|
||||
PlasmaComponents.ContextMenu {
|
||||
id: virtualDesktopsMenu
|
||||
|
||||
visualParent: virtualDesktopsMenuItem.action
|
||||
|
||||
function refresh() {
|
||||
clearMenuItems();
|
||||
|
||||
if (virtualDesktopInfo.numberOfDesktops <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var menuItem = menu.newMenuItem(virtualDesktopsMenu);
|
||||
menuItem.text = i18n("Move &To Current Desktop");
|
||||
menuItem.enabled = Qt.binding(function() {
|
||||
return menu.visualParent && menu.get(atm.VirtualDesktops).indexOf(virtualDesktopInfo.currentDesktop) === -1;
|
||||
});
|
||||
menuItem.clicked.connect(function() {
|
||||
tasksModel.requestVirtualDesktops(menu.modelIndex, [virtualDesktopInfo.currentDesktop]);
|
||||
});
|
||||
|
||||
menuItem = menu.newMenuItem(virtualDesktopsMenu);
|
||||
menuItem.text = i18n("&All Desktops");
|
||||
menuItem.checkable = true;
|
||||
menuItem.checked = Qt.binding(function() {
|
||||
return menu.visualParent && menu.get(atm.IsOnAllVirtualDesktops) === true;
|
||||
});
|
||||
menuItem.clicked.connect(function() {
|
||||
tasksModel.requestVirtualDesktops(menu.modelIndex, []);
|
||||
});
|
||||
backend.setActionGroup(menuItem.action);
|
||||
|
||||
menu.newSeparator(virtualDesktopsMenu);
|
||||
|
||||
for (var i = 0; i < virtualDesktopInfo.desktopNames.length; ++i) {
|
||||
menuItem = menu.newMenuItem(virtualDesktopsMenu);
|
||||
menuItem.text = i18nc("1 = number of desktop, 2 = desktop name", "&%1 %2", i + 1, virtualDesktopInfo.desktopNames[i]);
|
||||
menuItem.checkable = true;
|
||||
menuItem.checked = Qt.binding((function(i) {
|
||||
return function() { return menu.visualParent && menu.get(atm.VirtualDesktops).indexOf(virtualDesktopInfo.desktopIds[i]) > -1 };
|
||||
})(i));
|
||||
menuItem.clicked.connect((function(i) {
|
||||
return function() { return tasksModel.requestVirtualDesktops(menu.modelIndex, [virtualDesktopInfo.desktopIds[i]]); };
|
||||
})(i));
|
||||
backend.setActionGroup(menuItem.action);
|
||||
}
|
||||
|
||||
menu.newSeparator(virtualDesktopsMenu);
|
||||
|
||||
menuItem = menu.newMenuItem(virtualDesktopsMenu);
|
||||
menuItem.text = i18n("&New Desktop");
|
||||
menuItem.clicked.connect(function() {
|
||||
tasksModel.requestNewVirtualDesktop(menu.modelIndex);
|
||||
});
|
||||
}
|
||||
|
||||
Component.onCompleted: refresh()
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
id: activitiesDesktopsMenuItem
|
||||
|
||||
visible: activityInfo.numberOfRunningActivities > 1
|
||||
&& (visualParent && !get(atm.IsLauncher)
|
||||
&& !get(atm.IsStartup))
|
||||
|
||||
enabled: visible
|
||||
|
||||
text: i18n("Show in &Activities")
|
||||
icon: "activities"
|
||||
|
||||
Connections {
|
||||
target: activityInfo
|
||||
|
||||
function onNumberOfRunningActivitiesChanged() {
|
||||
activitiesDesktopsMenu.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.ContextMenu {
|
||||
id: activitiesDesktopsMenu
|
||||
|
||||
visualParent: activitiesDesktopsMenuItem.action
|
||||
|
||||
function refresh() {
|
||||
clearMenuItems();
|
||||
|
||||
if (activityInfo.numberOfRunningActivities <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var menuItem = menu.newMenuItem(activitiesDesktopsMenu);
|
||||
menuItem.text = i18n("Add To Current Activity");
|
||||
menuItem.enabled = Qt.binding(function() {
|
||||
return menu.visualParent && menu.get(atm.Activities).length > 0 &&
|
||||
menu.get(atm.Activities).indexOf(activityInfo.currentActivity) < 0;
|
||||
});
|
||||
menuItem.clicked.connect(function() {
|
||||
tasksModel.requestActivities(menu.modelIndex, menu.get(atm.Activities).concat(activityInfo.currentActivity));
|
||||
});
|
||||
|
||||
menuItem = menu.newMenuItem(activitiesDesktopsMenu);
|
||||
menuItem.text = i18n("All Activities");
|
||||
menuItem.checkable = true;
|
||||
menuItem.checked = Qt.binding(function() {
|
||||
return menu.visualParent && menu.get(atm.Activities).length === 0;
|
||||
});
|
||||
menuItem.toggled.connect(function(checked) {
|
||||
let newActivities = []; // will cast to an empty QStringList i.e all activities
|
||||
if (!checked) {
|
||||
newActivities = new Array(activityInfo.currentActivity);
|
||||
}
|
||||
tasksModel.requestActivities(menu.modelIndex, newActivities);
|
||||
});
|
||||
|
||||
menu.newSeparator(activitiesDesktopsMenu);
|
||||
|
||||
var runningActivities = activityInfo.runningActivities();
|
||||
for (var i = 0; i < runningActivities.length; ++i) {
|
||||
var activityId = runningActivities[i];
|
||||
|
||||
menuItem = menu.newMenuItem(activitiesDesktopsMenu);
|
||||
menuItem.text = activityInfo.activityName(runningActivities[i]);
|
||||
menuItem.checkable = true;
|
||||
menuItem.checked = Qt.binding( (function(activityId) {
|
||||
return function() {
|
||||
return menu.visualParent && menu.get(atm.Activities).indexOf(activityId) >= 0;
|
||||
};
|
||||
})(activityId));
|
||||
menuItem.toggled.connect((function(activityId) {
|
||||
return function (checked) {
|
||||
var newActivities = menu.get(atm.Activities);
|
||||
if (checked) {
|
||||
newActivities = newActivities.concat(activityId);
|
||||
} else {
|
||||
var index = newActivities.indexOf(activityId)
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
newActivities.splice(index, 1);
|
||||
}
|
||||
return tasksModel.requestActivities(menu.modelIndex, newActivities);
|
||||
};
|
||||
})(activityId));
|
||||
}
|
||||
|
||||
menu.newSeparator(activitiesDesktopsMenu);
|
||||
|
||||
for (var i = 0; i < runningActivities.length; ++i) {
|
||||
var activityId = runningActivities[i];
|
||||
var onActivities = menu.get(atm.Activities);
|
||||
|
||||
// if the task is on a single activity, don't insert a "move to" item for that activity
|
||||
if(onActivities.length == 1 && onActivities[0] == activityId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
menuItem = menu.newMenuItem(activitiesDesktopsMenu);
|
||||
menuItem.text = i18n("Move to %1", activityInfo.activityName(activityId))
|
||||
menuItem.clicked.connect((function(activityId) {
|
||||
return function () {
|
||||
return tasksModel.requestActivities(menu.modelIndex, [activityId]);
|
||||
};
|
||||
})(activityId));
|
||||
}
|
||||
|
||||
menu.newSeparator(activitiesDesktopsMenu);
|
||||
}
|
||||
|
||||
Component.onCompleted: refresh()
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
id: launcherToggleAction
|
||||
|
||||
visible: visualParent
|
||||
&& get(atm.IsLauncher) !== true
|
||||
&& get(atm.IsStartup) !== true
|
||||
&& plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
|
||||
&& (activityInfo.numberOfRunningActivities < 2)
|
||||
&& !doesBelongToCurrentActivity()
|
||||
|
||||
enabled: visualParent && get(atm.LauncherUrlWithoutIcon) != ""
|
||||
|
||||
text: i18n("&Pin to Task Manager")
|
||||
icon: "window-pin"
|
||||
|
||||
function doesBelongToCurrentActivity() {
|
||||
return tasksModel.launcherActivities(get(atm.LauncherUrlWithoutIcon)).some(function(activity) {
|
||||
return activity === activityInfo.currentActivity || activity === activityInfo.nullUuid;
|
||||
});
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
tasksModel.requestAddLauncher(get(atm.LauncherUrl));
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
id: showLauncherInActivitiesItem
|
||||
|
||||
text: i18n("&Pin to Task Manager")
|
||||
icon: "window-pin"
|
||||
|
||||
visible: visualParent
|
||||
&& get(atm.IsStartup) !== true
|
||||
&& plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
|
||||
&& (activityInfo.numberOfRunningActivities >= 2)
|
||||
|
||||
Connections {
|
||||
target: activityInfo
|
||||
function onNumberOfRunningActivitiesChanged() {
|
||||
activitiesDesktopsMenu.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.ContextMenu {
|
||||
id: activitiesLaunchersMenu
|
||||
visualParent: showLauncherInActivitiesItem.action
|
||||
|
||||
function refresh() {
|
||||
clearMenuItems();
|
||||
|
||||
if (menu.visualParent === null) return;
|
||||
|
||||
var createNewItem = function(id, title, url, activities) {
|
||||
var result = menu.newMenuItem(activitiesLaunchersMenu);
|
||||
result.text = title;
|
||||
|
||||
result.visible = true;
|
||||
result.checkable = true;
|
||||
|
||||
result.checked = activities.some(function(activity) { return activity === id });
|
||||
|
||||
result.clicked.connect(
|
||||
function() {
|
||||
if (result.checked) {
|
||||
tasksModel.requestAddLauncherToActivity(url, id);
|
||||
} else {
|
||||
tasksModel.requestRemoveLauncherFromActivity(url, id);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (menu.visualParent === null) return;
|
||||
|
||||
var url = menu.get(atm.LauncherUrlWithoutIcon);
|
||||
|
||||
var activities = tasksModel.launcherActivities(url);
|
||||
|
||||
createNewItem(activityInfo.nullUuid, i18n("On All Activities"), url, activities);
|
||||
|
||||
if (activityInfo.numberOfRunningActivities <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
createNewItem(activityInfo.currentActivity, i18n("On The Current Activity"), url, activities);
|
||||
|
||||
menu.newSeparator(activitiesLaunchersMenu);
|
||||
|
||||
var runningActivities = activityInfo.runningActivities();
|
||||
|
||||
runningActivities.forEach(function(id) {
|
||||
createNewItem(id, activityInfo.activityName(id), url, activities);
|
||||
});
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
menu.onVisualParentChanged.connect(refresh);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
visible: (visualParent
|
||||
&& plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
|
||||
&& !launcherToggleAction.visible
|
||||
&& activityInfo.numberOfRunningActivities < 2)
|
||||
|
||||
text: i18n("Unpin from Task Manager")
|
||||
icon: "window-unpin"
|
||||
|
||||
onClicked: {
|
||||
tasksModel.requestRemoveLauncher(get(atm.LauncherUrlWithoutIcon));
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
id: moreActionsMenuItem
|
||||
|
||||
visible: (visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true)
|
||||
|
||||
enabled: visible
|
||||
|
||||
text: i18n("More")
|
||||
icon: "view-more-symbolic"
|
||||
|
||||
PlasmaComponents.ContextMenu {
|
||||
visualParent: moreActionsMenuItem.action
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
enabled: menu.visualParent && menu.get(atm.IsMovable) === true
|
||||
|
||||
text: i18n("&Move")
|
||||
icon: "transform-move"
|
||||
|
||||
onClicked: tasksModel.requestMove(menu.modelIndex)
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
enabled: menu.visualParent && menu.get(atm.IsResizable) === true
|
||||
|
||||
text: i18n("Re&size")
|
||||
icon: "transform-scale"
|
||||
|
||||
onClicked: tasksModel.requestResize(menu.modelIndex)
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
visible: (menu.visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true)
|
||||
|
||||
enabled: menu.visualParent && get(atm.IsMaximizable) === true
|
||||
|
||||
checkable: true
|
||||
checked: menu.visualParent && get(atm.IsMaximized) === true
|
||||
|
||||
text: i18n("Ma&ximize")
|
||||
icon: "window-maximize"
|
||||
|
||||
onClicked: tasksModel.requestToggleMaximized(modelIndex)
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
visible: (menu.visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true)
|
||||
|
||||
enabled: menu.visualParent && get(atm.IsMinimizable) === true
|
||||
|
||||
checkable: true
|
||||
checked: menu.visualParent && get(atm.IsMinimized) === true
|
||||
|
||||
text: i18n("Mi&nimize")
|
||||
icon: "window-minimize"
|
||||
|
||||
onClicked: tasksModel.requestToggleMinimized(modelIndex)
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
checkable: true
|
||||
checked: menu.visualParent && menu.get(atm.IsKeepAbove) === true
|
||||
|
||||
text: i18n("Keep &Above Others")
|
||||
icon: "window-keep-above"
|
||||
|
||||
onClicked: tasksModel.requestToggleKeepAbove(menu.modelIndex)
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
checkable: true
|
||||
checked: menu.visualParent && menu.get(atm.IsKeepBelow) === true
|
||||
|
||||
text: i18n("Keep &Below Others")
|
||||
icon: "window-keep-below"
|
||||
|
||||
onClicked: tasksModel.requestToggleKeepBelow(menu.modelIndex)
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
enabled: menu.visualParent && menu.get(atm.IsFullScreenable) === true
|
||||
|
||||
checkable: true
|
||||
checked: menu.visualParent && menu.get(atm.IsFullScreen) === true
|
||||
|
||||
text: i18n("&Fullscreen")
|
||||
icon: "view-fullscreen"
|
||||
|
||||
onClicked: tasksModel.requestToggleFullScreen(menu.modelIndex)
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
enabled: menu.visualParent && menu.get(atm.IsShadeable) === true
|
||||
|
||||
checkable: true
|
||||
checked: menu.visualParent && menu.get(atm.IsShaded) === true
|
||||
|
||||
text: i18n("&Shade")
|
||||
icon: "window-shade"
|
||||
|
||||
onClicked: tasksModel.requestToggleShaded(menu.modelIndex)
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
separator: true
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
visible: (plasmoid.configuration.groupingStrategy !== 0) && menu.get(atm.IsWindow) === true
|
||||
|
||||
checkable: true
|
||||
checked: menu.visualParent && menu.get(atm.IsGroupable) === true
|
||||
|
||||
text: i18n("Allow this program to be grouped")
|
||||
icon: "view-group"
|
||||
|
||||
onClicked: tasksModel.requestToggleGrouping(menu.modelIndex)
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
separator: true
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
property QtObject configureAction: null
|
||||
|
||||
enabled: configureAction && configureAction.enabled
|
||||
visible: configureAction && configureAction.visible
|
||||
|
||||
text: configureAction ? configureAction.text : ""
|
||||
icon: configureAction ? configureAction.icon : ""
|
||||
|
||||
onClicked: configureAction.trigger()
|
||||
|
||||
Component.onCompleted: configureAction = plasmoid.action("configure")
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
property QtObject alternativesAction: null
|
||||
|
||||
enabled: alternativesAction && alternativesAction.enabled
|
||||
visible: alternativesAction && alternativesAction.visible
|
||||
|
||||
text: alternativesAction ? alternativesAction.text : ""
|
||||
icon: alternativesAction ? alternativesAction.icon : ""
|
||||
|
||||
onClicked: alternativesAction.trigger()
|
||||
|
||||
Component.onCompleted: alternativesAction = plasmoid.action("alternatives")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.MenuItem { separator: true }
|
||||
|
||||
PlasmaComponents.MenuItem {
|
||||
id: closeWindowItem
|
||||
visible: (visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true)
|
||||
|
||||
enabled: visualParent && get(atm.IsClosable) === true
|
||||
|
||||
text: i18n("&Close")
|
||||
icon: "window-close"
|
||||
|
||||
onClicked: tasksModel.requestClose(modelIndex)
|
||||
}
|
||||
}
|
|
@ -58,6 +58,7 @@ MouseArea {
|
|||
property real taskHeight: 0
|
||||
property string previousState: ""
|
||||
property bool rightClickDragging: false
|
||||
property bool toolTipOpen: false
|
||||
|
||||
property Item audioStreamOverlay
|
||||
property var audioStreams: []
|
||||
|
@ -153,6 +154,7 @@ MouseArea {
|
|||
}
|
||||
hoverEnabled = true;
|
||||
taskList.updateHoverFunc();
|
||||
toolTipArea.tooltipClicked = true;
|
||||
}
|
||||
|
||||
onContainsMouseChanged: {
|
||||
|
@ -176,6 +178,7 @@ MouseArea {
|
|||
hoverEnabled = true;
|
||||
|
||||
updateMousePosition(ma.mouseX);
|
||||
toolTipArea.tooltipClicked = true;
|
||||
|
||||
}
|
||||
|
||||
|
@ -226,6 +229,9 @@ MouseArea {
|
|||
if (plasmoid.configuration.showToolTips && toolTipArea.active) {
|
||||
hideToolTipTemporarily();
|
||||
}
|
||||
/*if(childCount >= 2 && plasmoid.configuration.showToolTips && toolTipArea.active) {
|
||||
toolTipArea.tooltipClicked = !toolTipArea.tooltipClicked;
|
||||
}*/
|
||||
TaskTools.activateTask(modelIndex(), model, mouse.modifiers, task);
|
||||
|
||||
} else if (mouse.button === Qt.BackButton || mouse.button === Qt.ForwardButton) {
|
||||
|
@ -452,7 +458,7 @@ MouseArea {
|
|||
opacity: 0.6
|
||||
visible: childCount >= 3 ? true : false
|
||||
anchors.rightMargin: PlasmaCore.Units.smallSpacing
|
||||
enabledBorders: Plasma.FrameSvg.EnabledBorders.RightBorder
|
||||
enabledBorders: PlasmaCore.FrameSvg.RightBorder
|
||||
|
||||
}
|
||||
|
||||
|
@ -711,8 +717,8 @@ MouseArea {
|
|||
PlasmaCore.ToolTipArea {
|
||||
id: toolTipArea
|
||||
z: -1
|
||||
//backgroundHints: "SolidBackground"
|
||||
MouseArea {
|
||||
|
||||
MouseArea {
|
||||
id: ma
|
||||
hoverEnabled: true
|
||||
propagateComposedEvents: true
|
||||
|
@ -720,34 +726,32 @@ MouseArea {
|
|||
onPositionChanged: {
|
||||
task.updateMousePosition(ma.mouseX);
|
||||
task.positionChanged(mouse);
|
||||
//var xtr = toolTipArea.backgroundHints();
|
||||
|
||||
}
|
||||
onContainsMouseChanged: {
|
||||
|
||||
task.updateMousePosition(ma.mouseX);
|
||||
//task.onContainsMouseChanged();
|
||||
//toolTipArea.onContainsMouseChanged();
|
||||
//mouse.accepted = false;
|
||||
}
|
||||
onPressed: mouse.accepted = false;
|
||||
onReleased: mouse.accepted = false;
|
||||
onWheel: wheel.accepted = false;
|
||||
//onExited: { hoverGradient.horizontalOffset = 0;
|
||||
//task.onExited();
|
||||
//}
|
||||
}
|
||||
anchors.fill: parent
|
||||
location: plasmoid.location
|
||||
|
||||
active: !inPopup && !groupDialog.visible && plasmoid.configuration.showToolTips
|
||||
property bool tooltipClicked: true
|
||||
active: !inPopup && !groupDialog.visible && (plasmoid.configuration.showToolTips || tasks.toolTipOpenedByClick === toolTipArea)
|
||||
interactive: model.IsWindow === true
|
||||
|
||||
mainItem: (model.IsWindow === true) ? openWindowToolTipDelegate : pinnedAppToolTipDelegate
|
||||
property alias mainToolTip: toolTipArea.mainItem
|
||||
onToolTipVisibleChanged: {
|
||||
task.toolTipOpen = toolTipVisible;
|
||||
if(!toolTipVisible) {
|
||||
tasks.toolTipOpenedByClick = null;
|
||||
} else {
|
||||
tasks.toolTipAreaItem = toolTipArea;
|
||||
}
|
||||
|
||||
}
|
||||
onContainsMouseChanged: {
|
||||
|
||||
updateMousePosition(ma.mouseX);
|
||||
if (containsMouse) {
|
||||
mainItem.parentTask = task;
|
||||
|
@ -802,6 +806,9 @@ MouseArea {
|
|||
mainItem.smartLauncherCount = Qt.binding(function() {
|
||||
return mainItem.smartLauncherCountVisible ? task.smartLauncherItem.count : 0;
|
||||
});
|
||||
tasks.toolTipAreaItem = toolTipArea;
|
||||
} else {
|
||||
tasks.toolTipOpenedByClick = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,11 @@ function activateTask(index, model, modifiers, task) {
|
|||
else if (plasmoid.configuration.showToolTips
|
||||
&& plasmoid.configuration.groupedTaskVisualization === 1
|
||||
) {
|
||||
task.showToolTip();
|
||||
if(tasks.toolTipOpenedByClick) tasks.toolTipOpenedByClick.hideImmediately();
|
||||
else {
|
||||
tasks.toolTipOpenedByClick = task.toolTipAreaItem;
|
||||
task.showToolTip();
|
||||
}
|
||||
}
|
||||
|
||||
// Option 3: show Present Windows for all child tasks
|
||||
|
|
|
@ -27,7 +27,8 @@ MouseArea {
|
|||
// This property tells the plasmoid to render labels next to task icons.
|
||||
// Previously, this property was determined by the value of (plasmoid.pluginName === "org.kde.plasma.icontasks")
|
||||
property bool iconsOnly: !plasmoid.configuration.labelVisible
|
||||
|
||||
property var toolTipOpenedByClick: null
|
||||
property var toolTipAreaItem: null
|
||||
//property QtObject contextMenuComponent: Qt.createComponent("ContextMenu.qml");
|
||||
property QtObject tasksMenuComponent: Qt.createComponent("TasksMenu.qml");
|
||||
property QtObject pulseAudioComponent: Qt.createComponent("PulseAudio.qml");
|
||||
|
@ -60,6 +61,7 @@ MouseArea {
|
|||
|
||||
signal requestLayout
|
||||
signal windowsHovered(variant winIds, bool hovered)
|
||||
signal activateWindowView(variant winIds)
|
||||
signal presentWindows(variant winIds)
|
||||
|
||||
states: State {
|
||||
|
@ -511,10 +513,12 @@ MouseArea {
|
|||
// With this, we can update each task icon pretty much globally.
|
||||
function updateHoverFunc() {
|
||||
for(var i = 0; i < taskRepeater.count; i++) {
|
||||
taskRepeater.itemAt(i).updateHoverColor();
|
||||
if(taskRepeater.itemAt(i)) {
|
||||
taskRepeater.itemAt(i).updateHoverColor();
|
||||
}
|
||||
}
|
||||
tasks.state = "";
|
||||
console.log("Updated hovers");
|
||||
//console.log("Updated hovers");
|
||||
}
|
||||
|
||||
Timer {
|
||||
|
@ -604,7 +608,8 @@ MouseArea {
|
|||
tasks.requestLayout.connect(layoutTimer.restart);
|
||||
tasks.requestLayout.connect(iconGeometryTimer.restart);
|
||||
tasks.windowsHovered.connect(backend.windowsHovered);
|
||||
tasks.presentWindows.connect(backend.presentWindows);
|
||||
//tasks.presentWindows.connect(backend.presentWindows);
|
||||
tasks.activateWindowView.connect(backend.activateWindowView);
|
||||
dragHelper.dropped.connect(resetDragSource);
|
||||
taskList.updateHoverFunc();
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ Lastly, feel free to fork this project and/or contribute to it in any way. Any a
|
|||
|
||||
<img src="Screenshots/Taskbar.png">
|
||||
<img src="Screenshots/Taskbar_2.png">
|
||||
<img src="Screenshots/Taskbar_3.png">
|
||||
|
||||
### Clock
|
||||
|
||||
|
|
BIN
Screenshots/Taskbar_3.png
Normal file
After Width: | Height: | Size: 28 KiB |