MauiKit Controls

PopupPage.qml
1/*
2 * Copyright 2018 Camilo Higuita <milo.h@aol.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20import QtQuick
21
22import QtQuick.Controls
23import QtQuick.Layouts
24
25import org.mauikit.controls as Maui
26
27/**
28 * @inherit QtQuick.Controls.Popup
29 * @since org.mauikit.controls 1.0
30 * @brief A QQC2 Popup with extra built-in features, such as a snapping surface, scrollable contents, and action buttons.
31 *
32 * <a href="https://doc.qt.io/qt-6/qml-qtquick-controls-popup.html">This control inherits from QQC2 Popup, to checkout its inherited properties refer to the Qt Docs.</a>
33 *
34 * @image html Misc/popuppage.png "The image depicts the control a floating VS snapped surface"
35 *
36 * @section structure Structure
37 *
38 * The inner container is handled by a MauiKit Page, and this can be accessed via the alias property `page` - which means this control can have a header and footer bar, and all the other Page features.
39 * @see page
40 *
41 * By default the children content is positioned into a MauiKit ScrollColumn, that's scrollable. If it's desired, this can be avoided by placing the children manually, using the property `stack`. This way any other element can be positioned manually using the Layout attached properties.
42 * @see stack
43 *
44 * @note The `stack` children are positioned using a ColumnLayout.
45 *
46 * @section features Features
47 *
48 * @subsection snapping Snapping
49 * The Popup can snap to the full window area on constrained spaces. To allow this behavior there a few steps to look after, first make `hint: 1`and set `persistent: true`.
50 * @ref ScrollColumn#notes Notes
51 * @see persistent
52 *
53 * @subsection scrollable Scrollable Layout
54 * By default the children content of this element will be placed on a MauiKit ScrollColumn, which allows the content to be scrollable/flickable when its implicit height is bigger than the actual popup area.
55 * To position the children content use the `implicitHeight` and the Layout attached properties, such as `Layout.fillWidth`.
56 * @see content
57 * @see ScrollColumn
58 *
59 * @subsection actions Action Buttons
60 * The regular QQC2 Popup control does not have support for setting standard action buttons like the Dialog controls does; but this control allows it. The action buttons will be styled in the same manner as the Dialog buttons, but the actions here are added differently.
61 * To set the actions, use the `actions` property.
62 * @see actions
63 *
64 * @code
65 * Maui.PopupPage
66 * {
67 * id: _popupPage
68 *
69 * title: "Title"
70 *
71 * persistent: true
72 * hint: 1
73 *
74 * Rectangle
75 * {
76 * implicitHeight: 200
77 * Layout.fillWidth: true
78 * color: "purple"
79 * }
80 *
81 * Rectangle
82 * {
83 * implicitHeight: 200
84 * Layout.fillWidth: true
85 * color: "orange"
86 * }
87 *
88 * Rectangle
89 * {
90 * implicitHeight: 200
91 * Layout.fillWidth: true
92 * color: "yellow"
93 * }
94 *
95 * actions: [
96 * Action
97 * {
98 * text: "Action1"
99 * },
100 *
101 * Action
102 * {
103 * text: "Action2"
104 * }
105 * ]
106 * }
107 * @endcode
108 *
109 * @section notes Notes
110 * Some properties have been obscure by the Maui Style layer.
111 * The style layer adds some extra properties to the Popup control:
112 * - `filling : bool` Whether the popup area should be style as if filling the whole window area.
113 * - `maxWidth : int` The maximum width the popup area can have. If the window width space becomes smaller then the popup area, then it will be resized to fit. Or if the `hint: 1` then it will snap to fill the whole window area.
114 * - `maxHeight : int` The maximum height the popup area can have. If the window height space becomes smaller then the popup area, then it will be resized to fit. Or if the `hint: 1` then it will snap to fill the whole window area.
115 * -` hint : double` Determines the resizing final size of the popup area when it reaches the `maxWidth` or `maxHeight` constrains. For example a `1` value means the popup area will be resize to fill the window available space, but a `0.5` value means it will be conserving a margin when resized of 25% at left and right sides.
116 * - `heightHint : double` By default this is bind to the `hint` value.
117 * - `widthHint : double` By default this is bind to the `hint` value.
119 *
120 * <a href="https://invent.kde.org/maui/mauikit/-/blob/qt6-2/examples/PopupPage.qml">You can find a more complete example at this link.</a>
121 */
122Maui.Popup
123{
124 id: control
125
126 focus: true
127
128 Maui.Theme.colorSet: Maui.Theme.Window
129 Maui.Theme.inherit: false
130
131 closePolicy: control.persistent ? Popup.NoAutoClose | Popup.CloseOnEscape : Popup.CloseOnEscape | Popup.CloseOnPressOutside
132
133 maxWidth: 300
134 maxHeight: implicitHeight
135 implicitHeight: _layout.implicitHeight + topPadding + bottomPadding + topMargin + bottomMargin
136 implicitWidth: _layout.implicitWidth + leftPadding + rightPadding
137
138 hint: 0.9
139 heightHint: 0.9
140 spacing: Maui.Style.space.big
141
142 margins: 0
143
144 filling: persistent && mWidth === control.parent.width
145
146 /**
147 * @brief Default children content will be added to a scrollable ColumnLayout.
148 * When adding a item keep on mind that to correctly have the scrollable behavior the item must have an implicit height set. And the positioning should be handled via the Layout attached properties.
149 * @property list<Item> PopupPage::scrollable
150 */
151 default property alias scrollable : _scrollView.content
152
153 /**
154 * @brief To skip the default scrollable-layout behavior, there is a `stack` overlay component to which items can be added, this is also controlled by a ColumnLayout, but it is not scrollable.
155 * @code
156 * Maui.PopupPage
157 * {
158 * stack: Rectangle
159 * {
160 * Layout.fillWidth: true
161 * Layout.fillHeight: true
162 * Layout.preferredHeight: 800
163 * }
164 * }
165 * @endcode
166 * @property list<QtObject> PopupPage::stack
167 */
168 property alias stack : _stack.data
169
170 /**
171 * @see Page::title
172 */
173 property alias title : _page.title
174
175 /**
176 * @brief Whether the dialog should be closed when it loses focus or not.
177 * If it is marked as persistent a close button is shown in the header bar, other wise the header bar is hidden if there is not more elements on it.
178 * By default this is set to `true`.
179 */
180 property bool persistent : true
182 /**
183 * @brief An alias to the MauiKit Page, which is the main container of this control.
184 * It is exposed to allow access to the Page properties.
185 * @see Page
186 * @property Page PopupPage::page
187 */
188 readonly property alias page : _page
189
190 /**
191 * @see Page::footBar
192 */
193 property alias footBar : _page.footBar
194
195 /**
196 * @see Page::headBar
197 */
198 property alias headBar: _page.headBar
199
200 /**
201 * @brief Whether the close button is visible.
202 * By default this is bind to the `persistent` value.
203 * @see persistent.
204 */
205 property bool closeButtonVisible: control.persistent
206
207 /**
208 * @see ScrollColumn::flickable
209 */
210 readonly property alias flickable : _scrollView.flickable
211
212 /**
213 * @brief An alias to the MauiKit ScrollColumn handling the scrollable content.
214 * @property ScrollView PopupPage::scrollView
215 */
216 readonly property alias scrollView : _scrollView
217
218 /**
219 * @brief The policy for the scroll view vertical scroll bar.
220 * By default this is set to `ScrollBar.AsNeeded`.
221 */
222 property int verticalScrollBarPolicy: ScrollBar.AsNeeded
223
224 /**
225 * @brief The policy for the scroll view horizontal scroll bar.
226 * By default this is set to `ScrollBar.AlwaysOff`.
227 */
228 property int horizontalScrollBarPolicy: ScrollBar.AlwaysOff
229
230 /**
231 * @brief Whether the control should be closed automatically after the close button is pressed.
232 * If this is set to `false`, then the `closeTriggered` will be emitted instead.
233 * This is useful if a conformation action needs to take place before closing the control.
234 * By default this is set to `true`.
235 */
236 property bool autoClose : true
237
238 /**
239 * @brief List of actions to be added to the bottom section as buttons.
240 */
241 property list<Action> actions
242
243 /**
244 * @brief The GridLayout handling the bottom part of action buttons added via the `actions` property.
245 * @property GridLayout PopupPage:: actionBar
246 */
247 readonly property alias actionBar : _defaultButtonsLayout
248
249 /**
250 * @brief Emitted when the close button has been clicked and the `autoClose` property has been disabled.
251 * @see autoClose
252 * @see closeButtonVisible
253 */
254 signal closeTriggered()
255
256 ColumnLayout
257 {
258 id: _layout
259 anchors.fill: parent
260 spacing: 0
261
262 Maui.Page
263 {
264 id: _page
265
266 clip: true
267
268 Maui.Theme.colorSet: control.Maui.Theme.colorSet
269 Maui.Controls.flat: true
270
271 Layout.fillWidth: true
272 Layout.fillHeight: true
273
274 implicitHeight: Math.max(_scrollView.contentHeight + _scrollView.topPadding + _scrollView.bottomPadding, _stack.implicitHeight) + _page.footerContainer.implicitHeight + (_page.topPadding + _page.bottomPadding) + _page.headerContainer.implicitHeight + (_page.topMargin + _page.bottomMargin)
275
276 implicitWidth: Math.max(_stack.implicitWidth, _scrollView.implicitWidth, _defaultButtonsLayout.implicitWidth)
277
278 headerPositioning: ListView.InlineHeader
279
280 padding: 0
281 margins: 0
282
283 headBar.visible: control.persistent
284
285 background: null
286
287 headBar.farRightContent: Loader
288 {
289 asynchronous: true
290 visible: active
291 active: control.persistent && closeButtonVisible
292
293 sourceComponent: Maui.CloseButton
294 {
295 onClicked:
296 {
297 if(control.autoClose)
298 {
299 control.close()
300 }else
301 {
302 control.closeTriggered()
303 }
304 }
305 }
306 }
307
308 ColumnLayout
309 {
310 id: _stack
311
312 anchors.fill: parent
313 spacing: control.spacing
314 }
315
316 Maui.ScrollColumn
317 {
318 id: _scrollView
319
320 anchors.fill: parent
321
322 visible: _stack.children.length === 0
323
324 spacing: control.spacing
325 padding: Maui.Style.space.big
326
327 ScrollBar.horizontal.policy: control.horizontalScrollBarPolicy
328 ScrollBar.vertical.policy: control.verticalScrollBarPolicy
329 }
330 }
331
332 Maui.Chip
333 {
334 id: _alertMessage
335
336 visible: text.length > 0
337
338 property int level : 0
339
340 Layout.fillWidth: true
341 Layout.margins: Maui.Style.contentMargins
342
343 color: switch(level)
344 {
345 case 0: return Maui.Theme.positiveBackgroundColor
346 case 1: return Maui.Theme.neutralBackgroundColor
347 case 2: return Maui.Theme.negativeBackgroundColor
348 }
349
350 SequentialAnimation on x
351 {
352 id: _alertAnim
353 // Animations on properties start running by default
354 running: false
355 loops: 3
356 NumberAnimation { from: 0; to: -10; duration: 100; easing.type: Easing.InOutQuad }
357 NumberAnimation { from: -10; to: 0; duration: 100; easing.type: Easing.InOutQuad }
358 PauseAnimation { duration: 50 } // This puts a bit of time between the loop
359 }
360
361 function reset()
362 {
363 _alertMessage.text = ""
364 _alertMessage.level = 0
365 }
366 }
367
368 GridLayout
369 {
370 id: _defaultButtonsLayout
371
372 rowSpacing: Maui.Style.space.small
373 columnSpacing: Maui.Style.space.small
374
375 Layout.fillWidth: true
376 Layout.margins: Maui.Style.contentMargins
377
378 property bool isWide : control.width > (100 * control.actions.length)
379
380 visible: control.actions.length
381
382 rows: isWide? 1 : _defaultButtonsLayout.children.length
383 columns: isWide ? _defaultButtonsLayout.children.length : 1
384
385 Repeater
386 {
387 model: control.actions
388
389 Button
390 {
391 id: _actionButton
392 focus: true
393 Layout.fillWidth: true
394
395 action: modelData
396 Maui.Controls.status: modelData.Maui.Controls.status
397 }
398 }
399 }
400 }
401
402 onClosed: _alertMessage.reset()
403
404 /**
405 * @brief Sends an inline alert notification that is displayed in the dialog.
406 * @param message The text for the message. Keep it short if possible.
407 * @param level Depending on the level the color may differ. The levels are:
408 * - 0 positive
409 * - 1 neutral
410 * - 2 negative
411 */
412 function alert(message, level)
413 {
414 _alertMessage.text = message
415 _alertMessage.level = level
416 }
417}
QString text() const
bool closeButtonVisible
Whether the close button is visible.
void closeTriggered()
Emitted when the close button has been clicked and the autoClose property has been disabled.
alias headBar
list< Action > actions
List of actions to be added to the bottom section as buttons.
alias actionBar
The GridLayout handling the bottom part of action buttons added via the actions property.
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri May 2 2025 11:57:11 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.