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.
118 *
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
137 hint: 0.9
138 heightHint: 0.9
139 spacing: Maui.Style.space.big
140
141 margins: 0
142
143 filling: persistent && mWidth === control.parent.width
144
145 /**
146 * @brief Default children content will be added to a scrollable ColumnLayout.
147 * 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.
148 * @property list<Item> PopupPage::scrollable
149 */
150 default property alias scrollable : _scrollView.content
151
152 /**
153 * @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.
154 * @code
155 * Maui.PopupPage
156 * {
157 * stack: Rectangle
158 * {
159 * Layout.fillWidth: true
160 * Layout.fillHeight: true
161 * Layout.preferredHeight: 800
162 * }
163 * }
164 * @endcode
165 * @property list<QtObject> PopupPage::stack
166 */
167 property alias stack : _stack.data
168
169 /**
170 * @see Page::title
171 */
172 property alias title : _page.title
173
174 /**
175 * @brief Whether the dialog should be closed when it loses focus or not.
176 * 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.
177 * By default this is set to `true`.
178 */
179 property bool persistent : true
181 /**
182 * @brief An alias to the MauiKit Page, which is the main container of this control.
183 * It is exposed to allow access to the Page properties.
184 * @see Page
185 * @property Page PopupPage::page
186 */
187 readonly property alias page : _page
188
189 /**
190 * @see Page::footBar
191 */
192 property alias footBar : _page.footBar
193
194 /**
195 * @see Page::headBar
196 */
197 property alias headBar: _page.headBar
198
199 /**
200 * @brief Whether the close button is visible.
201 * By default this is bind to the `persistent` value.
202 * @see persistent.
203 */
204 property bool closeButtonVisible: control.persistent
205
206 /**
207 * @see ScrollColumn::flickable
208 */
209 readonly property alias flickable : _scrollView.flickable
210
211 /**
212 * @brief An alias to the MauiKit ScrollColumn handling the scrollable content.
213 * @property ScrollView PopupPage::scrollView
214 */
215 readonly property alias scrollView : _scrollView
216
217 /**
218 * @brief The policy for the scroll view vertical scroll bar.
219 * By default this is set to `ScrollBar.AsNeeded`.
220 */
221 property int verticalScrollBarPolicy: ScrollBar.AsNeeded
222
223 /**
224 * @brief The policy for the scroll view horizontal scroll bar.
225 * By default this is set to `ScrollBar.AlwaysOff`.
226 */
227 property int horizontalScrollBarPolicy: ScrollBar.AlwaysOff
228
229 /**
230 * @brief Whether the control should be closed automatically after the close button is pressed.
231 * If this is set to `false`, then the `closeTriggered` will be emitted instead.
232 * This is useful if a conformation action needs to take place before closing the control.
233 * By default this is set to `true`.
234 */
235 property bool autoClose : true
236
237 /**
238 * @brief List of actions to be added to the bottom section as buttons.
239 */
240 property list<Action> actions
241
242 /**
243 * @brief The GridLayout handling the bottom part of action buttons added via the `actions` property.
244 * @property GridLayout PopupPage:: actionBar
245 */
246 readonly property alias actionBar : _defaultButtonsLayout
247
248 /**
249 * @brief Emitted when the close button has been clicked and the `autoClose` property has been disabled.
250 * @see autoClose
251 * @see closeButtonVisible
252 */
253 signal closeTriggered()
254
255 ColumnLayout
256 {
257 id: _layout
258 anchors.fill: parent
259 spacing: 0
260
261 Maui.Page
262 {
263 id: _page
264
265 clip: true
266
267 Maui.Theme.colorSet: control.Maui.Theme.colorSet
268 Maui.Controls.flat: true
269
270 Layout.fillWidth: true
271 Layout.fillHeight: true
272
273 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)
274
275 headerPositioning: ListView.InlineHeader
276
277 padding: 0
278 margins: 0
279
280 headBar.visible: control.persistent
281
282 background: null
283
284 headBar.farRightContent: Loader
285 {
286 asynchronous: true
287 visible: active
288 active: control.persistent && closeButtonVisible
289
290 sourceComponent: Maui.CloseButton
291 {
292 onClicked:
293 {
294 if(control.autoClose)
295 {
296 control.close()
297 }else
298 {
299 control.closeTriggered()
300 }
301 }
302 }
303 }
304
305 ColumnLayout
306 {
307 id: _stack
308
309 anchors.fill: parent
310 spacing: control.spacing
311 }
312
313 Maui.ScrollColumn
314 {
315 id: _scrollView
316
317 anchors.fill: parent
318
319 visible: _stack.children.length === 0
320
321 spacing: control.spacing
322 padding: Maui.Style.space.big
323
324 ScrollBar.horizontal.policy: control.horizontalScrollBarPolicy
325 ScrollBar.vertical.policy: control.verticalScrollBarPolicy
326 }
327 }
328
329 Maui.Chip
330 {
331 id: _alertMessage
332
333 visible: text.length > 0
334
335 property int level : 0
336
337 Layout.fillWidth: true
338 Layout.margins: Maui.Style.contentMargins
339
340 color: switch(level)
341 {
342 case 0: return Maui.Theme.positiveBackgroundColor
343 case 1: return Maui.Theme.neutralBackgroundColor
344 case 2: return Maui.Theme.negativeBackgroundColor
345 }
346
347 SequentialAnimation on x
348 {
349 id: _alertAnim
350 // Animations on properties start running by default
351 running: false
352 loops: 3
353 NumberAnimation { from: 0; to: -10; duration: 100; easing.type: Easing.InOutQuad }
354 NumberAnimation { from: -10; to: 0; duration: 100; easing.type: Easing.InOutQuad }
355 PauseAnimation { duration: 50 } // This puts a bit of time between the loop
356 }
357
358 function reset()
359 {
360 _alertMessage.text = ""
361 _alertMessage.level = 0
362 }
363 }
364
365 GridLayout
366 {
367 id: _defaultButtonsLayout
368
369 rowSpacing: Maui.Style.space.small
370 columnSpacing: Maui.Style.space.small
371
372 Layout.fillWidth: true
373 Layout.margins: Maui.Style.contentMargins
374
375 property bool isWide : control.width > (100 * control.actions.length)
376
377 visible: control.actions.length
378
379 rows: isWide? 1 : _defaultButtonsLayout.children.length
380 columns: isWide ? _defaultButtonsLayout.children.length : 1
381
382 Repeater
383 {
384 model: control.actions
385
386 Button
387 {
388 id: _actionButton
389 focus: true
390 Layout.fillWidth: true
391
392 action: modelData
393 Maui.Controls.status: modelData.Maui.Controls.status
394 }
395 }
396 }
397 }
398
399 onClosed: _alertMessage.reset()
400
401 /**
402 * @brief Sends an inline alert notification that is displayed in the dialog.
403 * @param message The text for the message. Keep it short if possible.
404 * @param level Depending on the level the color may differ. The levels are:
405 * - 0 positive
406 * - 1 neutral
407 * - 2 negative
408 */
409 function alert(message, level)
410 {
411 _alertMessage.text = message
412 _alertMessage.level = level
413 }
414}
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 Apr 18 2025 12:16:12 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.