Skip to content
Snippets Groups Projects
LunaIcon.qml 9.35 KiB
Newer Older
  • Learn to ignore specific revisions
  • samuel's avatar
    samuel committed
        Copyright (C) 2024 Samuel Jimenez <therealsamueljimenez@gmail.com>
              Ported the Luna Plasmoid to Plasma 6.
    
    
        Copyright 2016,2017 Bill Binder <dxtwjb@gmail.com>
    
        Copyright (C) 2011, 2012, 2013 Glad Deschrijver <glad.deschrijver@gmail.com>
    
        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 3 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, see <http://www.gnu.org/licenses/>.
    
    */
    
    
    samuel's avatar
    samuel committed
    import QtQuick 2.14
    import QtQuick.Shapes
    
    samuel's avatar
    samuel committed
    import org.kde.ksvg as KSvg
    import org.kde.plasma.core as PlasmaCore
    import org.kde.plasma.plasmoid
    
    wwjjbb's avatar
    wwjjbb committed
        id: lunaIcon
    
        property int phaseNumber: 0
    
    samuel's avatar
    samuel committed
        property int latitude: 90 //Degrees: 0=Equator, 90=North Pole, -90=South Pole
    
        property bool showShadow: true
    
        property bool transparentShadow: true
    
        property string lunarImage: ''
    
    samuel's avatar
    samuel committed
        property color diskColor: '#ffffff'
    
        property int lunarImageTweak: 0
    
    dxtwjb's avatar
    dxtwjb committed
        property bool showGrid: false
        property bool showTycho: false
        property bool showCopernicus: false
    
    samuel's avatar
    samuel committed
        property int theta: 45 // Degrees: 0= new moon, 90= first quarter, 180= full moon, 270= third quarter
    
    samuel's avatar
    samuel committed
        Item {
            id: lunaBackground
    
    samuel's avatar
    samuel committed
    
    
    samuel's avatar
    samuel committed
            anchors.centerIn: parent
            width: Math.min(parent.width, parent.height)
            height: Math.min(parent.width, parent.height)
    
    samuel's avatar
    samuel committed
            visible: false
    
    wwjjbb's avatar
    wwjjbb committed
        }
    
    
    samuel's avatar
    samuel committed
        Item {
            id: lunaTexture
    
    
            anchors.centerIn: parent
    
    samuel's avatar
    samuel committed
            width: lunaBackground.width
            height: lunaBackground.height
    
    samuel's avatar
    samuel committed
            visible: false
            layer.enabled: true
            layer.smooth: true
    
    samuel's avatar
    samuel committed
    
    
    samuel's avatar
    samuel committed
            KSvg.SvgItem {
                id: lunaSvgItem
    
    samuel's avatar
    samuel committed
    
    
    samuel's avatar
    samuel committed
                imagePath: lunarImage === '' ? '' : Qt.resolvedUrl("../data/" + lunarImage)
                visible: true
                anchors.centerIn: parent
                width: lunaBackground.width
                height: lunaBackground.height
                // Rotation to compensate the moon's image basic position to a north pole view
                transformOrigin: Item.Center
                rotation: latitude - 90 - lunarImageTweak
    
    samuel's avatar
    samuel committed
            }
    
    
    samuel's avatar
    samuel committed
            Shape {
                id: lunaCanvas
    
    samuel's avatar
    samuel committed
                property string lunarImage: lunaIcon.lunarImage
                property string diskColor: lunaIcon.diskColor
    
    samuel's avatar
    samuel committed
                opacity: (lunarImage === '') ? 1 : 0
                width: lunaBackground.width
                height: lunaBackground.height
                visible: true
                anchors.centerIn: parent
                preferredRendererType: Shape.CurveRenderer
    
    samuel's avatar
    samuel committed
    
    
    samuel's avatar
    samuel committed
                ShapePath {
                    fillColor: diskColor
                    strokeWidth: -1 //no stroke
    
                    PathAngleArc {
                        property int radius: Math.floor(height / 2)
    
                        centerX: radius
                        centerY: radius
                        radiusY: radius
                        radiusX: radius
                        startAngle: 0
                        sweepAngle: 360
                    }
    
    samuel's avatar
    samuel committed
    
                }
    
    samuel's avatar
    samuel committed
    
    
    samuel's avatar
    samuel committed
            }
    
    
    samuel's avatar
    samuel committed
            Canvas {
                id: shadow
    
                property int latitude: lunaIcon.latitude
                property int theta: lunaIcon.theta
                property bool showShadow: lunaIcon.showShadow
    
                width: lunaBackground.width
                height: lunaBackground.height
                visible: true
                anchors.centerIn: parent
                contextType: "2d"
                onLatitudeChanged: requestPaint()
                onThetaChanged: requestPaint()
                onShowShadowChanged: requestPaint()
                onPaint: {
                    context.reset();
                    if (showShadow) {
                        var radius = Math.floor(height / 2);
                        var cosTheta = Math.cos(theta / 180 * Math.PI);
                        var counterclockwisep = (theta < 180);
                        context.globalAlpha = 0.9;
                        context.translate(radius, radius);
                        context.rotate((latitude - 90) / 180 * Math.PI);
                        if (theta != 180) {
                            context.beginPath();
                            context.fillStyle = '#000000';
                            context.strokeStyle = '#000000';
                            context.arc(0, 0, radius, -0.5 * Math.PI, 0.5 * Math.PI, counterclockwisep);
                            if ((theta % 180) != 90) {
                                context.scale(cosTheta, 1);
                                context.arc(0, 0, radius, 0.5 * Math.PI, -0.5 * Math.PI, counterclockwisep);
                            }
                            context.closePath();
                            context.fill();
                            context.stroke();
    
    samuel's avatar
    samuel committed
                        }
    
    samuel's avatar
    samuel committed
                    }
    
    samuel's avatar
    samuel committed
                }
            }
    
            Canvas {
                id: markers
    
                property int latitude: lunaIcon.latitude
                property int theta: lunaIcon.theta
                property bool showShadow: lunaIcon.showShadow
                property bool showGrid: lunaIcon.showGrid
                property bool showTycho: lunaIcon.showTycho
                property bool showCopernicus: lunaIcon.showCopernicus
    
                function radians(deg) {
                    return deg / 180 * Math.PI;
                }
    
                function marker(radius, latitude, longitude) {
                    var dy = radius * Math.sin(radians(latitude));
                    var dx = radius * Math.cos(radians(latitude)) * Math.sin(radians(longitude));
                    // console.log("dx: " + dx.toString());
                    // console.log("dy: " + dy.toString());
                    context.beginPath();
                    context.strokeStyle = "#FF0000";
                    context.arc(dx, -dy, 5, 0, 2 * Math.PI);
                    context.moveTo(dx - 5, -dy - 5);
                    context.lineTo(dx + 5, -dy + 5);
                    context.moveTo(dx - 5, -dy + 5);
                    context.lineTo(dx + 5, -dy - 5);
                    context.stroke();
                }
    
                function grid(radius) {
                    context.beginPath();
                    context.strokeStyle = "#FF4040";
                    context.moveTo(0, -radius);
                    context.lineTo(0, radius);
                    context.moveTo(-radius, 0);
                    context.lineTo(radius, 0);
                    context.stroke();
                    context.beginPath();
                    context.strokeStyle = "#40FF40";
                    for (var ll = 10; ll < 65; ll += 10) {
                        var dy = radius * Math.sin(radians(ll));
                        context.moveTo(-radius, dy);
                        context.lineTo(radius, dy);
                        context.moveTo(-radius, -dy);
                        context.lineTo(radius, -dy);
                    }
                    context.stroke();
                }
    
                width: lunaBackground.width
                height: lunaBackground.height
                visible: true
                anchors.centerIn: parent
                contextType: "2d"
                onLatitudeChanged: requestPaint()
                onThetaChanged: requestPaint()
                onShowGridChanged: requestPaint()
                onShowTychoChanged: requestPaint()
                onShowCopernicusChanged: requestPaint()
                onShowShadowChanged: requestPaint()
                onPaint: {
                    context.reset();
                    if (!showShadow) {
                        var radius = Math.floor(height / 2);
                        var cosTheta = Math.cos(theta / 180 * Math.PI);
                        var counterclockwisep = (theta < 180);
                        context.globalAlpha = 0.9;
                        context.translate(radius, radius);
                        context.rotate((latitude - 90) / 180 * Math.PI);
                        // Calibration markers
                        if (showGrid)
                            grid(radius);
    
    samuel's avatar
    samuel committed
    
    
    samuel's avatar
    samuel committed
                        // Tycho
                        if (showTycho)
                            marker(radius, -43, -11.5);
    
    samuel's avatar
    samuel committed
    
    
    samuel's avatar
    samuel committed
                        // Copernicus
                        if (showCopernicus)
                            marker(radius, 9.6, -20);
    
    samuel's avatar
    samuel committed
                    }
    
    samuel's avatar
    samuel committed
    
    
    samuel's avatar
    samuel committed
        ShaderEffectSource {
            id: lunaMask
    
    samuel's avatar
    samuel committed
    
    
    samuel's avatar
    samuel committed
            anchors.centerIn: parent
            width: lunaBackground.width
            height: lunaBackground.height
    
    samuel's avatar
    samuel committed
            visible: false
    
    
    samuel's avatar
    samuel committed
            sourceItem: Shape {
                opacity: 1
                width: lunaBackground.width
                height: lunaBackground.height
                visible: true
                anchors.centerIn: parent
                preferredRendererType: Shape.CurveRenderer
    
                ShapePath {
                    fillColor: '#000000'
                    strokeWidth: -1 //no stroke
    
                    PathAngleArc {
                        property int radius: Math.floor(height / 2)
    
                        centerX: radius
                        centerY: radius
                        radiusY: radius
                        radiusX: radius
                        startAngle: 0
                        sweepAngle: 360
                    }
    
                }
    
            }
    
    
    samuel's avatar
    samuel committed
        ShaderEffect {
            property variant source: lunaTexture
            property variant shadow: shadow
            property variant mask: lunaMask
            property int transparent: transparentShadow
    
            visible: true
    
    samuel's avatar
    samuel committed
            anchors.fill: lunaBackground
    
    samuel's avatar
    samuel committed
            fragmentShader: "shadow.gsb"
    
    samuel's avatar
    samuel committed