1// SPDX-FileCopyrightText: 2016 Artem Fedoskin <afedoskin3@gmail.com>
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4import QtQuick 2.7
5
6import QtQuick.Controls 2.0
7import QtQuick.Controls.Material 2.0
8
9import QtQuick.Window 2.2 as Window
10import QtQuick.Layouts 1.1
11
12import "modules"
13import "modules/helpers"
14import "modules/popups"
15import "modules/menus"
16import "modules/tutorial"
17
18
19import "dialogs"
20import "dialogs/menus"
21import "dialogs/helpers"
22
23import "constants" 1.0
24import "indi"
25
26ApplicationWindow {
27    id: window
28    objectName: "window"
29    width: Window.Screen.desktopAvailableWidth
30    height: Window.Screen.desktopAvailableHeight
31    visible: true
32
33    //Application properties
34    property bool isLoaded: false
35    property bool isPortrait: width < height ? true: false
36    property bool isSkyMapVisible: stackView.currentItem == initPage
37    signal loaded();
38
39    onIsLoadedChanged: {
40        if(isLoaded) {
41            loaded()
42            if(KStarsLite.runTutorial) tutorialPopup.open()
43        }
44    }
45
46    header: ToolBar {
47        id: toolBar
48        Material.foreground: "white"
49        height: stackView.currentItem != initPage ? backButton.height : 0
50        visible: stackView.currentItem != initPage
51
52        /*background: Rectangle {
53            anchors.fill: parent
54            color: Num.sysPalette.dark
55        }*/
56
57        Behavior on height {
58            NumberAnimation {
59                duration: 200
60                easing.type: Easing.InOutQuad
61            }
62        }
63
64        Row {
65            id: toolRow
66            spacing: 20
67            height: parent.height
68            width: parent.width
69
70            ToolButton {
71                id: backButton
72                contentItem: Image {
73                    fillMode: Image.Pad
74                    horizontalAlignment: Image.AlignHCenter
75                    verticalAlignment: Image.AlignVCenter
76                    source: "images/back.png"
77                }
78                onClicked: {
79                    if(stackView.depth != 1) stackView.pop()
80                }
81            }
82
83            KSLabel {
84                id: titleLabel
85                text: stackView.currentItem.title
86
87                font.pixelSize: 20
88                width: parent.width - backButton.width - toolRow.spacing //To allow ellision of the text
89
90                elide: Label.ElideRight
91                wrapMode: Label.Wrap
92                maximumLineCount: 1
93
94                anchors.verticalCenter: parent.verticalCenter
95            }
96        }
97    }
98
99    Splash {
100        z:1
101        anchors.fill:parent
102        onTimeout: {
103            isLoaded = true
104        }
105    }
106
107    StackView {
108        visible: isLoaded
109        id: stackView
110        anchors.fill: parent
111        initialItem: initPage
112    }
113
114    Units {
115        id: units
116    }
117
118    //Dialogs
119    FindDialog {
120        id: findDialog
121    }
122
123    //Details
124    DetailsDialog {
125        id: detailsDialog
126    }
127
128    DetailsAddLink {
129        id: detailsAddLink
130    }
131
132    DetailsLinkMenu {
133        id: detailsLinkMenu
134        x: (window.width - width)/2
135        y: (window.height - height)/2
136    }
137
138    //Location
139    LocationDialog {
140        id: locationDialog
141    }
142
143    LocationEdit {
144        id: locationEdit
145    }
146
147    LocationLoading {
148        id: locationLoading
149    }
150
151    AboutDialog {
152        id: aboutDialog
153    }
154
155    //Pages
156    INDIControlPanel {
157        id: indiControlPanel
158    }
159
160    Page {
161        id: initPage
162        title: xi18n("Sky Map")
163        padding: 0
164
165        Rectangle {
166            anchors.fill: parent
167            color: "black" //Color scheme
168        }
169    }
170
171    SkyMapLiteWrapper {
172        /*The reason SkyMapLite is a not a child of initPage is that it can't handle properly change of
173          opacity. Each time we go from / to initPage this component is made invisible / visible and
174        skyMapLiteWrapper is anchored to fill null / parent*/
175        id: skyMapLite
176        anchors.fill: parent
177    }
178
179    //Popups
180    TimePage {
181        id: timePage
182    }
183
184    ColorSchemePopup {
185        id: colorSchemePopup
186        x: (window.width - width)/2
187        y: (window.height - height)/2
188    }
189
190    ProjectionsPopup {
191        id: projPopup
192        x: (window.width - width)/2
193        y: (window.height - height)/2
194    }
195
196    FOVPopup {
197        id: fovPopup
198        x: (window.width - width)/2
199        y: (window.height - height)/2
200    }
201
202    TutorialPopup {
203        id: tutorialPopup
204        x: (window.width - width)/2
205        y: (window.height - height)/2
206    }
207
208    TutorialExitPopup {
209        id: tutorialExitPopup
210        x: (window.width - width)/2
211        y: (window.height - height)/2
212    }
213
214    //Menus
215    ContextMenu {
216        id: contextMenu
217        x: (window.width - width)/2
218        y: (window.height - height)/2
219    }
220
221    LocationsGeoMenu {
222        id: locationsGeoMenu
223        x: (window.width - width)/2
224        y: (window.height - height)/2
225    }
226
227    Drawer {
228        id: globalDrawer
229        objectName: "globalDrawer"
230        width: Math.min(window.width, window.height) / 4 * 2
231        height: window.height
232        //Disable drawer while loading
233        dragMargin: isLoaded ? Qt.styleHints.startDragDistance : -Qt.styleHints.startDragDistance
234        background: Rectangle {
235            anchors.fill: parent
236            color: Num.sysPalette.base
237        }
238
239        onOpened: {
240            contextDrawer.close()
241        }
242
243        Image {
244            id: drawerBanner
245            source: "images/kstars.png"
246            fillMode: Image.PreserveAspectFit
247
248            anchors {
249                left: parent.left
250                top: parent.top
251                right: parent.right
252            }
253        }
254
255        ListView {
256            clip: true
257            id: pagesList
258            anchors {
259                left: parent.left
260                top: drawerBanner.bottom
261                right: parent.right
262                bottom: parent.bottom
263            }
264
265            delegate: ItemDelegate {
266                id: globalDrawerControl
267                Rectangle {
268                    anchors {
269                        horizontalCenter: parent.horizontalCenter
270                        bottom: parent.bottom
271                    }
272                    width: parent.width - 10
273                    color: "#E8E8E8"
274                    height: 1
275                }
276
277                contentItem: KSText {
278                    rightPadding: globalDrawerControl.spacing
279                         text: globalDrawerControl.text
280                         font: globalDrawerControl.font
281                         elide: Text.ElideRight
282                         visible: globalDrawerControl.text
283                         horizontalAlignment: Text.AlignLeft
284                         verticalAlignment: Text.AlignVCenter
285                }
286
287                width: parent.width
288                text: model.objID.title
289                onClicked: {
290                    if(stackView.currentItem != model.objID) {
291                        if(model.objID != initPage) {
292                            stackView.replace(null, [initPage, model.objID])
293                        } else {
294                            stackView.replace(null, initPage)
295                        }
296                        globalDrawer.close()
297                    }
298                }
299            }
300
301            property ListModel drawerModel : ListModel {
302                //Trick to enable storing of object ids
303                Component.onCompleted: {
304                    append({objID: initPage});
305                    append({objID: indiControlPanel});
306                    append({objID: findDialog});
307                    append({objID: locationDialog});
308                    append({objID: aboutDialog});
309                }
310            }
311
312            model: drawerModel
313
314            ScrollIndicator.vertical: ScrollIndicator { }
315        }
316    }
317
318    //Study mode
319    property bool step1: false
320    property bool step2: false
321    property bool step3: false
322    property bool step4: false
323    property bool step5: false
324
325    function askExitTutorial() {
326        tutorialExitPopup.open()
327    }
328
329    function exitTutorial() {
330        KStarsLite.runTutorial = false
331        tutorialPopup.close()
332        step1 = false
333        step2 = false
334        step3 = false
335        step4 = false
336        step5 = false
337    }
338
339    //Step 1 - Global Drawer
340    TutorialStep1 {
341
342    }
343
344    //Step 2 - Context Drawer
345    TutorialStep2 {
346
347    }
348
349    //Step 5 - Location
350    TutorialStep5 {
351
352    }
353
354    Drawer {
355        id: contextDrawer
356        objectName: "contextDrawer"
357        width: Math.min(window.width, window.height) / 4 * 2
358        height: window.height
359        //Disable drawer while loading and if SkyMapLite is not visible
360        dragMargin: isSkyMapVisible && isLoaded ? Qt.styleHints.startDragDistance + 15 : -Qt.styleHints.startDragDistance
361        edge: Qt.RightEdge
362        background: Rectangle {
363            anchors.fill: parent
364            color: Num.sysPalette.base
365        }
366
367        onOpened: {
368            globalDrawer.close()
369        }
370
371        KSLabel {
372            id: contextTitle
373            anchors {
374                top: parent.top
375                left: parent.left
376                margins: 10
377            }
378
379            font.pointSize: 14
380            text: stackView.currentItem.title
381        }
382
383        ListView {
384            id: contextList
385            anchors {
386                left: parent.left
387                top: contextTitle.bottom
388                right: parent.right
389                bottom: parent.bottom
390                topMargin: 15
391            }
392            model: drawerModel
393
394            delegate: ItemDelegate {
395                id: contextDrawerControl
396                Rectangle {
397                    anchors {
398                        horizontalCenter: parent.horizontalCenter
399                        bottom: parent.bottom
400                    }
401                    width: parent.width - 10
402                    color: "#E8E8E8"
403                    height: 1
404                }
405
406                width: parent.width
407                text: model.title
408                onClicked: {
409                    if(model.type == "popup") {
410                        objID.open()
411                    }
412
413                    contextDrawer.close()
414                }
415
416                contentItem: KSText {
417                    rightPadding: contextDrawerControl.spacing
418                         text: contextDrawerControl.text
419                         font: contextDrawerControl.font
420                         elide: Text.ElideRight
421                         visible: contextDrawerControl.text
422                         horizontalAlignment: Text.AlignLeft
423                         verticalAlignment: Text.AlignVCenter
424                }
425            }
426
427            property ListModel drawerModel : ListModel {
428                //Trick to enable storing of object ids
429                Component.onCompleted: {
430                    append({title: xi18n("Projection systems"), objID: projPopup, type: "popup"});
431                    append({title: xi18n("Color Schemes"), objID: colorSchemePopup, type: "popup"});
432                    append({title: xi18n("FOV Symbols"), objID: fovPopup, type: "popup"});
433                }
434            }
435
436            ScrollIndicator.vertical: ScrollIndicator { }
437        }
438
439        ColumnLayout {
440            anchors {
441                left: parent.left
442                right: parent.right
443                bottom: parent.bottom
444            }
445
446            RowLayout {
447                id: magnitudeRow
448                anchors {
449                    leftMargin: 10
450                    left: parent.left
451                    rightMargin: 10
452                    right: parent.right
453                }
454
455                property color magnitudeColor: colorSchemePopup.currentCScheme == "cs_night" ? "white" : "black"
456
457                Rectangle {
458                    anchors{
459                        left: parent.left
460                        bottom: smallestMag.bottom
461                    }
462
463                    width: 24
464                    height: 24
465                    radius: width * 0.5
466                    color: magnitudeRow.magnitudeColor
467                }
468
469                Rectangle {
470                    anchors{
471                        horizontalCenter: parent.horizontalCenter
472                        bottom: smallestMag.bottom
473                    }
474
475                    width: 16
476                    height: 16
477                    radius: width * 0.5
478                    color: magnitudeRow.magnitudeColor
479                }
480
481                Rectangle {
482                    id: smallestMag
483
484                    anchors {
485                        right: parent.right
486                        verticalCenter: parent.bottom
487                    }
488
489                    width: 8
490                    height: 8
491                    radius: width * 0.5
492                    color: magnitudeRow.magnitudeColor
493                }
494            }
495
496            Slider {
497                id: magSlider
498                anchors {
499                    left: parent.left
500                    right: parent.right
501                }
502
503                from: 1.18778
504                to: 5.75954
505                value: SkyMapLite.magLim
506
507                onValueChanged: {
508                    SkyMapLite.magLim = value
509                }
510            }
511        }
512    }
513
514    //Handle back button
515    Connections {
516        target: window
517        onClosing: {
518            if (Qt.platform.os == "android") {
519                if(stackView.depth > 1) {
520                    close.accepted = false;
521                    stackView.pop()
522                }
523            }
524        }
525    }
526}
527