diff --git a/applets/kickoff/package/contents/ui/FullRepresentation.qml b/applets/kickoff/package/contents/ui/FullRepresentation.qml index 62dd387d9..64e7c9ab1 100644 --- a/applets/kickoff/package/contents/ui/FullRepresentation.qml +++ b/applets/kickoff/package/contents/ui/FullRepresentation.qml @@ -1,795 +1,796 @@ /* Copyright (C) 2011 Martin Gräßlin Copyright (C) 2012 Gregor Taetzner Copyright (C) 2012 Marco Martin Copyright (C) 2013 2014 David Edmundson Copyright 2014 Sebastian Kügler 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.3 import org.kde.plasma.plasmoid 2.0 import QtQuick.Layouts 1.1 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.kquickcontrolsaddons 2.0 import org.kde.plasma.private.kicker 0.1 as Kicker Item { id: root Layout.minimumWidth: units.gridUnit * 26 Layout.maximumWidth: Layout.minimumWidth Layout.minimumHeight: units.gridUnit * 34 Layout.maximumHeight: Layout.minimumHeight property string previousState property bool switchTabsOnHover: plasmoid.configuration.switchTabsOnHover property Item currentView: mainTabGroup.currentTab.decrementCurrentIndex ? mainTabGroup.currentTab : mainTabGroup.currentTab.item property KickoffButton firstButton: null property var configMenuItems property QtObject globalFavorites: rootModelFavorites state: "Normal" onFocusChanged: { header.input.forceActiveFocus(); } function switchToInitial() { if (firstButton != null) { root.state = "Normal"; mainTabGroup.currentTab = firstButton.tab; tabBar.currentTab = firstButton; header.query = "" } } Kicker.DragHelper { id: dragHelper dragIconSize: units.iconSizes.medium onDropped: kickoff.dragSource = null } Kicker.AppsModel { id: rootModel autoPopulate: false appletInterface: plasmoid appNameFormat: plasmoid.configuration.showAppsByName ? 0 : 1 flat: false sorted: plasmoid.configuration.alphaSort showSeparators: false showTopLevelItems: true favoritesModel: Kicker.KAStatsFavoritesModel { id: rootModelFavorites favorites: plasmoid.configuration.favorites onFavoritesChanged: { plasmoid.configuration.favorites = favorites; } } Component.onCompleted: { favoritesModel.initForClient("org.kde.plasma.kickoff.favorites.instance-" + plasmoid.id) if (!plasmoid.configuration.favoritesPortedToKAstats) { favoritesModel.portOldFavorites(plasmoid.configuration.favorites); plasmoid.configuration.favoritesPortedToKAstats = true; } rootModel.refresh(); } } PlasmaCore.DataSource { id: pmSource engine: "powermanagement" connectedSources: ["PowerDevil"] } PlasmaCore.Svg { id: arrowsSvg imagePath: "widgets/arrows" size: "16x16" } Header { id: header } PlasmaCore.SvgItem { id: headerSeparator anchors { top: header.top horizontalCenter: header.horizontalCenter } height: headerSeparatorLine.elementSize("horizontal-line").height width: root.width - 2 * units.gridUnit elementId: "horizontal-line" svg: PlasmaCore.Svg { id: headerSeparatorLine imagePath: "widgets/line" } } Item { id: mainArea anchors.topMargin: mainTabGroup.state == "top" ? units.smallSpacing : 0 PlasmaComponents.TabGroup { id: mainTabGroup currentTab: favoritesPage anchors { fill: parent } //pages FavoritesView { id: favoritesPage } PlasmaExtras.ConditionalLoader { id: applicationsPage when: mainTabGroup.currentTab == applicationsPage source: Qt.resolvedUrl("ApplicationsView.qml") } PlasmaExtras.ConditionalLoader { id: systemPage when: mainTabGroup.currentTab == systemPage source: Qt.resolvedUrl("ComputerView.qml") } PlasmaExtras.ConditionalLoader { id: recentlyUsedPage when: mainTabGroup.currentTab == recentlyUsedPage source: Qt.resolvedUrl("RecentlyUsedView.qml") } PlasmaExtras.ConditionalLoader { id: oftenUsedPage when: mainTabGroup.currentTab == oftenUsedPage source: Qt.resolvedUrl("OftenUsedView.qml") } PlasmaExtras.ConditionalLoader { id: leavePage when: mainTabGroup.currentTab == leavePage source: Qt.resolvedUrl("LeaveView.qml") } PlasmaExtras.ConditionalLoader { id: searchPage when: root.state == "Search" //when: mainTabGroup.currentTab == searchPage || root.state == "Search" source: Qt.resolvedUrl("SearchView.qml") } state: { switch (plasmoid.location) { case PlasmaCore.Types.LeftEdge: return LayoutMirroring.enabled ? "right" : "left"; case PlasmaCore.Types.TopEdge: return "top"; case PlasmaCore.Types.RightEdge: return LayoutMirroring.enabled ? "left" : "right"; case PlasmaCore.Types.BottomEdge: default: return "bottom"; } } states: [ State { name: "left" AnchorChanges { target: header anchors { left: root.left top: undefined right: root.right bottom: root.bottom } } PropertyChanges { target: header width: header.implicitWidth } AnchorChanges { target: mainArea anchors { left: tabBar.right top: root.top right: root.right bottom: header.top } } PropertyChanges { target: tabBar width: (tabBar.opacity == 0) ? 0 : units.gridUnit * 5 } AnchorChanges { target: tabBar anchors { left: root.left top: root.top right: undefined bottom: header.top } } PropertyChanges { target:tabBarSeparator width: tabBarSeparatorLine.elementSize("vertical-line").width elementId: "vertical-line" } AnchorChanges { target: tabBarSeparator anchors { left: tabBar.right top: tabBar.top bottom:tabBar.bottom } } }, State { name: "top" AnchorChanges { target: header anchors { left: root.left top: undefined right: root.right bottom: root.bottom } } PropertyChanges { target: header height: header.implicitHeight } AnchorChanges { target: mainArea anchors { left: root.left top: tabBar.bottom right: root.right bottom: header.top } } PropertyChanges { target: tabBar height: (tabBar.opacity == 0) ? 0 : units.gridUnit * 5 } AnchorChanges { target: tabBar anchors { left: root.left top: root.top right: root.right bottom: undefined } } PropertyChanges { target:tabBarSeparator height: tabBarSeparatorLine.elementSize("horizontal-line").height elementId: "horizontal-line" } AnchorChanges { target: tabBarSeparator anchors { left: tabBar.left right: tabBar.right top: tabBar.bottom } } }, State { name: "right" AnchorChanges { target: header anchors { left: root.left top: undefined right: root.right bottom: root.bottom } } PropertyChanges { target: header width: header.implicitWidth } AnchorChanges { target: mainArea anchors { left: root.left top: root.top right: tabBar.left bottom: header.top } } PropertyChanges { target: tabBar width: (tabBar.opacity == 0) ? 0 : units.gridUnit * 5 } AnchorChanges { target: tabBar anchors { left: undefined top: root.top right: root.right bottom: header.top } } PropertyChanges { target:tabBarSeparator width: tabBarSeparatorLine.elementSize("vertical-line").width elementId: "vertical-line" } AnchorChanges { target: tabBarSeparator anchors { right: tabBar.left top: tabBar.top bottom: tabBar.bottom } } }, State { name: "bottom" AnchorChanges { target: header anchors { left: root.left top: root.top right: root.right bottom: undefined } } PropertyChanges { target: header height: header.implicitHeight } AnchorChanges { target: headerSeparator anchors { top: undefined bottom: header.bottom } } AnchorChanges { target: mainArea anchors { left: root.left top: header.bottom right: root.right bottom: tabBar.top } } PropertyChanges { target: tabBar height: (tabBar.opacity == 0) ? 0 : units.gridUnit * 5 } AnchorChanges { target: tabBar anchors { left: root.left top: undefined right: root.right bottom: root.bottom } } PropertyChanges { target:tabBarSeparator height: tabBarSeparatorLine.elementSize("horizontal-line").height elementId: "horizontal-line" } AnchorChanges { target: tabBarSeparator anchors { bottom: tabBar.top left: tabBar.left right: tabBar.right } } } ] } // mainTabGroup } PlasmaComponents.TabBar { id: tabBar property int count: 5 // updated in createButtons() Behavior on width { NumberAnimation { duration: units.longDuration; easing.type: Easing.InQuad; } enabled: plasmoid.expanded } Behavior on height { NumberAnimation { duration: units.longDuration; easing.type: Easing.InQuad; } enabled: plasmoid.expanded } tabPosition: { switch (plasmoid.location) { case PlasmaCore.Types.TopEdge: return Qt.TopEdge; case PlasmaCore.Types.LeftEdge: return Qt.LeftEdge; case PlasmaCore.Types.RightEdge: return Qt.RightEdge; default: return Qt.BottomEdge; } } onCurrentTabChanged: header.input.forceActiveFocus(); Connections { target: plasmoid onExpandedChanged: { if(menuItemsChanged()) { createButtons(); } if (!expanded) { switchToInitial(); } } } } // tabBar PlasmaCore.SvgItem { id: tabBarSeparator svg: PlasmaCore.Svg { id: tabBarSeparatorLine imagePath: "widgets/line" } } MouseArea { anchors.fill: tabBar property var oldPos: null + enabled: root.state !== "Search" hoverEnabled: root.switchTabsOnHover onExited: { // Reset so we switch immediately when MouseArea is entered // freshly, e.g. from the panel. oldPos = null; clickTimer.stop(); } onPositionChanged: { // Reject multiple events with the same coordinates that QQuickWindow // synthesizes. if (oldPos === Qt.point(mouse.x, mouse.y)) { return; } var button = tabBar.layout.childAt(mouse.x, mouse.y); if (!button || button.objectName !== "KickoffButton") { clickTimer.stop(); return; } // Switch immediately when MouseArea was freshly entered, e.g. // from the panel. if (oldPos === null) { oldPos = Qt.point(mouse.x, mouse.y); clickTimer.stop(); button.clicked(); return; } var dx = (mouse.x - oldPos.x); var dy = (mouse.y - oldPos.y); // Check Manhattan length against drag distance to get a decent // pointer motion vector. if ((Math.abs(dx) + Math.abs(dy)) > Qt.styleHints.startDragDistance) { if (tabBar.currentTab !== button) { var tabBarPos = mapToItem(tabBar, oldPos.x, oldPos.y); oldPos = Qt.point(mouse.x, mouse.y); var angleMouseMove = Math.atan2(dy, dx) * 180 / Math.PI; var angleToCornerA = 0; var angleToCornerB = 0; switch (plasmoid.location) { case PlasmaCore.Types.TopEdge: { angleToCornerA = Math.atan2(tabBar.height - tabBarPos.y, 0 - tabBarPos.x); angleToCornerB = Math.atan2(tabBar.height - tabBarPos.y, tabBar.width - tabBarPos.x); break; } case PlasmaCore.Types.LeftEdge: { angleToCornerA = Math.atan2(0 - tabBarPos.y, tabBar.width - tabBarPos.x); angleToCornerB = Math.atan2(tabBar.height - tabBarPos.y, tabBar.width - tabBarPos.x); break; } case PlasmaCore.Types.RightEdge: { angleToCornerA = Math.atan2(0 - tabBarPos.y, 0 - tabBarPos.x); angleToCornerB = Math.atan2(tabBar.height - tabBarPos.y, 0 - tabBarPos.x); break; } // PlasmaCore.Types.BottomEdge default: { angleToCornerA = Math.atan2(0 - tabBarPos.y, 0 - tabBarPos.x); angleToCornerB = Math.atan2(0 - tabBarPos.y, tabBar.width - tabBarPos.x); } } // Degrees are nicer to debug than radians. angleToCornerA = angleToCornerA * 180 / Math.PI; angleToCornerB = angleToCornerB * 180 / Math.PI; var lower = Math.min(angleToCornerA, angleToCornerB); var upper = Math.max(angleToCornerA, angleToCornerB); // If the motion vector is outside the angle range from oldPos to the // relevant tab bar corners, switch immediately. Otherwise start the // timer, which gets aborted should the pointer exit the tab bar // early. var inRange = (lower < angleMouseMove == angleMouseMove < upper); // Mirror-flip. if (plasmoid.location === PlasmaCore.Types.RightEdge ? inRange : !inRange) { clickTimer.stop(); button.clicked(); return; } else { clickTimer.pendingButton = button; clickTimer.start(); } } else { oldPos = Qt.point(mouse.x, mouse.y); } } } onClicked: { clickTimer.stop(); var button = tabBar.layout.childAt(mouse.x, mouse.y); if (!button || button.objectName !== "KickoffButton") { return; } button.clicked(); } Timer { id: clickTimer property Item pendingButton: null interval: 250 onTriggered: { if (pendingButton) { pendingButton.clicked(); } } } } Keys.forwardTo: [tabBar.layout] Keys.onPressed: { if (mainTabGroup.currentTab == applicationsPage) { if (event.key !== Qt.Key_Tab) { root.state = "Applications"; } } switch(event.key) { case Qt.Key_Up: { currentView.decrementCurrentIndex(); event.accepted = true; break; } case Qt.Key_Down: { currentView.incrementCurrentIndex(); event.accepted = true; break; } case Qt.Key_Left: { if (header.input.focus && header.state == "query") { break; } if (!currentView.deactivateCurrentIndex()) { if (root.state == "Applications") { mainTabGroup.currentTab = firstButton.tab; tabBar.currentTab = firstButton; } root.state = "Normal" } event.accepted = true; break; } case Qt.Key_Right: { if (header.input.focus && header.state == "query") { break; } currentView.activateCurrentIndex(); event.accepted = true; break; } case Qt.Key_Tab: { root.state == "Applications" ? root.state = "Normal" : root.state = "Applications"; event.accepted = true; break; } case Qt.Key_Enter: case Qt.Key_Return: { currentView.activateCurrentIndex(1); event.accepted = true; break; } case Qt.Key_Escape: { if (header.state != "query") { plasmoid.expanded = false; } else { header.query = ""; } event.accepted = true; break; } case Qt.Key_Menu: { currentView.openContextMenu(); event.accepted = true; break; } default: if (!header.input.focus) { header.input.forceActiveFocus(); } } } states: [ State { name: "Normal" PropertyChanges { target: root Keys.forwardTo: [tabBar.layout] } PropertyChanges { target: tabBar //Set the opacity and NOT the visibility, as visibility is recursive //and this binding would be executed also on popup show/hide //as recommended by the docs: https://doc.qt.io/qt-5/qml-qtquick-item.html#visible-prop //plus, it triggers https://bugreports.qt.io/browse/QTBUG-66907 //in which a mousearea may think it's under the mouse while it isn't opacity: tabBar.count > 1 ? 1 : 0 } }, State { name: "Applications" PropertyChanges { target: root Keys.forwardTo: [root] } PropertyChanges { target: tabBar opacity: tabBar.count > 1 ? 1 : 0 } }, State { name: "Search" PropertyChanges { target: tabBar opacity: 0 } PropertyChanges { target: mainTabGroup currentTab: searchPage } PropertyChanges { target: root Keys.forwardTo: [root] } } ] // states function getButtonDefinition(name) { switch(name) { case "bookmark": return {id: "bookmarkButton", tab: favoritesPage, iconSource: "bookmarks", text: i18n("Favorites")}; case "application": return {id: "applicationButton", tab: applicationsPage, iconSource: "applications-other", text: i18n("Applications")}; case "computer": return {id: "computerButton", tab: systemPage, iconSource: pmSource.data["PowerDevil"] && pmSource.data["PowerDevil"]["Is Lid Present"] ? "computer-laptop" : "computer", text: i18n("Computer")}; case "used": return {id: "usedButton", tab: recentlyUsedPage, iconSource: "view-history", text: i18n("History")}; case "oftenUsed": return {id: "usedButton", tab: oftenUsedPage, iconSource: "office-chart-pie", text: i18n("Often Used")}; case "leave": return {id: "leaveButton", tab: leavePage, iconSource: "system-log-out", text: i18n("Leave")}; } } Component { id: kickoffButton KickoffButton {} } Component.onCompleted: { createButtons(); } function getEnabled(configuration) { var res = []; for(var i = 0; i < configuration.length; i++) { var confItemName = configuration[i].substring(0, configuration[i].indexOf(":")); var confItemEnabled = configuration[i].substring(configuration[i].length-1) === "t"; if(confItemEnabled) { res.push(confItemName); } } return res; } function createButtons() { configMenuItems = plasmoid.configuration.menuItems; var menuItems = getEnabled(plasmoid.configuration.menuItems); tabBar.count = menuItems.length // remove old menu items for(var i = tabBar.layout.children.length -1; i >= 0; i--) { if(tabBar.layout.children[i].objectName === "KickoffButton") { tabBar.layout.children[i].destroy(); } } for (var i = 0; i < menuItems.length; i++) { var props = getButtonDefinition(menuItems[i]); var button = kickoffButton.createObject(tabBar.layout, props); if(i === 0) { firstButton = button; switchToInitial(); } } } function menuItemsChanged() { if(configMenuItems.length !== plasmoid.configuration.menuItems.length) { return true; } for(var i = 0; i < configMenuItems.length; i++) { if(configMenuItems[i] !== plasmoid.configuration.menuItems[i]) { return true; } } return false; } } diff --git a/containments/panel/contents/ui/ConfigOverlay.qml b/containments/panel/contents/ui/ConfigOverlay.qml index 42176d3d6..8273ef7b3 100644 --- a/containments/panel/contents/ui/ConfigOverlay.qml +++ b/containments/panel/contents/ui/ConfigOverlay.qml @@ -1,438 +1,420 @@ /* * Copyright 2013 Marco Martin * * 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 2.010-1301, USA. */ import QtQuick 2.5 import QtQuick.Layouts 1.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.kquickcontrolsaddons 2.0 MouseArea { id: configurationArea z: 1000 anchors.fill: currentLayout hoverEnabled: true property bool isResizingLeft: false property bool isResizingRight: false property Item currentApplet property int lastX property int lastY readonly property int spacerHandleSize: units.smallSpacing onHeightChanged: tooltip.visible = false; onWidthChanged: tooltip.visible = false; onPositionChanged: { if (currentApplet && currentApplet.applet && currentApplet.applet.pluginName === "org.kde.plasma.panelspacer") { if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { if ((mouse.y - handle.y) < spacerHandleSize || (mouse.y - handle.y) > (handle.height - spacerHandleSize)) { configurationArea.cursorShape = Qt.SizeVerCursor; } else { configurationArea.cursorShape = Qt.ArrowCursor; } } else { if ((mouse.x - handle.x) < spacerHandleSize || (mouse.x - handle.x) > (handle.width - spacerHandleSize)) { configurationArea.cursorShape = Qt.SizeHorCursor; } else { configurationArea.cursorShape = Qt.ArrowCursor; } } } else { if (configurationArea.containsPress) { configurationArea.cursorShape = Qt.ClosedHandCursor; } else { configurationArea.cursorShape = Qt.OpenHandCursor; } } if (pressed) { if (currentApplet && currentApplet.applet.pluginName === "org.kde.plasma.panelspacer") { if (isResizingLeft) { if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { handle.y += (mouse.y - lastY); handle.height = currentApplet.height + (currentApplet.y - handle.y); } else { handle.x += (mouse.x - lastX); handle.width = currentApplet.width + (currentApplet.x - handle.x); } lastX = mouse.x; lastY = mouse.y; return; } else if (isResizingRight) { if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { handle.height = mouse.y - handle.y; } else { handle.width = mouse.x - handle.x; } lastX = mouse.x; lastY = mouse.y; return; } } var padding = units.gridUnit * 3; if (currentApplet && (mouse.x < -padding || mouse.y < -padding || mouse.x > width + padding || mouse.y > height + padding)) { var newCont = plasmoid.containmentAt(mouse.x, mouse.y); if (newCont && newCont !== plasmoid) { var newPos = newCont.mapFromApplet(plasmoid, mouse.x, mouse.y); var applet = currentApplet.applet; currentApplet.destroy(); applet.anchors.fill = undefined newCont.addApplet(applet, newPos.x, newPos.y); return; } } if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { currentApplet.y += (mouse.y - lastY); handle.y = currentApplet.y; } else { currentApplet.x += (mouse.x - lastX); handle.x = currentApplet.x; } lastX = mouse.x; lastY = mouse.y; var item = currentLayout.childAt(mouse.x, mouse.y); if (item && item !== placeHolder) { placeHolder.width = item.width; placeHolder.height = item.height; placeHolder.parent = configurationArea; var posInItem = mapToItem(item, mouse.x, mouse.y); if ((plasmoid.formFactor === PlasmaCore.Types.Vertical && posInItem.y < item.height/2) || (plasmoid.formFactor !== PlasmaCore.Types.Vertical && posInItem.x < item.width/2)) { root.layoutManager.insertBefore(item, placeHolder); } else { root.layoutManager.insertAfter(item, placeHolder); } } } else { var item = currentLayout.childAt(mouse.x, mouse.y); if (root.dragOverlay && item && item !== lastSpacer) { root.dragOverlay.currentApplet = item; } else { root.dragOverlay.currentApplet = null; } } if (root.dragOverlay.currentApplet) { hideTimer.stop(); tooltip.visible = true; tooltip.raise(); } } onEntered: hideTimer.stop(); onExited: hideTimer.restart(); onCurrentAppletChanged: { if (!currentApplet || !root.dragOverlay.currentApplet) { hideTimer.start(); return; } handle.x = currentApplet.x; handle.y = currentApplet.y; handle.width = currentApplet.width; handle.height = currentApplet.height; } onPressed: { if (!root.dragOverlay.currentApplet) { return; } if (currentApplet.applet.pluginName === "org.kde.plasma.panelspacer") { if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { if ((mouse.y - handle.y) < spacerHandleSize) { configurationArea.isResizingLeft = true; configurationArea.isResizingRight = false; } else if ((mouse.y - handle.y) > (handle.height - spacerHandleSize)) { configurationArea.isResizingLeft = false; configurationArea.isResizingRight = true; } else { configurationArea.isResizingLeft = false; configurationArea.isResizingRight = false; } } else { if ((mouse.x - handle.x) < spacerHandleSize) { configurationArea.isResizingLeft = true; configurationArea.isResizingRight = false; } else if ((mouse.x - handle.x) > (handle.width - spacerHandleSize)) { configurationArea.isResizingLeft = false; configurationArea.isResizingRight = true; } else { configurationArea.isResizingLeft = false; configurationArea.isResizingRight = false; } } } lastX = mouse.x; lastY = mouse.y; placeHolder.width = currentApplet.width; placeHolder.height = currentApplet.height; root.layoutManager.insertBefore(currentApplet, placeHolder); currentApplet.parent = moveAppletLayer; currentApplet.z = 900; } onReleased: { if (!root.dragOverlay.currentApplet) { return; } if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { currentApplet.applet.configuration.length = handle.height; } else { currentApplet.applet.configuration.length = handle.width; } configurationArea.isResizingLeft = false; configurationArea.isResizingRight = false; root.layoutManager.insertBefore(placeHolder, currentApplet); placeHolder.parent = configurationArea; currentApplet.z = 1; handle.x = currentApplet.x; handle.y = currentApplet.y; handle.width = currentApplet.width; handle.height = currentApplet.height; root.layoutManager.save(); } Item { id: placeHolder visible: configurationArea.containsMouse Layout.fillWidth: currentApplet ? currentApplet.Layout.fillWidth : false Layout.fillHeight: currentApplet ? currentApplet.Layout.fillHeight : false } Timer { id: hideTimer interval: units.longDuration * 6 onTriggered: tooltip.visible = false; } Connections { target: currentApplet onXChanged: handle.x = currentApplet.x onYChanged: handle.y = currentApplet.y onWidthChanged: handle.width = currentApplet.width onHeightChanged: handle.height = currentApplet.height } Rectangle { id: handle visible: configurationArea.containsMouse color: theme.backgroundColor radius: 3 opacity: currentApplet ? 0.5 : 0 PlasmaCore.IconItem { source: "transform-move" width: Math.min(parent.width, parent.height) height: width anchors.centerIn: parent } Rectangle { anchors { left: parent.left top: parent.top bottom: (plasmoid.formFactor !== PlasmaCore.Types.Vertical) ? parent.bottom : undefined right: (plasmoid.formFactor !== PlasmaCore.Types.Vertical) ? undefined : parent.right } visible: currentApplet && currentApplet.applet.pluginName === "org.kde.plasma.panelspacer" opacity: visible && !xAnim.running && !yAnim.running ? 1.0 : 0 width: configurationArea.spacerHandleSize height: configurationArea.spacerHandleSize color: theme.textColor Behavior on opacity { NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } } Rectangle { anchors { right: parent.right top: (plasmoid.formFactor !== PlasmaCore.Types.Vertical) ? parent.top : undefined bottom: parent.bottom left: (plasmoid.formFactor !== PlasmaCore.Types.Vertical) ? undefined : parent.left } visible: currentApplet && currentApplet.applet.pluginName === "org.kde.plasma.panelspacer" opacity: visible && !xAnim.running && !yAnim.running ? 1.0 : 0 width: configurationArea.spacerHandleSize height: configurationArea.spacerHandleSize color: theme.textColor Behavior on opacity { NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } } Behavior on x { enabled: !configurationArea.pressed NumberAnimation { id: xAnim duration: units.longDuration easing.type: Easing.InOutQuad } } Behavior on y { id: yAnim enabled: !configurationArea.pressed NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } Behavior on width { enabled: !configurationArea.pressed NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } Behavior on height { enabled: !configurationArea.pressed NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } Behavior on opacity { NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } } PlasmaCore.Dialog { id: tooltip visualParent: currentApplet type: PlasmaCore.Dialog.Dock flags: Qt.WindowStaysOnTopHint|Qt.WindowDoesNotAcceptFocus|Qt.BypassWindowManagerHint location: plasmoid.location onVisualParentChanged: { if (visualParent) { currentApplet.applet.prepareContextualActions(); alternativesButton.visible = currentApplet.applet.action("alternatives") && currentApplet.applet.action("alternatives").enabled; configureButton.visible = currentApplet.applet.action("configure") && currentApplet.applet.action("configure").enabled; + closeButton.visible = currentApplet.applet.action("remove") && currentApplet.applet.action("remove").enabled; label.text = currentApplet.applet.title; } } mainItem: MouseArea { enabled: currentApplet width: handleButtons.width height: handleButtons.height hoverEnabled: true onEntered: hideTimer.stop(); onExited: hideTimer.restart(); ColumnLayout { id: handleButtons spacing: units.smallSpacing PlasmaExtras.Heading { id: label level: 3 Layout.fillWidth: true Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 } - PlasmaComponents.ToolButton { - Layout.fillWidth: true - // we want destructive actions to be far from the initial - // cursor position, so show this on the top unless it's on - // a top panel - visible: tooltip.location !== PlasmaCore.Types.TopEdge - && currentApplet.applet.action("remove") - && currentApplet.applet.action("remove").enabled - iconSource: "delete" - text: i18n("Remove") - onClicked: { - tooltip.visible = false; - currentApplet.applet.action("remove").trigger(); - } - } PlasmaComponents.ToolButton { id: configureButton Layout.fillWidth: true iconSource: "configure" text: i18n("Configure...") onClicked: { tooltip.visible = false; currentApplet.applet.action("configure").trigger() } } PlasmaComponents.ToolButton { id: alternativesButton Layout.fillWidth: true iconSource: "widget-alternatives" text: i18n("Show Alternatives...") onClicked: { tooltip.visible = false; currentApplet.applet.action("alternatives").trigger() } } PlasmaComponents.ToolButton { + id: closeButton Layout.fillWidth: true - // we want destructive actions to be far from the initial - // cursor position, so show this on the bottom for top panels - visible: tooltip.location === PlasmaCore.Types.TopEdge - && currentApplet.applet.action("remove") - && currentApplet.applet.action("remove").enabled iconSource: "delete" text: i18n("Remove") onClicked: { tooltip.visible = false; currentApplet.applet.action("remove").trigger(); } } } } } } diff --git a/desktoppackage/contents/configuration/panelconfiguration/MoreSettingsMenu.qml b/desktoppackage/contents/configuration/panelconfiguration/MoreSettingsMenu.qml index 0ed81179a..5b1643026 100644 --- a/desktoppackage/contents/configuration/panelconfiguration/MoreSettingsMenu.qml +++ b/desktoppackage/contents/configuration/panelconfiguration/MoreSettingsMenu.qml @@ -1,158 +1,139 @@ /* * Copyright 2013 Marco Martin * * 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 2.010-1301, USA. */ import QtQuick 2.0 import QtQuick.Layouts 1.0 import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.core 2.0 as PlasmaCore PlasmaCore.Dialog { id: contextMenu visualParent: settingsButton location: plasmoid.location type: PlasmaCore.Dialog.PopupMenu flags: Qt.Popup | Qt.FramelessWindowHint | Qt.WindowDoesNotAcceptFocus mainItem: ColumnLayout { id: menuColumn Layout.minimumWidth: menuColumn.implicitWidth Layout.minimumHeight: menuColumn.implicitHeight spacing: units.smallSpacing LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true - PlasmaComponents.ToolButton { - Layout.fillWidth: true - // we want destructive actions to be far from the initial cursor - // position, so show this on the top unless it's on a top panel - visible: location !== PlasmaCore.Types.TopEdge - text: i18nd("plasma_shell_org.kde.plasma.desktop", "Remove Panel") - iconSource: "delete" - onClicked: plasmoid.action("remove").trigger(); - } - PlasmaExtras.Heading { level: 3 text: i18nd("plasma_shell_org.kde.plasma.desktop", "Panel Alignment") } PlasmaComponents.ButtonColumn { spacing: 0 Layout.fillWidth: true PlasmaComponents.ToolButton { anchors { left: parent.left right: parent.right } text: panel.formFactor === PlasmaCore.Types.Vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Top") : i18nd("plasma_shell_org.kde.plasma.desktop", "Left") checkable: true checked: panel.alignment === Qt.AlignLeft onClicked: panel.alignment = Qt.AlignLeft flat: false } PlasmaComponents.ToolButton { anchors { left: parent.left right: parent.right } text: i18nd("plasma_shell_org.kde.plasma.desktop", "Center") checkable: true checked: panel.alignment === Qt.AlignCenter onClicked: panel.alignment = Qt.AlignCenter flat: false } PlasmaComponents.ToolButton { anchors { left: parent.left right: parent.right } text: panel.formFactor === PlasmaCore.Types.Vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Bottom") : i18nd("plasma_shell_org.kde.plasma.desktop", "Right") checkable: true checked: panel.alignment === Qt.AlignRight onClicked: panel.alignment = Qt.AlignRight flat: false } } PlasmaExtras.Heading { level: 3 text: i18nd("plasma_shell_org.kde.plasma.desktop", "Visibility") } PlasmaComponents.ButtonColumn { spacing: 0 Layout.fillWidth: true Layout.minimumWidth: implicitWidth PlasmaComponents.ToolButton { width: Math.max(implicitWidth, parent.width) text: i18nd("plasma_shell_org.kde.plasma.desktop", "Always Visible") checkable: true checked: configDialog.visibilityMode === 0 onClicked: configDialog.visibilityMode = 0 flat: false } PlasmaComponents.ToolButton { width: Math.max(implicitWidth, parent.width) text: i18nd("plasma_shell_org.kde.plasma.desktop", "Auto Hide") checkable: true checked: configDialog.visibilityMode === 1 onClicked: configDialog.visibilityMode = 1 flat: false } PlasmaComponents.ToolButton { width: Math.max(implicitWidth, parent.width) text: i18nd("plasma_shell_org.kde.plasma.desktop", "Windows Can Cover") checkable: true checked: configDialog.visibilityMode === 2 onClicked: configDialog.visibilityMode = 2 flat: false } PlasmaComponents.ToolButton { width: Math.max(implicitWidth, parent.width) text: i18nd("plasma_shell_org.kde.plasma.desktop", "Windows Go Below") checkable: true checked: configDialog.visibilityMode === 3 onClicked: configDialog.visibilityMode = 3 flat: false } } PlasmaComponents.ToolButton { Layout.fillWidth: true text: i18nd("plasma_shell_org.kde.plasma.desktop", "Maximize Panel") iconSource: panel.formFactor === PlasmaCore.Types.Vertical ? "zoom-fit-height" : "zoom-fit-width" onClicked: panel.maximize(); } - PlasmaComponents.ToolButton { - Layout.fillWidth: true - // we want destructive actions to be far from the initial cursor - // position, so show this on the bottom for top panels - visible: location === PlasmaCore.Types.TopEdge - text: i18nd("plasma_shell_org.kde.plasma.desktop", "Remove Panel") - iconSource: "delete" - onClicked: plasmoid.action("remove").trigger(); - } } function hide() { visible = false; } Component.onCompleted: { dialogRoot.closeContextMenu.connect(hide); } } diff --git a/desktoppackage/contents/configuration/panelconfiguration/ToolBar.qml b/desktoppackage/contents/configuration/panelconfiguration/ToolBar.qml index 944ad350b..7595d1e86 100644 --- a/desktoppackage/contents/configuration/panelconfiguration/ToolBar.qml +++ b/desktoppackage/contents/configuration/panelconfiguration/ToolBar.qml @@ -1,347 +1,358 @@ /* * Copyright 2013 Marco Martin * * 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 2.010-1301, USA. */ import QtQuick 2.0 import QtQuick.Controls 2.5 as QQC2 import QtQuick.Layouts 1.0 import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.configuration 2.0 import org.kde.kirigami 2.0 as Kirigami Item { id: root state: parent.state implicitWidth: Math.max(buttonsLayout_1.width, buttonsLayout_2.width, row.width) + units.smallSpacing * 2 implicitHeight: row.height + 20 + readonly property string removePanelButtonText: i18nd("plasma_shell_org.kde.plasma.desktop", "Remove Panel") readonly property string addWidgetsButtonText: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Widgets...") readonly property string addSpacerButtonText: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Spacer") readonly property string settingsButtonText: i18nd("plasma_shell_org.kde.plasma.desktop", "More Settings...") QQC2.Action { shortcut: "Escape" onTriggered: { // avoid leaving the panel in an inconsistent state when escaping while dragging it // "checked" means "pressed" in this case, we abuse that property to make the button look pressed if (edgeHandle.checked || sizeHandle.checked) { return } if (contextMenuLoader.opened) { contextMenuLoader.close() } else { configDialog.close() } } } GridLayout { id: buttonsLayout_1 rows: 1 columns: 1 flow: plasmoid.formFactor === PlasmaCore.Types.Horizontal ? GridLayout.TopToBottom : GridLayout.LeftToRight anchors.margins: rowSpacing anchors.topMargin: plasmoid.formFactor === PlasmaCore.Types.Vertical ? rowSpacing + closeButton.height : rowSpacing property bool showText: plasmoid.formFactor === PlasmaCore.Types.Vertical || (row.x + row.width < root.width - placeHolder.width - units.iconSizes.small*4 - units.largeSpacing*5) rowSpacing: units.smallSpacing columnSpacing: units.smallSpacing PlasmaComponents.Button { - text: buttonsLayout_2.showText ? root.addWidgetsButtonText : "" - tooltip: buttonsLayout_2.showText ? "" : root.addWidgetsButtonText - iconSource: "list-add" - Layout.fillWidth: true - onClicked: { - configDialog.close(); - configDialog.showAddWidgetDialog(); - } - } - - PlasmaComponents.Button { - iconSource: "distribute-horizontal-x" - text: buttonsLayout_2.showText ? root.addSpacerButtonText : "" - tooltip: buttonsLayout_2.showText ? "" : root.addSpacerButtonText + iconSource: "delete" + text: buttonsLayout_1.showText ? root.removePanelButtonText : "" + tooltip: buttonsLayout_1.showText ? "" : root.removePanelButtonText Layout.fillWidth: true onClicked: { - configDialog.addPanelSpacer(); + plasmoid.action("remove").trigger(); } } } GridLayout { id: row columns: dialogRoot.vertical ? 1 : 2 rows: dialogRoot.vertical ? 2 : 1 anchors.centerIn: parent rowSpacing: units.smallSpacing columnSpacing: units.smallSpacing EdgeHandle { id: edgeHandle Layout.alignment: Qt.AlignHCenter } SizeHandle { id: sizeHandle Layout.alignment: Qt.AlignHCenter } } PlasmaComponents.Label { id: placeHolder visible: false text: addWidgetsButtonText + addSpacerButtonText + settingsButtonText } Connections { target: configDialog onVisibleChanged: { if (!configDialog.visible) { settingsButton.checked = false } } } GridLayout { id: buttonsLayout_2 rows: 1 columns: 1 flow: plasmoid.formFactor === PlasmaCore.Types.Horizontal ? GridLayout.TopToBottom : GridLayout.LeftToRight anchors.margins: rowSpacing property bool showText: plasmoid.formFactor === PlasmaCore.Types.Vertical || (row.x + row.width < root.width - placeHolder.width - units.iconSizes.small*4 - units.largeSpacing*5) rowSpacing: units.smallSpacing columnSpacing: units.smallSpacing + PlasmaComponents.Button { + text: buttonsLayout_2.showText ? root.addWidgetsButtonText : "" + tooltip: buttonsLayout_2.showText ? "" : root.addWidgetsButtonText + iconSource: "list-add" + Layout.fillWidth: true + onClicked: { + configDialog.close(); + configDialog.showAddWidgetDialog(); + } + } + + PlasmaComponents.Button { + iconSource: "distribute-horizontal-x" + text: buttonsLayout_2.showText ? root.addSpacerButtonText : "" + tooltip: buttonsLayout_2.showText ? "" : root.addSpacerButtonText + Layout.fillWidth: true + onClicked: { + configDialog.addPanelSpacer(); + } + } + PlasmaComponents.Button { id: settingsButton iconSource: "configure" text: buttonsLayout_2.showText ? root.settingsButtonText : "" tooltip: buttonsLayout_2.showText ? "" : root.settingsButtonText Layout.fillWidth: true checkable: true onCheckedChanged: { if (checked) { contextMenuLoader.open() } else { contextMenuLoader.close() } } } PlasmaComponents.ToolButton { id: closeButton parent: plasmoid.formFactor === PlasmaCore.Types.Horizontal ? buttonsLayout_2 : root anchors.right: plasmoid.formFactor === PlasmaCore.Types.Horizontal ? undefined : parent.right iconSource: "window-close" tooltip: i18nd("plasma_shell_org.kde.plasma.desktop", "Close") onClicked: { configDialog.close() } } Loader { id: contextMenuLoader property bool opened: item && item.visible onOpenedChanged: settingsButton.checked = opened source: "MoreSettingsMenu.qml" active: false function open() { active = true item.visible = true } function close() { if (item) { item.visible = false } } } } //BEGIN States states: [ State { name: "TopEdge" PropertyChanges { target: root height: root.implicitHeight } AnchorChanges { target: root anchors { top: undefined bottom: root.parent.bottom left: root.parent.left right: root.parent.right } } AnchorChanges { target: buttonsLayout_1 anchors { verticalCenter: root.verticalCenter top: undefined bottom: undefined left: root.left right: undefined } } AnchorChanges { target: buttonsLayout_2 anchors { verticalCenter: root.verticalCenter top: undefined bottom: undefined left: undefined right: root.right } } PropertyChanges { target: buttonsLayout_1 width: buttonsLayout_1.implicitWidth } PropertyChanges { target: buttonsLayout_2 width: buttonsLayout_2.implicitWidth } }, State { name: "BottomEdge" PropertyChanges { target: root height: root.implicitHeight } AnchorChanges { target: root anchors { top: root.parent.top bottom: undefined left: root.parent.left right: root.parent.right } } AnchorChanges { target: buttonsLayout_1 anchors { verticalCenter: root.verticalCenter top: undefined bottom: undefined left: root.left right: undefined } } AnchorChanges { target: buttonsLayout_2 anchors { verticalCenter: root.verticalCenter top: undefined bottom: undefined left: undefined right: root.right } } PropertyChanges { target: buttonsLayout_1 width: buttonsLayout_1.implicitWidth } PropertyChanges { target: buttonsLayout_2 width: buttonsLayout_2.implicitWidth } }, State { name: "LeftEdge" PropertyChanges { target: root width: root.implicitWidth } AnchorChanges { target: root anchors { top: root.parent.top bottom: root.parent.bottom left: undefined right: root.parent.right } } AnchorChanges { target: buttonsLayout_1 anchors { verticalCenter: undefined top: root.top bottom: undefined left: root.left right: root.right } } AnchorChanges { target: buttonsLayout_2 anchors { verticalCenter: undefined top: undefined bottom: root.bottom left: root.left right: root.right } } }, State { name: "RightEdge" PropertyChanges { target: root width: root.implicitWidth } AnchorChanges { target: root anchors { top: root.parent.top bottom: root.parent.bottom left: root.parent.left right: undefined } } AnchorChanges { target: buttonsLayout_1 anchors { verticalCenter: undefined top: root.top bottom: undefined left: root.left right: root.right } } AnchorChanges { target: buttonsLayout_2 anchors { verticalCenter: undefined top: undefined bottom: root.bottom left: root.left right: root.right } } } ] //END States }