Warning, /plasma/kdeplasma-addons/applets/colorpicker/package/contents/ui/main.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 import QtQuick
0008 import QtQuick.Controls as QQC2
0009 import QtQuick.Layouts
0010 import QtQuick.Dialogs as QtDialogs
0011 
0012 import org.kde.plasma.plasmoid 2.0
0013 import org.kde.plasma.core as PlasmaCore
0014 import org.kde.plasma.components 3.0 as PlasmaComponents3
0015 import org.kde.plasma.extras 2.0 as PlasmaExtras
0016 import org.kde.kirigami 2.20 as Kirigami
0017 import org.kde.kcmutils as KCMUtils
0018 import org.kde.config as KConfig
0019 import org.kde.kwindowsystem 1.0
0020 
0021 import org.kde.plasma.private.colorpicker 2.0 as ColorPicker
0022 import "logic.js" as Logic
0023 
0024 PlasmoidItem {
0025     id: root
0026 
0027     readonly property bool isVertical: Plasmoid.formFactor === PlasmaCore.Types.Vertical
0028 
0029     readonly property color recentColor: historyModel.count > 0 ? historyModel.get(0).color : "#00000000" // transparent as fallback
0030     readonly property string defaultFormat: Plasmoid.configuration.defaultFormat
0031     readonly property int maxColorCount: 9
0032 
0033     preferredRepresentation: compactRepresentation
0034 
0035     function addColorToHistory(color) {
0036         // this .toString() is needed otherwise Qt completely screws it up
0037         // replacing *all* items in the list by the new items and other nonsense
0038         historyModel.insert(0, { color: color.toString() });
0039         // limit to 9 entries
0040         if (historyModel.count > maxColorCount) {
0041             historyModel.remove(maxColorCount);
0042         }
0043         historyModel.save();
0044     }
0045 
0046     function colorPicked(color) {
0047         if (color != recentColor) {
0048             addColorToHistory(color)
0049         }
0050 
0051         if (Plasmoid.configuration.autoClipboard) {
0052             picker.copyToClipboard(Logic.formatColor(color, root.defaultFormat))
0053         }
0054     }
0055 
0056     function pickColor() {
0057         root.expanded = false
0058         picker.pick()
0059     }
0060 
0061     ColorPicker.GrabWidget {
0062         id: picker
0063         onCurrentColorChanged: colorPicked(currentColor)
0064     }
0065 
0066     Component {
0067         id: colorWindowComponent
0068 
0069         Window { // QTBUG-119055
0070             id: window
0071             width: Kirigami.Units.gridUnit * 19
0072             height: Kirigami.Units.gridUnit * 23
0073             visible: true
0074             title: Plasmoid.title
0075             QtDialogs.ColorDialog {
0076                 id: colorDialog
0077                 title: Plasmoid.title
0078                 selectedColor: historyModel.count > 0 ? root.recentColor : undefined /* Prevent transparent colors */
0079                 onAccepted: {
0080                     root.colorPicked(selectedColor);
0081                     window.destroy();
0082                 }
0083                 onRejected: window.destroy()
0084             }
0085             onClosing: destroy()
0086             Component.onCompleted: colorDialog.open()
0087         }
0088     }
0089 
0090     // prevents the popup from actually opening, needs to be queued
0091     Timer {
0092         id: delayedPickTimer
0093         interval: 0
0094         onTriggered: root.pickColor()
0095     }
0096 
0097     ListModel {
0098         id: historyModel
0099 
0100         function save() {
0101             let history = [];
0102             for (let i = 0; i < count; i++) {
0103                history.push(get(i).color);
0104             }
0105             Plasmoid.configuration.history = history;
0106         }
0107     }
0108 
0109     Plasmoid.onActivated: {
0110         if (Plasmoid.configuration.pickOnActivate) {
0111             delayedPickTimer.start();
0112         }
0113     }
0114 
0115     Plasmoid.contextualActions: [
0116         PlasmaCore.Action {
0117             text: i18nc("@action", "Open Color Dialog")
0118             icon.name: "color-management"
0119             onTriggered: colorWindowComponent.createObject(root)
0120         },
0121         PlasmaCore.Action {
0122             text: i18nc("@action", "Clear History")
0123             icon.name: "edit-clear-history"
0124             onTriggered: {
0125                 historyModel.clear();
0126                 historyModel.save();
0127             }
0128         },
0129         PlasmaCore.Action {
0130             text: i18nc("@action", "View History")
0131             icon.name: "view-history"
0132             onTriggered: root.expanded = true
0133         }
0134     ]
0135 
0136     Component.onCompleted: {
0137         Plasmoid.configuration.history.forEach(item => historyModel.append({ color: item }));
0138         Logic.copyToClipboardText = i18ndc("plasma_applet_org.kde.plasma.colorpicker", "@title:menu", "Copy to Clipboard"); // i18n is not supported in js library
0139     }
0140 
0141     compactRepresentation: CompactRepresentation { }
0142 
0143     fullRepresentation: GridView {
0144         id: fullRoot
0145 
0146         readonly property int columns: 3
0147 
0148         Layout.minimumWidth: columns * Kirigami.Units.gridUnit * 6
0149         Layout.minimumHeight: Layout.minimumWidth
0150         Layout.maximumWidth: Layout.minimumWidth
0151         Layout.maximumHeight: Layout.minimumHeight
0152 
0153         cellWidth: Math.floor(fullRoot.width / fullRoot.columns)
0154         cellHeight: cellWidth
0155         boundsBehavior: Flickable.StopAtBounds
0156 
0157         model: historyModel
0158 
0159         highlight: PlasmaExtras.Highlight {}
0160         highlightMoveDuration: 0
0161 
0162         Loader {
0163             width: parent.width - Kirigami.Units.gridUnit * 2
0164             anchors.centerIn: parent
0165             visible: active
0166 
0167             active: fullRoot.count === 0 && root.expanded
0168             asynchronous: true
0169 
0170             sourceComponent: PlasmaExtras.PlaceholderMessage {
0171                 id: emptyHint
0172 
0173                 opacity: 0
0174                 iconName: "edit-none"
0175 
0176                 readonly property bool compositingActive: KWindowSystem.isPlatformWayland || KX11Extras.compositingActive
0177 
0178                 text: compositingActive ? i18nc("@info:usagetip", "No colors") : i18nc("@info:status when color picking is unavailable", "Color picking unavailable when compositing is disabled")
0179                 explanation: compositingActive ? "" : i18nc("@info:status when color pick is unavailable", "Compositing has been manually disabled or blocked by a running application")
0180 
0181                 helpfulAction: compositingActive ? pickColorAction : enableCompositingAction
0182 
0183                 QQC2.Action {
0184                     id: pickColorAction
0185                     icon.name: "color-picker"
0186                     text: i18nc("@action:button", "Pick Color")
0187                     onTriggered: root.pickColor()
0188                 }
0189 
0190                 QQC2.Action {
0191                     id: enableCompositingAction
0192                     enabled: KConfig.KAuthorized.authorizeControlModule("kwincompositing")
0193                     icon.name: "settings-configure"
0194                     text: i18nc("@action:button open kwincompositing KCM", "Configure Compositing")
0195                     onTriggered: KCMUtils.KCMLauncher.openSystemSettings("kwincompositing")
0196                 }
0197 
0198                 NumberAnimation {
0199                     duration: Kirigami.Units.longDuration
0200                     easing.type: Easing.OutCubic
0201                     property: "opacity"
0202                     running: true
0203                     target: emptyHint
0204                     to: 1
0205                 }
0206             }
0207         }
0208 
0209         Connections {
0210             target: root
0211             function onExpandedChanged() {
0212                 if (root.expanded) {
0213                     fullRoot.forceActiveFocus()
0214                 }
0215             }
0216         }
0217 
0218         Keys.onPressed: event => {
0219             if (event.key === Qt.Key_Escape) {
0220                 root.expanded = false;
0221                 event.accepted = true;
0222             }
0223         }
0224 
0225         // This item serves as a drag pixmap and is captured when a drag starts
0226         Rectangle {
0227             id: dragImageDummy
0228             border {
0229                 color: Kirigami.Theme.textColor
0230                 width: 1
0231             }
0232             radius: width
0233             width: Kirigami.Units.iconSizes.large
0234             height: Kirigami.Units.iconSizes.large
0235             visible: false
0236         }
0237 
0238         delegate: MouseArea {
0239             id: delegateMouse
0240 
0241             readonly property color currentColor: model.color
0242 
0243             width: fullRoot.cellWidth
0244             height: fullRoot.cellHeight
0245 
0246             drag.target: rect
0247             Drag.dragType: Drag.Automatic
0248             Drag.active: delegateMouse.drag.active
0249             Drag.mimeData: {
0250                 "application/x-color": rect.color,
0251                 "text/plain": colorLabel.text
0252             }
0253 
0254             acceptedButtons: Qt.LeftButton | Qt.RightButton
0255             hoverEnabled: true
0256 
0257             Keys.onDeletePressed: event => remove()
0258             Keys.onPressed: event => {
0259                 switch (event.key) {
0260                 case Qt.Key_Space:
0261                 case Qt.Key_Enter:
0262                 case Qt.Key_Return:
0263                 case Qt.Key_Select:
0264                     copy();
0265                     break;
0266                 case Qt.Key_Menu:
0267                     openMenu();
0268                     break;
0269                 }
0270             }
0271 
0272             Accessible.name: colorLabel.text
0273             Accessible.role: Accessible.ButtonMenu
0274 
0275             onContainsMouseChanged: {
0276                 if (containsMouse) {
0277                     fullRoot.currentIndex = index;
0278                 } else if (fullRoot.currentIndex === index) {
0279                     fullRoot.currentIndex = -1;
0280                 }
0281             }
0282 
0283             onPressed: mouse => {
0284                 // grab pixmap only once
0285                 if (Drag.imageSource.toString() === "") { // cannot just do !Drag.imageSource on QUrl
0286                     dragImageDummy.color = currentColor;
0287                     dragImageDummy.grabToImage(result => {
0288                         Drag.imageSource = result.url;
0289                     });
0290                 }
0291             }
0292 
0293             onClicked: mouse => {
0294                 if (mouse.button === Qt.LeftButton) {
0295                     copy();
0296                 } else if (mouse.button === Qt.RightButton) {
0297                     openMenu();
0298                 }
0299             }
0300 
0301             function copy() {
0302                 picker.copyToClipboard(Logic.formatColor(currentColor, root.defaultFormat))
0303                 colorLabel.visible = false;
0304                 copyIndicatorLabel.visible = true;
0305                 colorLabelRestoreTimer.start()
0306             }
0307 
0308             function openMenu() {
0309                 const menu = Logic.createContextMenu(this, currentColor, picker, colorLabel, copyIndicatorLabel, colorLabelRestoreTimer);
0310                 menu.openRelative();
0311             }
0312 
0313             function remove() {
0314                 historyModel.remove(index);
0315                 historyModel.save();
0316             }
0317 
0318             PlasmaCore.ToolTipArea {
0319                 anchors.fill: parent
0320                 active: colorLabel.truncated
0321                 mainText: colorLabel.text
0322             }
0323 
0324             Timer {
0325                 id: colorLabelRestoreTimer
0326                 interval: Kirigami.Units.humanMoment
0327                 onTriggered: {
0328                     colorLabel.visible = true;
0329                     copyIndicatorLabel.visible = false;
0330                 }
0331             }
0332 
0333             Rectangle {
0334                 id: rect
0335 
0336                 anchors {
0337                     fill: parent
0338                     margins: Kirigami.Units.smallSpacing
0339                 }
0340 
0341                 color: delegateMouse.currentColor
0342 
0343                 border {
0344                     color: Kirigami.Theme.textColor
0345                     width: 1
0346                 }
0347 
0348                 Rectangle {
0349                     anchors {
0350                         bottom: parent.bottom
0351                         left: parent.left
0352                         right: parent.right
0353                         margins: rect.border.width
0354                     }
0355                     height: colorLabel.contentHeight + 2 * Kirigami.Units.smallSpacing
0356                     color: Kirigami.Theme.backgroundColor
0357                     opacity: 0.8
0358 
0359                     PlasmaComponents3.Label {
0360                         id: colorLabel
0361                         anchors.fill: parent
0362                         horizontalAlignment: Text.AlignHCenter
0363                         verticalAlignment: Text.AlignVCenter
0364                         elide: Text.ElideLeft
0365                         fontSizeMode: Text.HorizontalFit
0366                         minimumPointSize: Kirigami.Theme.smallFont.pointSize
0367                         text: Logic.formatColor(delegateMouse.currentColor, root.defaultFormat)
0368                         textFormat: Text.PlainText
0369                     }
0370 
0371                     PlasmaComponents3.Label {
0372                         id: copyIndicatorLabel
0373                         visible: false
0374                         anchors.fill: parent
0375                         horizontalAlignment: Text.AlignHCenter
0376                         verticalAlignment: Text.AlignVCenter
0377                         elide: Text.ElideLeft
0378                         fontSizeMode: Text.HorizontalFit
0379                         minimumPointSize: Kirigami.Theme.smallFont.pointSize
0380                         text: i18nc("@info:progress just copied a color to clipboard", "Copied!")
0381                         textFormat: Text.PlainText
0382                     }
0383                 }
0384             }
0385 
0386             Loader {
0387                 active: parent.containsMouse || Kirigami.Settings.tabletMode || Kirigami.Settings.hasTransientTouchInput
0388                 anchors.right: parent.right
0389                 anchors.top: parent.top
0390                 sourceComponent: PlasmaComponents3.Button {
0391                     text: i18nc("@action:button", "Delete")
0392                     icon.name: "delete"
0393                     display: PlasmaComponents3.AbstractButton.IconOnly
0394 
0395                     onClicked: delegateMouse.remove()
0396 
0397                     PlasmaComponents3.ToolTip {
0398                         text: parent.text
0399                     }
0400                 }
0401             }
0402         }
0403     }
0404 }