7.4 KiB · text History cc97953
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.plasmoid
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami as Kirigami

import "Lambent.js" as L

// The Lambent logo followed by one circle per place (or chosen device).
// The logo opens everything; a circle opens just its own place. Scrolling
// steps the matching brightness clamp: the global one over the logo, the
// place's over a circle. Used both as the panel representation and as a
// filter bar at the top of the popup.
Item {
    id: strip

    required property var store
    property bool inPanel: true

    readonly property bool vertical: inPanel && Plasmoid.formFactor === PlasmaCore.Types.Vertical
    // Panel thickness drives circle size; in the popup use a fixed size.
    readonly property real cell: inPanel
        ? Math.max(Kirigami.Units.iconSizes.small,
                   Math.min(vertical ? width : height, Kirigami.Units.iconSizes.medium))
        : Kirigami.Units.iconSizes.smallMedium + Kirigami.Units.smallSpacing
    readonly property bool showCircles: store.hasValidConfig && store.connected
    readonly property int count: (showCircles ? circles.count : 0) + 1

    Layout.minimumWidth: inPanel && !vertical ? count * cell + (count - 1) * flow.spacing : -1
    Layout.preferredWidth: Layout.minimumWidth
    Layout.minimumHeight: inPanel && vertical ? count * cell + (count - 1) * flow.spacing : flow.implicitHeight
    Layout.preferredHeight: Layout.minimumHeight
    implicitHeight: flow.implicitHeight

    // Mouse wheels report in eighths of a degree, 120 to a notch; a
    // touchpad sends a stream of small ones. Step once per notch's worth.
    function wheelSteps(holder, wheel) {
        holder.acc += wheel.angleDelta.y !== 0 ? wheel.angleDelta.y : -wheel.angleDelta.x
        var steps = 0
        while (holder.acc >= 120) { holder.acc -= 120; steps++ }
        while (holder.acc <= -120) { holder.acc += 120; steps-- }
        return steps
    }

    Flow {
        id: flow
        anchors.fill: strip.inPanel ? parent : undefined
        width: strip.inPanel ? undefined : strip.width
        flow: strip.vertical ? Flow.TopToBottom : Flow.LeftToRight
        spacing: strip.inPanel ? 0 : Kirigami.Units.smallSpacing

        // ── logo: everything, global clamp ──────────────────────────────
        Item {
            width: strip.cell
            height: strip.cell

            Rectangle {
                anchors.fill: parent
                radius: Kirigami.Units.cornerRadius
                color: Kirigami.Theme.highlightColor
                opacity: logoMouse.containsMouse ? 0.2
                         : (!strip.inPanel && strip.store.focusKey === "") ? 0.3 : 0
            }

            Kirigami.Icon {
                anchors.fill: parent
                anchors.margins: parent.width * 0.08
                source: strip.store.logoSource
                // Full colour once connected; greyed out until then.
                isMask: !strip.store.connected
                color: Kirigami.Theme.disabledTextColor
                opacity: (strip.store.rev, 0.45 + 0.55 * strip.store.globalClamp.curr / 255)
            }

            PlasmaCore.ToolTipArea {
                anchors.fill: parent
                mainText: i18n("Lambent")
                textFormat: Text.RichText
                subText: (strip.store.rev,
                          !strip.store.available ? strip.store.statusText()
                          : !strip.store.hasValidConfig ? i18n("Click to configure the connection")
                          : !strip.store.connected ? strip.store.statusText()
                          : i18n("Global brightness: %1", L.rungName(strip.store.globalClamp.tgt, strip.store.ladder))
                            + "<br/>" + i18n("Click to see everything")
                            + (strip.store.wheelBrightness ? "<br/><small>" + i18n("Scroll to dim or brighten everything") + "</small>" : ""))
            }

            MouseArea {
                id: logoMouse
                property int acc: 0
                anchors.fill: parent
                hoverEnabled: true
                onClicked: {
                    if (!strip.store.hasValidConfig || !strip.store.available) {
                        Plasmoid.internalAction("configure").trigger()
                    } else if (strip.inPanel) {
                        strip.store.openAll()
                    } else {
                        strip.store.focusKey = ""
                    }
                }
                onWheel: function(wheel) {
                    if (!strip.store.wheelBrightness || !strip.store.connected) {
                        wheel.accepted = false
                        return
                    }
                    var steps = strip.wheelSteps(logoMouse, wheel)
                    for (var i = 0; i < Math.abs(steps); i++) strip.store.clampStep("", steps > 0)
                }
            }
        }

        // ── one circle per place / chosen device ────────────────────────
        Repeater {
            id: circles
            model: strip.showCircles ? strip.store.circlesModelRef : null

            delegate: Item {
                id: circleItem

                required property string key
                required property string label

                readonly property var info: (strip.store.rev, strip.store.circleInfo(key))
                readonly property string place: (strip.store.rev, (strip.store.circleDefs[key] || {}).place || "")
                readonly property bool selected: strip.store.focusKey === key && (!strip.inPanel || strip.store.expanded)

                width: strip.cell
                height: strip.cell

                PixelCircle {
                    anchors.fill: parent
                    anchors.margins: strip.inPanel ? strip.cell * 0.15 : 0
                    lit: circleItem.info.lit
                    pixels: circleItem.info.pixels
                    level: circleItem.info.level
                    walking: circleItem.info.walking
                    highlighted: mouse.containsMouse || circleItem.selected
                }

                PlasmaCore.ToolTipArea {
                    anchors.fill: parent
                    mainText: circleItem.label
                    subText: (strip.store.rev, strip.store.circleTooltip(circleItem.key))
                    textFormat: Text.RichText
                }

                MouseArea {
                    id: mouse
                    property int acc: 0
                    anchors.fill: parent
                    hoverEnabled: true
                    onClicked: {
                        if (strip.inPanel) strip.store.openCircle(circleItem.key)
                        else strip.store.focusKey = strip.store.focusKey === circleItem.key ? "" : circleItem.key
                    }
                    onWheel: function(wheel) {
                        if (!strip.store.wheelBrightness) {
                            wheel.accepted = false
                            return
                        }
                        var steps = strip.wheelSteps(mouse, wheel)
                        // a device with no place has only the global clamp
                        for (var i = 0; i < Math.abs(steps); i++) strip.store.clampStep(circleItem.place, steps > 0)
                    }
                }
            }
        }
    }
}