🏑 index : quine-global-labs/plasma-desktop.git

/*
    SPDX-FileCopyrightText: 2012, 2015 Sebastian KΓΌgler <sebas@kde.org>
    SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

import QtQuick 2.4
import QtQuick.Layouts 1.4
import QtQuick.Window 2.15
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.20 as Kirigami

import org.kde.kcmutils as KCM

Item {
    id: toolBoxContent

    property alias enterAnimation: enterAnimation
    property alias exitAnimation: exitAnimation

    visible: false
    opacity: 0
    transform: Translate {
        id: translator
    }
    transformOrigin: Item.Center

    Behavior on rotation {
        NumberAnimation {
            duration: Kirigami.Units.shortDuration;
            easing.type: Easing.InOutExpo;
        }
        enabled: visible
    }
    Behavior on x {
        NumberAnimation {
            duration: Kirigami.Units.shortDuration;
            easing.type: Easing.InOutExpo;
        }
        enabled: visible

    }
    Behavior on y {
        NumberAnimation {
            duration: Kirigami.Units.shortDuration;
            easing.type: Easing.InOutExpo;
        }
        enabled: visible
    }

    width: buttonRow.width
    height: buttonRow.height + (touchMode ? backgroundFrame.margins.top + backgroundFrame.margins.bottom : 0)

    state: "topcenter"

    property QtObject container: main
    property int pressedX
    property int pressedY
    property int snapStartX
    property bool snapX: false;
    property bool dragging: false
    readonly property bool touchMode: Kirigami.Settings.hasTransientTouchInput || Kirigami.Settings.tabletMode

    onXChanged: stateTimer.restart()
    onYChanged: stateTimer.restart()

    Timer {
        id: stateTimer
        interval: 0
        onTriggered: updateState()
    }
    function updateState() {
        var container = main;
        //print("    w: " + container.width +"x"+container.height+" : "+x+"/"+y+" tbw: " + toolBoxContent.width);

        var x = toolBoxContent.x - main.x;
        var y = toolBoxContent.y - main.y;

        var cornerSnap = iconWidth

        //top
        if (y + height / 2 < container.height / 2) {
            if (Math.abs(container.width/2 - (x + width/2)) < Kirigami.Units.gridUnit) {
                toolBoxContent.state = "topcenter";
            } else {
                toolBoxContent.state = "top";
            }
        //bottom
        } else {
            if (Math.abs(container.width/2 - (x + height/2)) < Kirigami.Units.gridUnit) {
                toolBoxContent.state = "bottomcenter";
            } else {
                toolBoxContent.state = "bottom";
            }
        }

        if (!mouseArea.pressed) {
            main.placeToolBox(toolBoxContent.state);
        }

        stateTimer.running = false;
    }

    function destroyToolBox() {
        main.toolBoxContent = null;
        toolBoxContent.destroy();
    }

    SequentialAnimation {
        id: enterAnimation

        PropertyAction {
            target: toolBoxContent
            property: "visible"
            value: true
        }
        ParallelAnimation {
            NumberAnimation {
                target: toolBoxContent
                property: "opacity"
                duration: Kirigami.Units.longDuration
                easing.type: Easing.OutCubic
                to: 1
            }
            NumberAnimation {
                target: translator
                property: "y"
                duration: Kirigami.Units.longDuration
                easing.type: Easing.OutCubic
                from: state == "top" || state == "topcenter" ? -height
                    : state == "bottom" || state == "bottomcenter" ? height
                    : 0
                to: 0
            }
        }
    }

    SequentialAnimation {
        id: exitAnimation

        ParallelAnimation {
            NumberAnimation {
                target: toolBoxContent
                property: "opacity"
                duration: Kirigami.Units.longDuration
                easing.type: Easing.InCubic
                to: 0
            }
            NumberAnimation {
                target: translator
                property: "y"
                duration: Kirigami.Units.longDuration
                easing.type: Easing.InCubic
                to: state == "top" || state == "topcenter" ? -toolBoxContent.height
                    : state == "bottom" || state == "bottomcenter" ? toolBoxContent.height
                    : 0
            }
        }
        ScriptAction {
            script: toolBoxContent.destroyToolBox()
        }
    }

    MouseArea {
        id: mouseArea
        anchors {
            fill: parent
            leftMargin: -backgroundFrame.margins.left
            topMargin: touchMode ? 0 : -backgroundFrame.margins.top
            rightMargin: -backgroundFrame.margins.right
            bottomMargin: touchMode ? 0 : -backgroundFrame.margins.bottom
        }
        drag {
            filterChildren: true
            target: main.Plasmoid.immutable ? undefined : toolBoxContent
            minimumX: 0
            maximumX: container.width - toolBoxContent.width
            minimumY: 0
            maximumY: container.height
        }

        hoverEnabled: true

        onPressed: {
            pressedX = toolBoxContent.x
            pressedY = toolBoxContent.y
        }
        onPositionChanged: mouse => {
            if (pressed && (Math.abs(toolBoxContent.x - pressedX) > iconSize ||
                Math.abs(toolBoxContent.y - pressedY) > iconSize)) {
                dragging = true;
            }

            // Center snapping X
            if (snapX && Math.abs(snapStartX - mouse.x) > Kirigami.Units.gridUnit) {
                toolBoxContent.anchors.horizontalCenter = undefined;
                snapX = false;
            } else if (!snapX && Math.abs(main.width/2 - (toolBoxContent.x + toolBoxContent.width/2)) < Kirigami.Units.gridUnit) {
                toolBoxContent.anchors.horizontalCenter = main.horizontalCenter;
                snapStartX = mouse.x;
                snapX = true;
            }
        }

        onReleased: mouse => {
            toolBoxContent.anchors.horizontalCenter = undefined;
            toolBoxContent.anchors.verticalCenter = undefined;
            snapX = false;
            main.Plasmoid.configuration.ToolBoxButtonState = toolBoxContent.state;
            main.Plasmoid.configuration.ToolBoxButtonX = toolBoxContent.x;
            main.Plasmoid.configuration.ToolBoxButtonY = toolBoxContent.y;
            //print("Saved coordinates for ToolBox in config: " + toolBoxContent.x + ", " +toolBoxContent.x);
            if (dragging) {
                main.placeToolBox();
            }
            dragging = false;
            stateTimer.stop();
            updateState();
        }
        onCanceled: dragging = false;

        KSvg.FrameSvgItem {
            id: backgroundFrame
            anchors.fill: parent
            imagePath: "widgets/background"
            width: Math.round(buttonLayout.width + margins.horizontal)
            height: Math.round(buttonLayout.height + margins.vertical)
        }

        Row {
            id: buttonRow
            anchors.centerIn: parent
            spacing: buttonLayout.columnSpacing

            Grid {
                id: buttonLayout
                rowSpacing: Kirigami.Units.smallSpacing
                columnSpacing: rowSpacing

                // Show buttons in two lines if screen space is limited
                readonly property real buttonWidth: addWidgetButton.implicitWidth
                    + addPanelButton.implicitWidth
                    + configureButton.implicitWidth
                    + themeButton.implicitWidth
                    + displaySettingsButton.implicitWidth
                    + manageContainmentsButton.implicitWidth
                    + (touchMode ? menuButton.implicitWidth : 0)
                    + closeButton.implicitWidth
                rows: Math.ceil(buttonWidth / (Screen.width * 0.8))

                PlasmaComponents3.ToolButton {
                    id: addWidgetButton
                    property QtObject qAction: Plasmoid.internalAction("add widgets")
                    text: qAction.text
                    icon.name: "list-add"
                    onClicked: qAction.trigger()
                }

                PlasmaComponents3.ToolButton {
                    id: addPanelButton
                    height: addWidgetButton.height
                    property QtObject qAction: Plasmoid.corona.action("add panel")
                    text: qAction.text
                    icon.name: "list-add"
                    Accessible.role: Accessible.ButtonMenu
                    onClicked: Plasmoid.corona.showAddPanelContextMenu(mapToGlobal(0, height))
                }

                PlasmaComponents3.ToolButton {
                    id: configureButton
                    property QtObject qAction: Plasmoid.internalAction("configure")
                    text: qAction.text
                    icon.name: "preferences-desktop-wallpaper"
                    onClicked: qAction.trigger()
                }

                PlasmaComponents3.ToolButton {
                    id: themeButton
                    text: i18nd("plasma_toolbox_org.kde.desktoptoolbox", "Choose Global Theme…")
                    icon.name: "preferences-desktop-theme-global"
                    onClicked: KCM.KCMLauncher.openSystemSettings("kcm_lookandfeel")
                }

                PlasmaComponents3.ToolButton {
                    id: displaySettingsButton
                    text: i18nd("plasma_toolbox_org.kde.desktoptoolbox", "Configure Display Settings…")
                    icon.name: "preferences-desktop-display"
                    onClicked: KCM.KCMLauncher.openSystemSettings("kcm_kscreen")
                }

                PlasmaComponents3.ToolButton {
                    id: manageContainmentsButton
                    property QtObject qAction: Plasmoid.corona.action("manage-containments")
                    text: qAction.text
                    visible: qAction.visible
                    icon.name: "preferences-system-windows-effect-fadedesktop"
                    onClicked: qAction.trigger()
                }

                PlasmaComponents3.ToolButton {
                    id: menuButton

                    height: addWidgetButton.height
                    visible: touchMode

                    icon.name: "overflow-menu"
                    text: i18ndc("plasma_toolbox_org.kde.desktoptoolbox", "@action:button", "More")

                    onClicked: {
                        container.parent.openContextMenu(mapToGlobal(0, height));
                    }
                }
            }

            PlasmaComponents3.ToolButton {
                id: closeButton
                anchors.verticalCenter: buttonLayout.verticalCenter
                height: addWidgetButton.height
                display: PlasmaComponents3.AbstractButton.IconOnly
                icon.name: "window-close"
                text: i18nd("plasma_toolbox_org.kde.desktoptoolbox", "Exit Edit Mode")
                onClicked: Plasmoid.containment.corona.editMode = false
                PlasmaComponents3.ToolTip {
                    text: closeButton.text
                }
            }
        }
    }
}