1/* 2 * SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org> 3 * 4 * SPDX-License-Identifier: LGPL-2.0-or-later 5 */ 6 7import QtQuick 2.12 8import QtQuick.Controls 2.0 as QQC2 9import QtQuick.Window 2.5 10import "templates/private" 11import org.kde.kirigami 2.4 12import QtGraphicalEffects 1.0 13 14/** 15 * A window that provides some basic features needed for all apps 16 * Use this class only if you need a custom content for your application, 17 * different from the Page Row behavior recommended by the HIG and provided 18 * by ApplicationWindow. 19 * It is recommended to use ApplicationWindow instead 20 * @see ApplicationWindow 21 * 22 * It's usually used as a root QML component for the application. 23 * It provides support for a central page stack, side drawers and 24 * a top ApplicationHeader, as well as basic support for the 25 * Android back button 26 * 27 * Setting a width and height property on the ApplicationWindow 28 * will set its initial size, but it won't set it as an automatically binding. 29 * to resize programmatically the ApplicationWindow they need to 30 * be assigned again in an imperative fashion 31 * 32 * 33 * Example usage: 34 * @code 35 * import org.kde.kirigami 2.4 as Kirigami 36 * 37 * Kirigami.ApplicationWindow { 38 * [...] 39 * globalDrawer: Kirigami.GlobalDrawer { 40 * actions: [ 41 * Kirigami.Action { 42 * text: "View" 43 * icon.name: "view-list-icons" 44 * Kirigami.Action { 45 * text: "action 1" 46 * } 47 * Kirigami.Action { 48 * text: "action 2" 49 * } 50 * Kirigami.Action { 51 * text: "action 3" 52 * } 53 * }, 54 * Kirigami.Action { 55 * text: "Sync" 56 * icon.name: "folder-sync" 57 * } 58 * ] 59 * } 60 * 61 * contextDrawer: Kirigami.ContextDrawer { 62 * id: contextDrawer 63 * } 64 * 65 * pageStack: PageStack { 66 * ... 67 * } 68 * [...] 69 * } 70 * @endcode 71 * 72 * @inherit QtQuick.Controls.ApplicationWindow 73 */ 74QQC2.ApplicationWindow { 75 id: root 76 77 /** 78 * This property holds the stack used to allocate the pages and to manage the 79 * transitions between them. 80 * 81 * Put a container here, such as QtQuick.Controls.StackView. 82 */ 83 property Item pageStack 84 LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft 85 LayoutMirroring.childrenInherit: true 86 87 /** 88 * Shows a little passive notification at the bottom of the app window 89 * lasting for few seconds, with an optional action button. 90 * 91 * @param message The text message to be shown to the user. 92 * @param timeout How long to show the message: 93 * possible values: "short", "long" or the number of milliseconds 94 * @param actionText Text in the action button, if any. 95 * @param callBack A JavaScript function that will be executed when the 96 * user clicks the button. 97 */ 98 function showPassiveNotification(message, timeout, actionText, callBack) { 99 if (!internal.__passiveNotification) { 100 var component = Qt.createComponent("templates/private/PassiveNotification.qml"); 101 internal.__passiveNotification = component.createObject(overlay.parent); 102 } 103 104 internal.__passiveNotification.showNotification(message, timeout, actionText, callBack); 105 } 106 107 /** 108 * Hide the passive notification, if any is shown 109 */ 110 function hidePassiveNotification() { 111 if(internal.__passiveNotification) { 112 internal.__passiveNotification.hideNotification(); 113 } 114 } 115 116 117 /** 118 * @returns a pointer to this application window 119 * can be used anywhere in the application. 120 */ 121 function applicationWindow() { 122 return root; 123 } 124 125 /** 126 * header: ApplicationHeader 127 * An item that can be used as a title for the application. 128 * Scrolling the main page will make it taller or shorter (through the point of going away) 129 * It's a behavior similar to the typical mobile web browser addressbar 130 * the minimum, preferred and maximum heights of the item can be controlled with 131 * * Layout.minimumHeight: default is 0, i.e. hidden 132 * * Layout.preferredHeight: default is Units.gridUnit * 1.6 133 * * Layout.maximumHeight: default is Units.gridUnit * 3 134 * 135 * To achieve a titlebar that stays completely fixed just set the 3 sizes as the same 136 * //FIXME: this should become an actual ApplicationHeader 137 */ 138 //header: undefined 139 140 /** 141 * This property controls whether the standard chrome of the app, such 142 * as the Action button, the drawer handles and the application 143 * header should be visible or not. 144 */ 145 property bool controlsVisible: true 146 147 /** 148 * This property holds the drawer for global actions, that will be opened by sliding from the 149 * left screen edge or by dragging the ActionButton to the right. 150 * 151 * It is recommended to use the GlobalDrawer class here. 152 */ 153 property OverlayDrawer globalDrawer 154 155 /** 156 * This property holds whether the application is considered to be in "widescreen" mode, such 157 * as on desktops or horizontal tablets. 158 * 159 * Different styles can have an own logic for deciding this. 160 */ 161 property bool wideScreen: width >= Units.gridUnit * 60 162 163 /** 164 * The drawer for context-dependent actions, that will be opened by sliding from the 165 * right screen edge or by dragging the ActionButton to the left. 166 * It is recommended to use the ContextDrawer class here. 167 * 168 * The contents of the context drawer should depend from what page is 169 * loaded in the main pageStack 170 * 171 * Example usage: 172 * @code 173 * import org.kde.kirigami 2.4 as Kirigami 174 * 175 * Kirigami.ApplicationWindow { 176 * [...] 177 * contextDrawer: Kirigami.ContextDrawer { 178 * id: contextDrawer 179 * } 180 * [...] 181 * } 182 * @endcode 183 * 184 * @code 185 * import org.kde.kirigami 2.4 as Kirigami 186 * 187 * Kirigami.Page { 188 * [...] 189 * contextualActions: [ 190 * Kirigami.Action { 191 * icon.name: "edit" 192 * text: "Action text" 193 * onTriggered: { 194 * // do stuff 195 * } 196 * }, 197 * Kirigami.Action { 198 * icon.name: "edit" 199 * text: "Action text" 200 * onTriggered: { 201 * // do stuff 202 * } 203 * } 204 * ] 205 * [...] 206 * } 207 * @endcode 208 * 209 * When this page will be the current one, the context drawer will visualize 210 * contextualActions defined as property in that page. 211 */ 212 property OverlayDrawer contextDrawer 213 214 /** 215 * This property holds whether the application is in reachable mode for single hand use. 216 * the whole content of the application is moved down the screen to be 217 * reachable with the thumb. if wideScreen is true, or reachableModeEnabled is false, 218 * tis property has no effect. 219 */ 220 property bool reachableMode: false 221 222 /** 223 * This property holds whether the application will go into reachable mode on pull down. 224 */ 225 property bool reachableModeEnabled: true 226 227 /** 228 * This property holds a standard action that will quit the application when triggered. 229 * Its properties have the following values: 230 * 231 * @code 232 * Action { 233 * text: "Quit" 234 * icon.name: "application-exit-symbolic"; 235 * shortcut: StandardKey.Quit 236 * [...] 237 * @endcode 238 * @since 5.76 239 */ 240 readonly property Action quitAction: _quitAction 241 242 color: Theme.backgroundColor 243 244 MouseArea { 245 parent: contentItem.parent 246 z: 0 247 anchors.fill: parent 248 onClicked: root.reachableMode = false; 249 visible: root.reachableMode && root.reachableModeEnabled 250 Rectangle { 251 anchors.fill: parent 252 color: Qt.rgba(0, 0, 0, 0.3) 253 opacity: 0.15 254 Icon { 255 anchors.horizontalCenter: parent.horizontalCenter 256 y: x 257 width: Units.iconSizes.large 258 height: width 259 source: "go-up" 260 } 261 } 262 } 263 264 contentItem.z: 1 265 contentItem.anchors.left: contentItem.parent.left 266 contentItem.anchors.right: contentItem.parent.right 267 contentItem.anchors.topMargin: root.wideScreen && header && controlsVisible ? header.height : 0 268 contentItem.anchors.leftMargin: root.globalDrawer && root.globalDrawer.modal === false && (!root.pageStack || root.pageStack.leftSidebar !== root.globalDrawer) ? root.globalDrawer.width * root.globalDrawer.position : 0 269 contentItem.anchors.rightMargin: root.contextDrawer && root.contextDrawer.modal === false ? root.contextDrawer.width * root.contextDrawer.position : 0 270 271 Binding { 272 when: menuBar !== undefined 273 target: menuBar 274 property: "x" 275 value: -contentItem.x 276 } 277 Binding { 278 when: header !== undefined 279 target: header 280 property: "x" 281 value: -contentItem.x 282 } 283 Binding { 284 when: footer !== undefined 285 target: footer 286 property: "x" 287 value: -contentItem.x 288 } 289 290 contentItem.transform: Translate { 291 Behavior on y { 292 NumberAnimation { 293 duration: Units.longDuration 294 easing.type: Easing.InOutQuad 295 } 296 } 297 y: root.reachableMode && root.reachableModeEnabled && !root.wideScreen ? root.height/2 : 0 298 x: root.globalDrawer && root.globalDrawer.modal === true && root.globalDrawer.toString().indexOf("SplitDrawer") === 0 ? root.globalDrawer.contentItem.width * root.globalDrawer.position : 0 299 } 300 //Don't want overscroll in landscape mode 301 onWidthChanged: { 302 if (width > height) { 303 root.reachableMode = false; 304 } 305 } 306 Binding { 307 when: globalDrawer !== undefined && root.visible 308 target: globalDrawer 309 property: "parent" 310 value: overlay 311 } 312 Binding { 313 when: contextDrawer !== undefined && root.visible 314 target: contextDrawer 315 property: "parent" 316 value: overlay 317 } 318 onPageStackChanged: pageStack.parent = contentItem; 319 320 width: Settings.isMobile ? Units.gridUnit * 30 : Units.gridUnit * 55 321 height: Settings.isMobile ? Units.gridUnit * 45 : Units.gridUnit * 40 322 visible: true 323 324 Component.onCompleted: { 325 // Explicitly break the binding as we need this to be set only at startup. 326 // if the bindings are active, after this the window is resized by the 327 // compositor and then the bindings are reevaluated, then the window 328 // size would reset ignoring what the compositor asked. 329 // see BUG 433849 330 root.width = root.width; 331 root.height = root.height; 332 } 333 334 QtObject { 335 id: internal 336 property QtObject __passiveNotification 337 } 338 339 Action { 340 id: _quitAction 341 text: qsTr("Quit") 342 icon.name: "application-exit"; 343 shortcut: StandardKey.Quit 344 onTriggered: root.close() 345 } 346} 347