Revision control
Copy as Markdown
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtQuick.Shapes
import QtQuick.Controls
import QtQuick.Layouts
Window {
id: mainWindow
property real designWindowWidthRatio: topLevel.zoomRect.width / 997
property real designWindowHeightRatio: topLevel.zoomRect.height / 1024
property int preferredRendererType: curveRendererCheckBox.checked ? Shape.CurveRenderer : Shape.GeometryRenderer
title: qsTr("Weather Forecast")
width: 1280
height: 960
visible: true
color: "white"
FontLoader {
id: workSansRegular
source: "assets/WorkSans-Regular.ttf"
}
Rectangle {
id: bgFill
color: "#9FCBF9"
anchors.fill: parent
}
Item {
id: mapContainer
anchors.left: !settingsDrawer.isLandscape ? parent.left : settingsDrawer.right
anchors.top: !settingsDrawer.isLandscape ? settingsDrawer.bottom : parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
layer.enabled: msaaCheckBox.checked
layer.samples: 4
Item {
property rect selectedRect
property rect zoomTarget: Qt.rect(0, 0, mapshape.width, mapshape.height)
property rect zoomRect: zoomTarget
property real zoomScale: Math.min(width / zoomRect.width, height / zoomRect.height)
property real subScale: 1
property rect overlayRect
property real overlayRotation: 0
anchors.fill: parent
anchors.margins: 10
id: topLevel
transformOrigin: Item.TopLeft
scale: zoomScale > 0 ? zoomScale : 1
Behavior on zoomRect { PropertyAnimation { duration: 500 } }
Europe {
id: mapshape
x: (topLevel.width / topLevel.scale - topLevel.zoomRect.width) / 2 - topLevel.zoomRect.x
y: (topLevel.height / topLevel.scale - topLevel.zoomRect.height) / 2 - topLevel.zoomRect.y
onZoomTo: (child, name, childRect, textRect) => {
if (!child) {
topLevel.zoomTarget = Qt.rect(0, 0, mapshape.width, mapshape.height)
return
}
let x_in = childRect.x
let y_in = childRect.y
let w_in = childRect.width
let h_in = childRect.height
// try to center the target in the map
var x, y, w, h
let ar_in = h_in / w_in
let ar = height / width
if (ar_in < ar) {
// in rect too short
h = w_in * ar
y = y_in - (h - h_in) / 2
x = x_in
w = w_in
} else {
// in rect too narrow
w = h_in / ar
x = x_in - (w - w_in) / 2
y = y_in
h = h_in
}
topLevel.selectedRect = Qt.rect(x_in, y_in, w_in, h_in)
topLevel.subScale = Math.min(mapshape.width / w, mapshape.height / h)
topLevel.zoomTarget = Qt.rect(x, y, w, h)
if (textRect) {
topLevel.overlayRect = Qt.rect(textRect.x, textRect.y, textRect.width, textRect.height)
topLevel.overlayRotation = textRect.rotation
} else {
topLevel.overlayRect = topLevel.zoomTarget
topLevel.overlayRotation = 0
}
textLayer.label = name
}
Item {
id: globalLayer
anchors.fill: parent
opacity: mapshape.zoomedIn ? 0 : 1
z: 2
Behavior on opacity {
NumberAnimation { duration: 500 }
}
Repeater {
model: ListModel {
ListElement {
itemSource: "Cloud.qml"
temperature: 22
placeName: "Oslo"
itemX: 0.440
itemY: 0.320
}
ListElement {
itemSource: "CloudWithLightning.qml"
placeName: "Helsinki"
temperature: 20
itemX: 0.615
itemY: 0.300
}
ListElement {
itemSource: "SunBehindCloud.qml"
placeName: "Berlin"
temperature: 24
itemX: 0.490
itemY: 0.540
}
ListElement {
itemSource: "SunBehindCloud.qml"
placeName: "London"
temperature: 22
itemX: 0.249
itemY: 0.550
}
ListElement {
itemSource: "SunBehindCloud.qml"
placeName: "Paris"
temperature: 22
itemX: 0.293
itemY: 0.630
}
ListElement {
itemSource: "SunBehindCloud.qml"
placeName: "Rome"
temperature: 22
itemX: 0.496
itemY: 0.827
}
ListElement {
itemSource: "SunBehindCloud.qml"
placeName: "Budapest"
temperature: 22
itemX: 0.612
itemY: 0.666
}
ListElement {
itemSource: "SunBehindCloud.qml"
placeName: "Sofia"
temperature: 22
itemX: 0.719
itemY: 0.781
}
ListElement {
itemSource: "SunBehindCloud.qml"
placeName: "Kyiv"
temperature: 22
itemX: 0.796
itemY: 0.543
}
ListElement {
itemSource: "Sun.qml"
placeName: "Madrid"
temperature: 28
itemX: 0.140
itemY: 0.830
}
ListElement {
itemSource: "CloudWithSnow.qml"
placeName: "Reykjavik"
temperature: 12
itemX: 0.050
itemY: 0.120
}
}
delegate: BouncyShape {
x: itemX * mapshape.width
y: itemY * mapshape.height
amount: 1.5
MapLabel {
iconSource: itemSource
label: placeName
degrees: temperature
}
}
}
} // end globalLayer
} // end Europe
Item {
id: textLayer
opacity: mapshape.zoomedIn ? 1 : 0
z: 2
x: mapshape.x + topLevel.overlayRect.x
y: mapshape.y + topLevel.overlayRect.y
width: topLevel.overlayRect.width
height: topLevel.overlayRect.height
rotation: topLevel.overlayRotation
property string label: ""
property real localScale: 10 / topLevel.subScale
Behavior on opacity {
NumberAnimation { duration: 800}
}
Item {
anchors.fill: parent
DemoShape {
id: textShape
property real s: Math.min(parent.width / boundingRect.width,
parent.height / boundingRect.height)
anchors.centerIn: parent
scale: Number.isNaN(s) ? 1 : 0.5 * s
asynchronous: true
//! [textShape]
ShapePath {
strokeColor: "transparent"
strokeWidth: 1
joinStyle: ShapePath.RoundJoin
fillRule: ShapePath.WindingFill
fillGradient: RadialGradient {
centerX: textShape.width / 2
centerY: textShape.height / 2
centerRadius: textShape.width / 2
focalX: centerX; focalY: centerY
GradientStop { position: 0; color: "#b0ab9d7f" }
GradientStop { position: 1; color: "#5cab9d7f" }
}
PathText {
id: textPath
text: textLayer.label
font.family: workSansRegular.font.family
font.pixelSize: 64
}
}
//! [textShape]
}
}
}
Item {
id: localLayer
property real localScale: 10 / topLevel.subScale
opacity: mapshape.zoomedIn ? 1 : 0
z: 2
x: mapshape.x + topLevel.selectedRect.x
y: mapshape.y + topLevel.selectedRect.y
width: topLevel.selectedRect.width
height: topLevel.selectedRect.height
Item {
scale: localLayer.localScale
x: 2 * parent.width / 3
y: 2 * parent.height / 3
BouncyShape {
hoverEnabled: mapshape.zoomedIn
Sun {
width: 10
height: 10
}
}
}
Item {
scale: localLayer.localScale
x: parent.width / 10
y: parent.height / 10
BouncyShape {
hoverEnabled: mapshape.zoomedIn
CloudWithLightning {
width: 10
height: 10
}
}
}
Behavior on opacity { NumberAnimation{ duration: 800 } }
}
}
}
Rectangle {
id: gear
anchors.top: mapContainer.top
anchors.left: mapContainer.left
anchors.leftMargin: 30
anchors.topMargin: 30
radius: 8
width: 44
height: width
color: Qt.rgba(0, 0, 0, hoverHandler.hovered ? 0.21 : 0.07)
//! [msaa]
layer.enabled: msaaCheckBox.checked
layer.samples: 4
//! [msaa]
Gear {
anchors.centerIn: parent
width: 24
height: width
}
HoverHandler {
id: hoverHandler
}
TapHandler {
onTapped: (eventPoint, button) => {
settingsDrawer.isOpen = !settingsDrawer.isOpen
}
}
}
SettingsDrawer {
id: settingsDrawer
isLandscape: mainWindow.width > mainWindow.height
width: isLandscape ? implicitWidth : mainWindow.width
height: isLandscape ? mainWindow.height : mainWindow.height * 0.33
RadioButton {
id: curveRendererCheckBox
text: qsTr("Curve Renderer")
checked: true
}
RadioButton {
id: geometryRendererCheckBox
text: qsTr("Geometry Renderer")
}
RadioButton {
id: msaaCheckBox
text: qsTr("Geometry Renderer 4x MSAA")
}
}
}