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