diff --git a/applets/colorpicker/package/contents/ui/configGeneral.qml b/applets/colorpicker/package/contents/ui/configGeneral.qml index c8dff7b21..db527e78f 100644 --- a/applets/colorpicker/package/contents/ui/configGeneral.qml +++ b/applets/colorpicker/package/contents/ui/configGeneral.qml @@ -1,97 +1,97 @@ /* * Copyright 2015 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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, see */ import QtQuick 2.0 import QtQuick.Controls 1.0 as QtControls import QtQuick.Layouts 1.0 -import "../code/logic.js" as Logic +import "logic.js" as Logic ColumnLayout { id: appearancePage property alias cfg_autoClipboard: autoClipboardCheckBox.checked property string cfg_defaultFormat property bool cfg_pickOnActivate QtControls.CheckBox { id: autoClipboardCheckBox Layout.fillWidth: true text: i18n("Automatically copy color to clipboard") } GridLayout { Layout.fillWidth: false // Layout thinks it's smart whereas it's not Layout.alignment: Qt.AlignLeft columns: 2 QtControls.Label { Layout.row: 0 Layout.column: 0 Layout.fillWidth: true horizontalAlignment: Text.AlignRight text: i18n("Default color format:") } QtControls.ComboBox { id: defaultFormatCombo Layout.row: 0 Layout.column: 1 // ComboBox default sizing is totally off Layout.minimumWidth: theme.mSize(theme.defaultFont).width * 12 model: Logic.formats currentIndex: defaultFormatCombo.model.indexOf(cfg_defaultFormat) onActivated: cfg_defaultFormat = model[index] } QtControls.Label { Layout.row: 1 Layout.column: 0 Layout.fillWidth: true horizontalAlignment: Text.AlignRight text: i18n("When pressing the keyboard shortcut:") } QtControls.ExclusiveGroup { id: activationExclusiveGroup } QtControls.RadioButton { Layout.row: 1 Layout.column: 1 text: i18n("Pick a color") exclusiveGroup: activationExclusiveGroup checked: cfg_pickOnActivate onCheckedChanged: cfg_pickOnActivate = checked } QtControls.RadioButton { Layout.row: 2 Layout.column: 1 text: i18n("Show history") exclusiveGroup: activationExclusiveGroup checked: !cfg_pickOnActivate } } Item { Layout.fillHeight: true } } diff --git a/applets/colorpicker/package/contents/code/logic.js b/applets/colorpicker/package/contents/ui/logic.js similarity index 100% rename from applets/colorpicker/package/contents/code/logic.js rename to applets/colorpicker/package/contents/ui/logic.js diff --git a/applets/colorpicker/package/contents/ui/main.qml b/applets/colorpicker/package/contents/ui/main.qml index 98b58960f..661780418 100644 --- a/applets/colorpicker/package/contents/ui/main.qml +++ b/applets/colorpicker/package/contents/ui/main.qml @@ -1,384 +1,384 @@ /* * Copyright 2015 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 2.010-1301, USA. */ import QtQuick 2.2 import QtQuick.Controls 1.1 as QtControls import QtQuick.Layouts 1.1 import QtQuick.Dialogs 1.0 as QtDialogs 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.draganddrop 2.0 import org.kde.plasma.private.colorpicker 2.0 as ColorPicker -import "../code/logic.js" as Logic +import "logic.js" as Logic Item { id: root readonly property bool isVertical: plasmoid.formFactor === PlasmaCore.Types.Vertical readonly property color recentColor: plasmoid.configuration.history[0] || theme.highlightColor // nice default color readonly property string defaultFormat: plasmoid.configuration.defaultFormat Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation Plasmoid.toolTipSubText: Logic.formatColor(recentColor, defaultFormat) function addColorToHistory(color) { // this is needed, otherwise the first pick after plasma start isn't registered var history = plasmoid.configuration.history // this .toString() is needed otherwise Qt completely screws it up // replacing *all* items in the list by the new items and other nonsense history.unshift(color.toString()) // limit to 9 entries plasmoid.configuration.history = history.slice(0, 9) } function colorPicked(color) { if (color != recentColor) { addColorToHistory(color) } if (plasmoid.configuration.autoClipboard) { picker.copyToClipboard(Logic.formatColor(color, root.defaultFormat)) } } function pickColor() { plasmoid.expanded = false picker.pick() } ColorPicker.GrabWidget { id: picker onCurrentColorChanged: colorPicked(currentColor) } QtDialogs.ColorDialog { id: colorDialog title: plasmoid.title color: recentColor onColorChanged: colorPicked(color) } // prevents the popup from actually opening, needs to be queued Timer { id: delayedPickTimer interval: 0 onTriggered: root.pickColor() } Plasmoid.onActivated: { if (plasmoid.configuration.pickOnActivate) { delayedPickTimer.start() } } function action_clear() { plasmoid.configuration.history = [] } function action_colordialog() { colorDialog.open() } Component.onCompleted: { plasmoid.setAction("colordialog", i18n("Open Color Dialog"), "color-management") plasmoid.setAction("clear", i18n("Clear History"), "edit-clear-history") } Plasmoid.compactRepresentation: Grid { readonly property int buttonSize: root.isVertical ? width : height columns: root.isVertical ? 1 : 3 rows: root.isVertical ? 3 : 1 Layout.minimumWidth: isVertical ? units.iconSizes.small : ((height * 2) + spacer.width) Layout.minimumHeight: isVertical ? ((width * 2) + spacer.height) : units.iconSizes.small PlasmaComponents.ToolButton { width: buttonSize height: buttonSize tooltip: i18n("Pick Color") onClicked: root.pickColor() PlasmaCore.IconItem { id: pickerIcon anchors.centerIn: parent width: Math.round(parent.width * 0.9) height: width source: "color-picker" active: parent.hovered } } Item { // spacer id: spacer readonly property int thickness: Math.ceil(Math.min(parent.width, parent.height) / units.iconSizes.small) width: root.isVertical ? parent.width : thickness height: root.isVertical ? thickness : parent.height Rectangle { anchors.centerIn: parent width: Math.min(parent.width, colorCircle.height) height: Math.min(parent.height, colorCircle.height) color: theme.textColor opacity: 0.6 } } // this is so the circle we put ontop of the ToolButton resizes // exactly like the regular icon on the other button PlasmaCore.FrameSvgItem { id: surfaceNormal imagePath: "widgets/button" prefix: "normal" visible: false } DropArea { id: dropArea property bool containsAcceptableDrag: false width: buttonSize height: buttonSize preventStealing: true // why the hell is hasColor not a property?! onDragEnter: containsAcceptableDrag = (event.mimeData.hasColor() || ColorPicker.Utils.isValidColor(event.mimeData.text)) onDragLeave: containsAcceptableDrag = false onDrop: { if (event.mimeData.hasColor()) { addColorToHistory(event.mimeData.color) } else if (ColorPicker.Utils.isValidColor(event.mimeData.text)) { addColorToHistory(event.mimeData.text) } containsAcceptableDrag = false } PlasmaComponents.ToolButton { anchors.fill: parent tooltip: i18n("Color Options") onClicked: plasmoid.expanded = !plasmoid.expanded // indicate viable drag... checked: dropArea.containsAcceptableDrag checkable: checked Rectangle { id: colorCircle anchors.centerIn: parent // try to match the color-picker icon in size width: units.roundToIconSize(pickerIcon.width) * 0.75 height: units.roundToIconSize(pickerIcon.height) * 0.75 radius: width / 2 color: root.recentColor function luminance(color) { if (!color) { return 0; } // formula for luminance according to https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef var a = [color.r, color.g, color.b].map(function (v) { return (v <= 0.03928) ? v / 12.92 : Math.pow( ((v + 0.055) / 1.055), 2.4 ); }); return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722; } border { color: theme.textColor width: { var contrast = luminance(theme.viewBackgroundColor) / luminance(colorCircle.color) + 0.05; // show border only if there's too little contrast to the surrounding view if (contrast > 3) { return 0; } else { return Math.round(Math.max(units.devicePixelRatio, width / 20)); } } } } } } } Plasmoid.fullRepresentation: GridView { id: fullRoot readonly property int columns: 3 Layout.minimumWidth: columns * units.gridUnit * 6 Layout.minimumHeight: Layout.minimumWidth Layout.maximumWidth: Layout.minimumWidth Layout.maximumHeight: Layout.minimumHeight cellWidth: Math.floor(fullRoot.width / fullRoot.columns) cellHeight: cellWidth boundsBehavior: Flickable.StopAtBounds model: plasmoid.configuration.history highlight: PlasmaComponents.Highlight {} highlightMoveDuration: 0 PlasmaComponents.Button { anchors.centerIn: parent text: i18n("Pick Color") visible: fullRoot.count === 0 onClicked: root.pickColor() } Connections { target: plasmoid onExpandedChanged: { if (plasmoid.expanded) { fullRoot.forceActiveFocus() } } } QtControls.Action { shortcut: "Return" onTriggered: { if (fullRoot.currentItem) { fullRoot.currentItem.clicked(null) } } } QtControls.Action { shortcut: "Escape" onTriggered: plasmoid.expanded = false } // This item serves as a drag pixmap and is captured when a drag starts Rectangle { id: dragImageDummy border { color: theme.textColor width: Math.round(units.devicePixelRatio) } radius: width width: units.iconSizes.large height: units.iconSizes.large visible: false } delegate: MouseArea { id: delegateMouse readonly property color currentColor: modelData width: fullRoot.cellWidth height: fullRoot.cellHeight drag.target: rect Drag.dragType: Drag.Automatic Drag.active: delegateMouse.drag.active Drag.mimeData: { "application/x-color": rect.color, "text/plain": colorLabel.text } hoverEnabled: true onContainsMouseChanged: { if (containsMouse) { fullRoot.currentIndex = index } else { fullRoot.currentIndex = -1 } } onPressed: { // grab pixmap only once if (Drag.imageSource.toString() === "") { // cannot just do !Drage.imageSource on QUrl dragImageDummy.color = currentColor; dragImageDummy.grabToImage(function (result) { Drag.imageSource = result.url; }); } } onClicked: { formattingMenu.model = Logic.menuForColor(delegateMouse.currentColor) formattingMenu.open(0, rect.height) } PlasmaCore.ToolTipArea { anchors.fill: parent active: colorLabel.truncated mainText: colorLabel.text } Rectangle { id: rect anchors { fill: parent margins: units.smallSpacing } color: delegateMouse.currentColor border { color: theme.textColor width: Math.round(units.devicePixelRatio) } Rectangle { anchors { bottom: parent.bottom left: parent.left right: parent.right margins: rect.border.width } height: colorLabel.contentHeight + 2 * units.smallSpacing color: theme.backgroundColor opacity: 0.8 PlasmaComponents.Label { id: colorLabel anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter elide: Text.ElideLeft fontSizeMode: Text.HorizontalFit minimumPointSize: theme.smallestFont.pointSize text: Logic.formatColor(delegateMouse.currentColor, root.defaultFormat) } } PlasmaComponents.ModelContextMenu { id: formattingMenu onClicked: picker.copyToClipboard(model.text) } } } } } diff --git a/applets/quicklaunch/package/contents/ui/IconItem.qml b/applets/quicklaunch/package/contents/ui/IconItem.qml index 330f74e46..c06be301e 100644 --- a/applets/quicklaunch/package/contents/ui/IconItem.qml +++ b/applets/quicklaunch/package/contents/ui/IconItem.qml @@ -1,283 +1,283 @@ /* * Copyright 2015 David Rosca * * 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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, see */ import QtQuick 2.2 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.draganddrop 2.0 as DragAndDrop -import "../code/layout.js" as LayoutManager +import "layout.js" as LayoutManager Item { id: iconItem property int itemIndex : index property bool dragging : false property bool isPopupItem : false property var launcher : logic.launcherData(url) property string iconName : launcher.iconName || "fork" width: isPopupItem ? LayoutManager.popupItemWidth() : grid.cellWidth height: isPopupItem ? LayoutManager.popupItemHeight() : grid.cellHeight DragAndDrop.DragArea { id: dragArea width: Math.min(iconItem.width, iconItem.height) height: width enabled: !plasmoid.immutable defaultAction: Qt.MoveAction supportedActions: Qt.IgnoreAction | Qt.MoveAction delegate: icon mimeData { url: url source: iconItem } onDragStarted: { dragging = true; } onDrop: { dragging = false; if (action == Qt.MoveAction) { removeLauncher(); } } MouseArea { id: mouseArea anchors.fill: parent anchors.margins: LayoutManager.itemPadding() hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton onPressed: { if (mouse.button == Qt.RightButton) { contextMenu.refreshActions(); contextMenu.open(mouse.x, mouse.y); } } onClicked: { if (mouse.button == Qt.LeftButton) { logic.openUrl(url) } } PlasmaCore.IconItem { id: icon anchors { top: parent.top left: parent.left } width: units.iconSizes.medium height: width usesPlasmaTheme: false source: url == "quicklaunch:drop" ? "" : iconName active: mouseArea.containsMouse } PlasmaComponents.Label { id: label anchors { bottom : parent.bottom right : parent.right } text: iconItem.launcher.applicationName maximumLineCount: 1 wrapMode: Text.Wrap } PlasmaCore.FrameSvgItem { anchors.fill: parent imagePath: "widgets/viewitem" prefix: "hover" visible: dragging || url == "quicklaunch:drop" } PlasmaCore.ToolTipArea { anchors.fill: parent active: !dragging mainText: iconItem.launcher.applicationName subText: iconItem.launcher.genericName icon: iconName } PlasmaComponents.ContextMenu { id: contextMenu property var jumpListItems : [] visualParent: mouseArea PlasmaComponents.MenuItem { id: jumpListSeparator separator: true } PlasmaComponents.MenuItem { text: i18n("Add Launcher...") icon: "list-add" onClicked: addLauncher() } PlasmaComponents.MenuItem { text: i18n("Edit Launcher...") icon: "document-edit" onClicked: editLauncher() } PlasmaComponents.MenuItem { text: i18n("Remove Launcher") icon: "list-remove" onClicked: removeLauncher() } PlasmaComponents.MenuItem { separator: true } PlasmaComponents.MenuItem { action: plasmoid.action("configure") } PlasmaComponents.MenuItem { action: plasmoid.action("remove") } function refreshActions() { for (var i = 0; i < jumpListItems.length; ++i) { var item = jumpListItems[i]; removeMenuItem(item); item.destroy(); } jumpListItems = []; for (var i = 0; i < launcher.jumpListActions.length; ++i) { var action = launcher.jumpListActions[i]; var item = menuItemComponent.createObject(iconItem, { "text": action.name, "icon": action.icon }); item.clicked.connect(function() { logic.openExec(this.exec); }.bind(action)); addMenuItem(item, jumpListSeparator); jumpListItems.push(item); } } } Component { id: menuItemComponent PlasmaComponents.MenuItem { } } } } states: [ State { name: "popup" when: isPopupItem AnchorChanges { target: dragArea anchors.left: dragArea.parent.left anchors.right: dragArea.parent.right anchors.top: dragArea.parent.top anchors.bottom: dragArea.parent.bottom } AnchorChanges { target: icon anchors.right: undefined anchors.bottom: undefined } AnchorChanges { target: label anchors.top: label.parent.top anchors.left: icon.right } PropertyChanges { target: label horizontalAlignment: Text.AlignHLeft visible: true elide: Text.ElideRight anchors.leftMargin: units.smallSpacing anchors.rightMargin: units.smallSpacing } }, State { name: "grid" when: !isPopupItem AnchorChanges { target: dragArea anchors.verticalCenter: dragArea.parent.verticalCenter anchors.horizontalCenter: dragArea.parent.horizontalCenter } AnchorChanges { target: icon anchors.right: icon.parent.right anchors.bottom: label.visible ? label.top : icon.parent.bottom } AnchorChanges { target: label anchors.top: undefined anchors.left: label.parent.left } PropertyChanges { target: label horizontalAlignment: Text.AlignHCenter visible: showLauncherNames elide: Text.ElideNone } } ] function addLauncher() { logic.addLauncher(isPopupItem); } function editLauncher() { logic.editLauncher(url, itemIndex, isPopupItem); } function removeLauncher() { var m = isPopupItem ? popupModel : launcherModel; m.removeUrl(itemIndex); } } diff --git a/applets/quicklaunch/package/contents/ui/Popup.qml b/applets/quicklaunch/package/contents/ui/Popup.qml index 38c8cf6ca..cd6446b30 100644 --- a/applets/quicklaunch/package/contents/ui/Popup.qml +++ b/applets/quicklaunch/package/contents/ui/Popup.qml @@ -1,119 +1,119 @@ /* * Copyright 2015 David Rosca * * 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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, see */ import QtQuick 2.2 import org.kde.draganddrop 2.0 as DragAndDrop -import "../code/layout.js" as LayoutManager +import "layout.js" as LayoutManager Item { id: popup property bool dragging: false property alias popupModel : popupModel width: LayoutManager.popupItemWidth() height: Math.max(1, popupModel.count) * LayoutManager.popupItemHeight() DragAndDrop.DropArea { anchors.fill: parent preventStealing: true enabled: !plasmoid.immutable onDragEnter: { dragging = true; } onDragMove: { if (!event.mimeData.hasUrls) { return; } var index = listView.indexAt(event.x, event.y); if (isInternalDrop(event)) { popupModel.moveUrl(event.mimeData.source.itemIndex, index); } else if (event.mimeData.hasUrls) { popupModel.showDropMarker(index); } } onDragLeave: { dragging = false; popupModel.clearDropMarker(); } onDrop: { dragging = false; popupModel.clearDropMarker(); if (isInternalDrop(event)) { event.accept(Qt.IgnoreAction); saveConfiguration(); } else if (event.mimeData.hasUrls) { var index = listView.indexAt(event.x, event.y); popupModel.insertUrls(index == -1 ? popupModel.count : index, event.mimeData.urls); event.accept(event.proposedAction); } } } ListView { id: listView anchors.fill: parent interactive: false model: UrlModel { id: popupModel } delegate: IconItem { isPopupItem: true } } Connections { target: plasmoid.configuration onPopupUrlsChanged: { popupModel.urlsChanged.disconnect(saveConfiguration); popupModel.setUrls(plasmoid.configuration.popupUrls); popupModel.urlsChanged.connect(saveConfiguration); } } Component.onCompleted: { popupModel.setUrls(plasmoid.configuration.popupUrls); popupModel.urlsChanged.connect(saveConfiguration); } function saveConfiguration() { if (!dragging) { plasmoid.configuration.popupUrls = popupModel.urls(); } } function isInternalDrop(event) { return event.mimeData.source && event.mimeData.source.ListView && event.mimeData.source.ListView.view == listView; } } diff --git a/applets/quicklaunch/package/contents/code/layout.js b/applets/quicklaunch/package/contents/ui/layout.js similarity index 100% rename from applets/quicklaunch/package/contents/code/layout.js rename to applets/quicklaunch/package/contents/ui/layout.js diff --git a/applets/quicklaunch/package/contents/ui/main.qml b/applets/quicklaunch/package/contents/ui/main.qml index 82de269d5..51e0236da 100644 --- a/applets/quicklaunch/package/contents/ui/main.qml +++ b/applets/quicklaunch/package/contents/ui/main.qml @@ -1,292 +1,292 @@ /* * Copyright 2015 David Rosca * * 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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, see */ import QtQuick 2.2 import QtQuick.Layouts 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.draganddrop 2.0 as DragAndDrop import org.kde.plasma.private.quicklaunch 1.0 -import "../code/layout.js" as LayoutManager +import "layout.js" as LayoutManager Item { id: root property int maxSectionCount: Plasmoid.configuration.maxSectionCount property bool showLauncherNames : Plasmoid.configuration.showLauncherNames property bool enablePopup : Plasmoid.configuration.enablePopup property string title : Plasmoid.formFactor == PlasmaCore.Types.Planar ? Plasmoid.configuration.title : "" property bool vertical : Plasmoid.formFactor == PlasmaCore.Types.Vertical || (Plasmoid.formFactor == PlasmaCore.Types.Planar && height > width) property bool horizontal : Plasmoid.formFactor == PlasmaCore.Types.Horizontal property bool dragging : false Layout.minimumWidth: LayoutManager.minimumWidth() Layout.minimumHeight: LayoutManager.minimumHeight() Layout.preferredWidth: LayoutManager.preferredWidth() Layout.preferredHeight: LayoutManager.preferredHeight() Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation DragAndDrop.DropArea { anchors.fill: parent preventStealing: true enabled: !plasmoid.immutable onDragEnter: { if (event.mimeData.hasUrls) { dragging = true; } else { event.ignore(); } } onDragMove: { var index = grid.indexAt(event.x, event.y); if (isInternalDrop(event)) { launcherModel.moveUrl(event.mimeData.source.itemIndex, index); } else { launcherModel.showDropMarker(index); } popup.visible = root.childAt(event.x, event.y) == popupArrow; } onDragLeave: { dragging = false; launcherModel.clearDropMarker(); } onDrop: { dragging = false; launcherModel.clearDropMarker(); if (isInternalDrop(event)) { event.accept(Qt.IgnoreAction); saveConfiguration(); } else { var index = grid.indexAt(event.x, event.y); launcherModel.insertUrls(index == -1 ? launcherModel.count : index, event.mimeData.urls); event.accept(event.proposedAction); } } } PlasmaComponents.Label { id: titleLabel anchors { top: parent.top left: parent.left right: parent.right } height: theme.mSize(theme.defaultFont).height horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignTop elide: Text.ElideMiddle text: title } Item { id: launcher anchors { top: title.length ? titleLabel.bottom : parent.top left: parent.left right: !vertical && popupArrow.visible ? popupArrow.left : parent.right bottom: vertical && popupArrow.visible ? popupArrow.top : parent.bottom } GridView { id: grid anchors.fill: parent interactive: false flow: horizontal ? GridView.FlowTopToBottom : GridView.FlowLeftToRight cellWidth: LayoutManager.preferredCellWidth() cellHeight: LayoutManager.preferredCellHeight() visible: count model: UrlModel { id: launcherModel } delegate: IconItem { } } PlasmaCore.IconItem { id: defaultIcon anchors.fill: parent source: "fork" visible: !grid.visible PlasmaCore.ToolTipArea { anchors.fill: parent icon: "fork" mainText: i18n("Quicklaunch") subText: i18n("Add launchers by Drag and Drop or by using the context menu.") } } } PlasmaCore.Dialog { id: popup type: PlasmaCore.Dialog.PopupMenu flags: Qt.WindowStaysOnTopHint hideOnWindowDeactivate: true location: plasmoid.location visualParent: vertical ? popupArrow : root mainItem: Popup { } } PlasmaCore.ToolTipArea { id: popupArrow visible: enablePopup anchors { top: vertical ? undefined : parent.top right: parent.right bottom: parent.bottom } subText: popup.visible ? i18n("Hide icons") : i18n("Show hidden icons") MouseArea { id: arrowMouseArea anchors.fill: parent onClicked: { popup.visible = !popup.visible } PlasmaCore.Svg { id: arrowSvg imagePath: "widgets/arrows" } PlasmaCore.SvgItem { id: arrow anchors.centerIn: parent width: Math.min(parent.width, parent.height) height: width rotation: popup.visible ? 180 : 0 Behavior on rotation { RotationAnimation { duration: units.shortDuration * 3 } } svg: arrowSvg elementId: { if (plasmoid.location == PlasmaCore.Types.TopEdge) { return "down-arrow"; } else if (plasmoid.location == PlasmaCore.Types.LeftEdge) { return "right-arrow"; } else if (plasmoid.location == PlasmaCore.Types.RightEdge) { return "left-arrow"; } else if (vertical) { return "right-arrow"; } else { return "up-arrow"; } } } } } Logic { id: logic onLauncherAdded: { var m = isPopup ? popup.mainItem.popupModel : launcherModel; m.appendUrl(url); } onLauncherEdited: { var m = isPopup ? popup.mainItem.popupModel : launcherModel; m.changeUrl(index, url); } } // States to fix binding loop with enabled popup states: [ State { name: "normal" when: !vertical PropertyChanges { target: popupArrow width: units.iconSizes.smallMedium height: root.height } }, State { name: "vertical" when: vertical PropertyChanges { target: popupArrow width: root.width height: units.iconSizes.smallMedium } } ] Connections { target: plasmoid.configuration onLauncherUrlsChanged: { launcherModel.urlsChanged.disconnect(saveConfiguration); launcherModel.setUrls(plasmoid.configuration.launcherUrls); launcherModel.urlsChanged.connect(saveConfiguration); } } Component.onCompleted: { launcherModel.setUrls(plasmoid.configuration.launcherUrls); launcherModel.urlsChanged.connect(saveConfiguration); plasmoid.setAction("addLauncher", i18n("Add Launcher..."), "list-add"); } function action_addLauncher() { logic.addLauncher(); } function saveConfiguration() { if (!dragging) { plasmoid.configuration.launcherUrls = launcherModel.urls(); } } function isInternalDrop(event) { return event.mimeData.source && event.mimeData.source.GridView && event.mimeData.source.GridView.view == grid; } }