diff --git a/applets/taskmanager/package/contents/ui/Task.qml b/applets/taskmanager/package/contents/ui/Task.qml index acc97bed6..fd4e60893 100644 --- a/applets/taskmanager/package/contents/ui/Task.qml +++ b/applets/taskmanager/package/contents/ui/Task.qml @@ -1,434 +1,442 @@ /*************************************************************************** * Copyright (C) 2012-2013 by Eike Hein * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ import QtQuick 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.draganddrop 2.0 import org.kde.plasma.private.taskmanager 0.1 as TaskManager import "../code/layout.js" as LayoutManager import "../code/tools.js" as TaskTools MouseArea { id: task width: groupDialog.mainItem.width height: units.iconSizes.small + LayoutManager.verticalMargins() visible: false LayoutMirroring.enabled: (Qt.application.layoutDirection == Qt.RightToLeft) LayoutMirroring.childrenInherit: (Qt.application.layoutDirection == Qt.RightToLeft) property int itemIndex: index property int itemId: model.Id property bool inPopup: false property bool isGroupParent: model.hasModelChildren property bool isLauncher: model.IsLauncher property bool isStartup: model.IsStartup property bool demandsAttention: model.DemandsAttention property bool showingContextMenu: false property int textWidth: label.implicitWidth property bool pressed: false property int pressX: -1 property int pressY: -1 property Item busyIndicator property int wheelDelta: 0 readonly property bool smartLauncherEnabled: plasmoid.configuration.smartLaunchersEnabled && !inPopup && !isStartup property QtObject smartLauncherItem: null acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MidButton hoverEnabled: true onItemIndexChanged: { if (!inPopup && !tasks.vertical && LayoutManager.calculateStripes() > 1) { var newWidth = LayoutManager.taskWidth(); if (index == backend.tasksModel.launcherCount) { newWidth += LayoutManager.launcherLayoutWidthDiff(); } width = newWidth; } } onIsStartupChanged: { if (!isStartup) { tasks.itemGeometryChanged(task, itemId); busyIndicator.visible = false; busyIndicator.running = false; icon.visible = true; } } onDemandsAttentionChanged: { tasks.updateStatus(demandsAttention); } onContainsMouseChanged: { if (!containsMouse) { pressed = false; } tasks.itemHovered(model.Id, containsMouse); } onPressed: { if (mouse.button == Qt.LeftButton || mouse.button == Qt.MidButton) { pressed = true; pressX = mouse.x; pressY = mouse.y; } else if (mouse.button == Qt.RightButton) { if (plasmoid.configuration.showToolTips) { toolTip.hideToolTip(); } showingContextMenu = true; tasks.itemContextMenu(task, plasmoid.action("configure")); } } onReleased: { if (pressed) { if (mouse.button == Qt.MidButton) { if (plasmoid.configuration.middleClickAction == TaskManager.Backend.NewInstance) { tasks.launchNewInstance(model.Id); } else if (plasmoid.configuration.middleClickAction == TaskManager.Backend.Close) { tasks.closeByItemId(model.Id); } } else if (mouse.button == Qt.LeftButton) { if (mouse.modifiers & Qt.ShiftModifier) { tasks.launchNewInstance(model.Id); } else if (isGroupParent) { if ((iconsOnly || mouse.modifiers == Qt.ControlModifier) && backend.canPresentWindows()) { tasks.presentWindows(model.Id); } else if (groupDialog.visible) { groupDialog.visible = false; } else { groupDialog.visualParent = task; groupDialog.visible = true; } } else { tasks.activateItem(model.Id, true); } } } pressed = false; pressX = -1; pressY = -1; } onPositionChanged: { if (pressX != -1 && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { tasks.dragSource = task; dragHelper.startDrag(task, model.MimeType, model.MimeData, model.LauncherUrl, model.DecorationRole); pressX = -1; pressY = -1; return; } } onWheel: { if (plasmoid.configuration.wheelEnabled) { wheelDelta = TaskTools.wheelActivateNextPrevTask(task, wheelDelta, wheel.angleDelta.y); } } onSmartLauncherEnabledChanged: { if (smartLauncherEnabled && !smartLauncherItem) { var smartLauncher = Qt.createQmlObject(" import org.kde.plasma.private.taskmanager 0.1 as TaskManager; TaskManager.SmartLauncherItem { }", task); smartLauncher.launcherUrl = Qt.binding(function() { return model.LauncherUrl; }); smartLauncherItem = smartLauncher; } } Connections { target: backend onShowingContextMenuChanged: { if (task.showingContextMenu && !backend.showingContextMenu) { task.showingContextMenu = false; } } } PlasmaCore.FrameSvgItem { id: frame anchors { fill: parent topMargin: (!tasks.vertical && taskList.rows > 1) ? units.smallSpacing / 4 : 0 bottomMargin: (!tasks.vertical && taskList.rows > 1) ? units.smallSpacing / 4 : 0 leftMargin: ((inPopup || tasks.vertical) && taskList.columns > 1) ? units.smallSpacing / 4 : 0 rightMargin: ((inPopup || tasks.vertical) && taskList.columns > 1) ? units.smallSpacing / 4 : 0 } imagePath: "widgets/tasks" property string basePrefix: "normal" prefix: TaskTools.taskPrefix("normal") onRepaintNeeded: prefix = TaskTools.taskPrefix(basePrefix); onBasePrefixChanged: prefix = TaskTools.taskPrefix(basePrefix); PlasmaCore.ToolTipArea { id: toolTip anchors.fill: parent active: !inPopup && !groupDialog.visible && plasmoid.configuration.showToolTips interactive: true location: plasmoid.location mainItem: toolTipDelegate //FIXME TODO: highlightWindows: plasmoid.configuration.highlightWindows onContainsMouseChanged: { if (containsMouse) { toolTipDelegate.windows = model.WindowList; toolTipDelegate.mainText = model.DisplayRole; toolTipDelegate.icon = model.DecorationRole; toolTipDelegate.subText = model.IsLauncher ? model.GenericName : toolTip.generateSubText(model); toolTipDelegate.launcherUrl = model.LauncherUrl; } } function generateSubText(task) { var subTextEntries = new Array(); if (!plasmoid.configuration.showOnlyCurrentDesktop && backend.numberOfDesktops() > 1) { subTextEntries.push(i18n("On %1", task.DesktopName)); } if (task.OnAllActivities && backend.numberOfActivities() > 1) { subTextEntries.push(i18nc("Which virtual desktop a window is currently on", "Available on all activities")); } else if (plasmoid.configuration.showOnlyCurrentActivity) { if (task.OtherActivityNames.length > 0) { subTextEntries.push(i18nc("Activities a window is currently on (apart from the current one)", "Also available on %1", task.OtherActivityNames.join(", "))); } } else if (task.ActivityNames.length > 0) { subTextEntries.push(i18nc("Which activities a window is currently on", "Available on %1", task.ActivityNames.join(", "))); } return subTextEntries.join("\n"); } + + Connections { + target: toolTip.containsMouse ? label : null + + onTextChanged: { + toolTipDelegate.mainText = label.text; + } + } } } Loader { anchors.fill: frame asynchronous: true source: "TaskProgressOverlay.qml" active: plasmoid.configuration.smartLaunchersEnabled && task.smartLauncherItem && task.smartLauncherItem.progressVisible } Item { id: iconBox anchors { left: parent.left leftMargin: tasks.vertical && !label.visible ? adjustMargin(true, parent.width, taskFrame.margins.left) : taskFrame.margins.left top: parent.top topMargin: adjustMargin(false, parent.height, taskFrame.margins.top); bottom: parent.bottom bottomMargin: adjustMargin(false, parent.height, taskFrame.margins.bottom); right: (tasks.vertical && !label.visible && !inPopup) ? parent.right : undefined rightMargin: tasks.vertical && !label.visible ? adjustMargin(true, parent.width, taskFrame.margins.right) : undefined } function adjustMargin(vert, size, margin) { if (!size) { return margin; } var margins = vert ? LayoutManager.horizontalMargins() : LayoutManager.verticalMargins(); if ((size - margins) < units.iconSizes.small) { return Math.ceil((margin * (units.iconSizes.small / size)) / 2); } return margin; } width: inPopup ? units.iconSizes.small : Math.min(height, parent.width - LayoutManager.horizontalMargins()) PlasmaCore.IconItem { id: icon anchors.fill: parent visible: false active: task.containsMouse || task.showingContextMenu enabled: true usesPlasmaTheme: false source: model.DecorationRole onVisibleChanged: { if (visible && busyIndicator) { busyIndicator.destroy(); } } } Loader { anchors.fill: icon asynchronous: true source: "TaskBadgeOverlay.qml" active: plasmoid.configuration.smartLaunchersEnabled && height >= units.iconSizes.small && icon.visible && task.smartLauncherItem && task.smartLauncherItem.countVisible } PlasmaComponents.BusyIndicator { id: busyIndicator anchors.fill: parent visible: false running: false } states: [ // Using a state transition avoids a binding loop between label.visible and // the text label margin, which derives from the icon width. State { name: "standalone" when: !label.visible AnchorChanges { target: iconBox anchors.left: undefined anchors.horizontalCenter: parent.horizontalCenter } PropertyChanges { target: iconBox anchors.leftMargin: 0 } } ] } TaskManager.TextLabel { id: label anchors { fill: parent leftMargin: taskFrame.margins.left + iconBox.width + units.smallSpacing topMargin: taskFrame.margins.top rightMargin: taskFrame.margins.right bottomMargin: taskFrame.margins.bottom } visible: (inPopup || !iconsOnly && !model.IsLauncher && (parent.width - LayoutManager.horizontalMargins()) >= (theme.mSize(theme.defaultFont).width * 7)) enabled: true text: (!inPopup && iconsOnly) ? "" : model.DisplayRole color: theme.textColor elide: !inPopup } states: [ State { name: "launcher" when: model.IsLauncher PropertyChanges { target: frame basePrefix: "" } }, State { name: "hovered" when: containsMouse || showingContextMenu PropertyChanges { target: frame basePrefix: "hover" } }, State { name: "attention" when: model.DemandsAttention || (task.smartLauncherItem && task.smartLauncherItem.urgent) PropertyChanges { target: frame basePrefix: "attention" } }, State { name: "minimized" when: model.Minimized && !(groupDialog.visible && groupDialog.target == task) PropertyChanges { target: frame basePrefix: "minimized" } }, State { name: "active" when: model.Active || groupDialog.visible && groupDialog.target == task PropertyChanges { target: frame basePrefix: "focus" } } ] Component.onCompleted: { if (model.IsStartup) { busyIndicator.running = true; busyIndicator.visible = true; } else { icon.visible = true; } if (model.hasModelChildren) { var component = Qt.createComponent("GroupExpanderOverlay.qml"); component.createObject(task); } } /* Component.onDestruction: { if (groupDialog.visible && groupDialog.groupItemId == model.Id) { groupDialog.visible = false; } } */ } diff --git a/kcms/lookandfeel/autotests/lookandfeel/metadata.desktop b/kcms/lookandfeel/autotests/lookandfeel/metadata.desktop index 483af6a3e..175babd11 100644 --- a/kcms/lookandfeel/autotests/lookandfeel/metadata.desktop +++ b/kcms/lookandfeel/autotests/lookandfeel/metadata.desktop @@ -1,98 +1,77 @@ [Desktop Entry] Comment=Test Look and Feel package Comment[ast]=Paquete d'aspeutu y sentir de prueba Comment[bs]=Test paketa Pogledaj i Osjeti Comment[ca]=Prova el paquet d'aspecte i comportament Comment[ca@valencia]=Prova el paquet d'aspecte i comportament -Comment[cs]=Otestovat balíček vzhledu a chování Comment[da]=Test pakke med udseende og fremtoning Comment[de]=Testpaket für das Erscheinungsbild Comment[el]=Δοκιμή του πακέτου εμφάνισης και αίσθησης Comment[en_GB]=Test Look and Feel package Comment[es]=Probar paquete de aspecto visual Comment[et]=Välimuse testimine Comment[fi]=Ulkoasun ja tuntuman testipaketti Comment[fr]=Tester le paquet d'apparence Comment[gl]=Paquete de aparencia e comportamento de probas Comment[hu]=A megjelenés csomag tesztelése Comment[id]=Paket Tes Lihat dan Rasakan Comment[it]=Prova il pacchetto dell'aspetto Comment[ja]=外観パッケージをテスト Comment[ko]=모습과 느낌 테스트 패키지 -Comment[lt]=Bandyti išvaizdos ir pojūčio paketą -Comment[nb]=Test pakka Utseende og oppførsel Comment[nds]=Test-Utsehn- un Bedenen-Paket Comment[nl]=Pakket voor uiterlijk en gedrag testen -Comment[nn]=Testpakke for utsjånad og åtferd Comment[pl]=Wypróbuj pakiet wrażeń wzrokowych i dotykowych Comment[pt]=Pacote de teste da Aparência e Comportamento -Comment[pt_BR]=Pacote de teste de Aparência Comment[ru]=Тестовое оформление рабочей среды Comment[sk]=Balík pre vzhľad a nastavenie Comment[sl]=Preizkusni paket za Videz in občutek -Comment[sr]=Пробни пакет изгледа и осећаја -Comment[sr@ijekavian]=Пробни пакет изгледа и осећаја -Comment[sr@ijekavianlatin]=Probni paket izgleda i osećaja -Comment[sr@latin]=Probni paket izgleda i osećaja Comment[sv]=Prova paket för utseende och känsla Comment[tr]=Görünüm ve Duyum paketini dene Comment[uk]=Перевірка пакунка вигляду і поведінки -Comment[x-test]=xxTest Look and Feel packagexx Comment[zh_CN]=测试观感包 Comment[zh_TW]=測試外觀與感覺套件 Encoding=UTF-8 Name=Test Name[bs]=Test Name[ca]=Prova Name[ca@valencia]=Prova -Name[cs]=Otestovat Name[da]=Test Name[de]=Test Name[el]=Δοκιμή Name[en_GB]=Test Name[es]=Probar Name[et]=Test Name[fi]=Testi Name[fr]=Tester Name[gl]=Proba Name[hu]=Teszt Name[id]=Tes Name[it]=Prova Name[ja]=テスト Name[ko]=시험 -Name[lt]=Testas -Name[nb]=Test Name[nds]=Test Name[nl]=Test -Name[nn]=Test Name[pa]=ਟੈਸਟ Name[pl]=Próba Name[pt]=Teste -Name[pt_BR]=Teste Name[ru]=Тест -Name[se]=Geahččaleapmi Name[sk]=Test Name[sl]=Preizkus -Name[sr]=Проба -Name[sr@ijekavian]=Проба -Name[sr@ijekavianlatin]=Proba -Name[sr@latin]=Proba Name[sv]=Prova Name[tr]=Test Name[uk]=Тест -Name[x-test]=xxTestxx Name[zh_CN]=测试 Name[zh_TW]=測試 Type=Service X-KDE-ServiceTypes=Plasma/LookAndFeel X-KDE-ParentApp= X-KDE-PluginInfo-Author=KDE Visual Design Group X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Email=plasma-devel@kde.org X-KDE-PluginInfo-License=GPLv2+ X-KDE-PluginInfo-Name=org.kde.test X-KDE-PluginInfo-Version=2.0 X-KDE-PluginInfo-Website=http://www.kde.org X-Plasma-MainScript=defaults diff --git a/toolboxes/desktoptoolbox/contents/ui/ToolBoxButton.qml b/toolboxes/desktoptoolbox/contents/ui/ToolBoxButton.qml index 378c6ed96..7cf4098b4 100644 --- a/toolboxes/desktoptoolbox/contents/ui/ToolBoxButton.qml +++ b/toolboxes/desktoptoolbox/contents/ui/ToolBoxButton.qml @@ -1,306 +1,311 @@ /*************************************************************************** * Copyright 2012,2015 by Sebastian Kügler * * Copyright 2015 by Kai Uwe Broulik * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.4 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons import org.kde.plasma.plasmoid 2.0 Item { id: toolBoxButton property string text: main.Plasmoid.activityName property bool isCorner: !buttonMouse.dragging && ((state == "topleft") || (state == "topright") || (state == "bottomright") || (state == "bottomleft")) property bool isHorizontal: (state != "left" && state != "right") rotation: switch(state) { case "left": return -90; case "right": return 90; default: return 0; } transform: Translate { x: state == "left" ? Math.round(-width/2 + height/2) : state == "right" ? + Math.round(width/2 - height/2) : 0 Behavior on x { NumberAnimation { duration: units.shortDuration * 3; easing.type: Easing.InOutExpo; } } } transformOrigin: Item.Center Behavior on rotation { NumberAnimation { duration: units.shortDuration * 3; easing.type: Easing.InOutExpo; } enabled: visible } Behavior on x { NumberAnimation { duration: units.shortDuration * 3; easing.type: Easing.InOutExpo; } enabled: visible } Behavior on y { NumberAnimation { duration: units.shortDuration * 3; easing.type: Easing.InOutExpo; } enabled: visible } - width: buttonLayout.width + (buttonLayout.width % 2) - height: buttonLayout.height + (buttonLayout.height % 2) + clip: true + width: backgroundFrame.width + height: backgroundFrame.height //x and y default to 0, so top left would be correct //If the position is anything else it will updated via onXChanged during intialisation state: "topleft" onXChanged: stateTimer.restart() onYChanged: stateTimer.restart() Timer { id: stateTimer interval: 100 onTriggered: updateState() } function updateState() { var container = main; //print(" w: " + container.width +"x"+container.height+" : "+x+"/"+y+" tbw: " + toolBoxButton.width); var x = toolBoxButton.x - main.x; var y = toolBoxButton.y - main.y; var cornerSnap = iconWidth if (x < cornerSnap && y < cornerSnap) { toolBoxButton.state = "topleft"; } else if (container.width - x - buttonLayout.width < cornerSnap && y < cornerSnap) { toolBoxButton.state = "topright"; } else if (container.width - x - buttonLayout.width < cornerSnap && container.height - y - buttonLayout.width < cornerSnap) { toolBoxButton.state = "bottomright"; } else if (x < cornerSnap && container.height - y - buttonLayout.width < cornerSnap) { toolBoxButton.state = "bottomleft"; //top diagonal half } else if (x > (y * (container.width/container.height))) { //Top edge if (container.width - x > y ) { toolBoxButton.state = "top"; //right edge } else { //toolBoxButton.transformOrigin = Item.BottomRight toolBoxButton.state = "right"; } //bottom diagonal half } else { //Left edge if (container.height - y > x ) { //toolBoxButton.transformOrigin = Item.TopLeft toolBoxButton.state = "left"; //Bottom edge } else { toolBoxButton.state = "bottom"; } } if (!buttonMouse.pressed) { main.placeToolBox(toolBoxButton.state); } } PlasmaCore.FrameSvgItem { id: backgroundFrame - imagePath: isCorner ? "widgets/translucentbackground" : "widgets/background" + anchors { + left: parent.left + top: parent.top + } + imagePath: "widgets/translucentbackground" opacity: buttonMouse.containsMouse || (toolBoxLoader.item && toolBoxLoader.item.visible) ? 1.0 : 0.4 - x: -margins.left - y: -margins.top width: (isCorner ? buttonLayout.height : buttonLayout.width) + margins.left + margins.right height: buttonLayout.height + margins.top + margins.bottom Behavior on width { NumberAnimation { duration: units.longDuration; easing.type: Easing.InOutQuad; } } Behavior on opacity { NumberAnimation { duration: units.longDuration; } } } Row { id: buttonLayout - - //when in the corner centre in the middle of the remaining space - //the visible space is the width of the background frame + one margin, the other is offscreen - //we want to work out the offset which is the visible frame width - our icon width / 2 - //X is relative to the start of button, but the frame is one marging wider to the left so this needs taking into account - x: isCorner ? Math.round((parent.width - width) / 2 + units.smallSpacing) : 0 - + anchors.centerIn: parent + height: Math.max(toolBoxIcon.height, fontMetrics.height) spacing: units.smallSpacing Behavior on x { NumberAnimation { duration: units.longDuration; easing.type: Easing.InOutQuad; } } PlasmaCore.SvgItem { id: toolBoxIcon svg: PlasmaCore.Svg { id: iconSvg imagePath: "widgets/configuration-icons" onRepaintNeeded: toolBoxIcon.elementId = iconSvg.hasElement("menu") ? "menu" : "configure" } elementId: iconSvg.hasElement("menu") ? "menu" : "configure" anchors.verticalCenter: parent.verticalCenter width: iconSize height: iconSize opacity: buttonMouse.containsMouse || (toolBoxLoader.item && toolBoxLoader.item.visible) ? 1 : 0.5 rotation: isHorizontal ? 0 : -90; transformOrigin: Item.Center Behavior on opacity { NumberAnimation { duration: units.longDuration; easing.type: Easing.InOutExpo; } } } PlasmaComponents.Label { id: activityName + anchors.verticalCenter: parent.verticalCenter opacity: isCorner ? 0 : 1 text: toolBoxButton.text + visible: opacity Behavior on opacity { //only have this animation when going from hidden -> shown enabled: activityName.opacity == 0 SequentialAnimation { //pause to allow the toolbox frame to resize //otherwise we see the text overflow the box //whilst that animates PauseAnimation { duration: units.longDuration } NumberAnimation { duration: units.shortDuration easing.type: Easing.InOutExpo } } } } + + FontMetrics { + id: fontMetrics + font: activityName.font + } } MouseArea { id: buttonMouse property QtObject container: main property int pressedX property int pressedY property bool dragging: false anchors { fill: parent margins: -10 } drag { target: main.Plasmoid.immutable ? undefined : toolBoxButton minimumX: 0 maximumX: container.width - toolBoxIcon.width minimumY: 0 maximumY: container.height - toolBoxIcon.height } hoverEnabled: true onPressed: { pressedX = toolBoxButton.x pressedY = toolBoxButton.y } onPositionChanged: { if (pressed && (Math.abs(toolBoxButton.x - pressedX) > iconSize || Math.abs(toolBoxButton.y - pressedY) > iconSize)) { dragging = true; } } onClicked: { plasmoid.contextualActionsAboutToShow(); toolBoxLoader.active = true // the dialog auto-closes on losing focus toolBoxLoader.item.visible = !main.dialogWasVisible plasmoid.focus = true; } onReleased: { main.Plasmoid.configuration.ToolBoxButtonState = toolBoxButton.state; main.Plasmoid.configuration.ToolBoxButtonX = toolBoxButton.x; main.Plasmoid.configuration.ToolBoxButtonY = toolBoxButton.y; //print("Saved coordinates for ToolBox in config: " + toolBoxButton.x + ", " +toolBoxButton.x); if (dragging) { main.placeToolBox(); } dragging = false; stateTimer.stop(); updateState(); } onCanceled: dragging = false; } states: [ State { name: "topleft" }, State { name: "top" }, State { name: "topright" }, State { name: "right" }, State { name: "bottomright" }, State { name: "bottom" }, State { name: "bottomleft" }, State { name: "topleft" }, State { name: "left" } ] }