Kirigami2

controls/templates/InlineMessage.qml
1/*
2 * SPDX-FileCopyrightText: 2018 Eike Hein <hein@kde.org>
3 * SPDX-FileCopyrightText: 2022 ivan tkachenko <me@ratijas.tk>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8import QtQuick
9import QtQuick.Controls as QQC2
10import QtQuick.Templates as T
11import org.kde.kirigami as Kirigami
12import org.kde.kirigami.templates.private as TP
13
14/**
15 * An inline message item with support for informational, positive,
16 * warning and error types, and with support for associated actions.
17 *
18 * InlineMessage can be used to give information to the user or
19 * interact with the user, without requiring the use of a dialog.
20 *
21 * The InlineMessage item is hidden by default. It also manages its
22 * height (and implicitHeight) during an animated reveal when shown.
23 * You should avoid setting height on an InlineMessage unless it is
24 * already visible.
25 *
26 * Optionally an icon can be set, defaulting to an icon appropriate
27 * to the message type otherwise.
28 *
29 * Optionally a close button can be shown.
30 *
31 * Actions are added from left to right. If more actions are set than
32 * can fit, an overflow menu is provided.
33 *
34 * Example:
35 * @code
36 * import org.kde.kirigami as Kirigami
37 *
38 * Kirigami.InlineMessage {
39 * type: Kirigami.MessageType.Error
40 *
41 * text: i18n("My error message")
42 *
43 * actions: [
44 * Kirigami.Action {
45 * icon.name: "list-add"
46 * text: i18n("Add")
47 * onTriggered: source => {
48 * // do stuff
49 * }
50 * },
51 * Kirigami.Action {
52 * icon.name: "edit"
53 * text: i18n("Edit")
54 * onTriggered: source => {
55 * // do stuff
56 * }
57 * }
58 * ]
59 * }
60 * @endcode
61 *
62 * @since 5.45
63 * @inherit QtQuick.Templates.Control
64 */
65T.Control {
66 id: root
67
68 visible: false
69
70 /**
71 * Defines a position for the message: whether it's to be used as an inline component inside the page,
72 * a page header, or a page footer.
73 */
74 enum Position {
75 Inline,
76 Header,
77 Footer
78 }
79
80 /**
81 * Adjust the look of the message based upon the position.
82 * If a message is positioned in the header area or in the footer area
83 * of a page, it might be desirable to not have borders but just a line
84 * separating it from the content area. In this case, use the Header or
85 * Footer position.
86 * Default is InlineMessage.Position.Inline
87 */
88 property int position: InlineMessage.Position.Inline
89
90 /**
91 * This signal is emitted when a link is hovered in the message text.
92 * @param The hovered link.
93 */
94 signal linkHovered(string link)
95
96 /**
97 * This signal is emitted when a link is clicked or tapped in the message text.
98 * @param The clicked or tapped link.
99 */
100 signal linkActivated(string link)
102 /**
103 * This property holds the link embedded in the message text that the user is hovering over.
104 */
105 readonly property alias hoveredLink: label.hoveredLink
106
107 /**
108 * This property holds the message type. One of Information, Positive, Warning or Error.
109 *
110 * The default is Kirigami.MessageType.Information.
111 */
112 property int type: Kirigami.MessageType.Information
113
114 /**
115 * This grouped property holds the description of an optional icon.
116 *
117 * * source: The source of the icon, a freedesktop-compatible icon name is recommended.
118 * * color: An optional tint color for the icon.
119 *
120 * If no custom icon is set, an icon appropriate to the message type
121 * is shown.
122 */
123 property TP.IconPropertiesGroup icon: TP.IconPropertiesGroup {}
124
125 /**
126 * This property holds the message text.
127 */
128 property string text
129
130 /**
131 * This property holds whether the close button is displayed.
132 *
133 * The default is false.
134 */
135 property bool showCloseButton: false
136
137 /**
138 * This property holds the list of actions to show. Actions are added from left to
139 * right. If more actions are set than can fit, an overflow menu is
140 * provided.
141 */
142 property list<T.Action> actions
143
144 /**
145 * This property holds whether the current message item is animating.
146 */
147 readonly property bool animating: _animating
148
149 property bool _animating: false
150
151 implicitHeight: visible ? (contentLayout.implicitHeight + topPadding + bottomPadding) : 0
152
153 padding: Kirigami.Units.smallSpacing
154
155 Behavior on implicitHeight {
156 enabled: !root.visible
157
158 SequentialAnimation {
159 PropertyAction { targets: root; property: "_animating"; value: true }
160 NumberAnimation { duration: Kirigami.Units.longDuration }
161 }
162 }
163
164 onVisibleChanged: {
165 if (!visible) {
166 contentLayout.opacity = 0;
167 }
168 }
169
170 opacity: visible ? 1 : 0
171
172 Behavior on opacity {
173 enabled: !root.visible
174
175 NumberAnimation { duration: Kirigami.Units.shortDuration }
176 }
177
178 onOpacityChanged: {
179 if (opacity === 0) {
180 contentLayout.opacity = 0;
181 } else if (opacity === 1) {
182 contentLayout.opacity = 1;
183 }
184 }
185
186 onImplicitHeightChanged: {
187 height = implicitHeight;
188 }
189
190 contentItem: Item {
191 id: contentLayout
192
193 // Used to defer opacity animation until we know if InlineMessage was
194 // initialized visible.
195 property bool complete: false
196
197 Behavior on opacity {
198 enabled: root.visible && contentLayout.complete
199
200 SequentialAnimation {
201 NumberAnimation { duration: Kirigami.Units.shortDuration * 2 }
202 PropertyAction { targets: root; property: "_animating"; value: false }
203 }
204 }
205
206 implicitHeight: {
207 if (atBottom) {
208 return label.implicitHeight + actionsLayout.implicitHeight + actionsLayout.anchors.topMargin
209 } else {
210 return Math.max(icon.implicitHeight, label.implicitHeight, closeButton.implicitHeight, actionsLayout.implicitHeight)
211 }
212 }
213
214 readonly property real remainingWidth: width - (
215 icon.width
216 + label.anchors.leftMargin + label.implicitWidth + label.anchors.rightMargin
217 + (root.showCloseButton ? closeButton.width : 0)
218 )
219 readonly property bool multiline: remainingWidth <= 0 || atBottom
220
221 readonly property bool atBottom: (root.actions.length > 0) && (label.lineCount > 1 || actionsLayout.implicitWidth > remainingWidth)
222
223 Kirigami.Icon {
224 id: icon
225
226 width: Kirigami.Units.iconSizes.smallMedium
227 height: Kirigami.Units.iconSizes.smallMedium
228
229 anchors {
230 left: parent.left
231 leftMargin: Kirigami.Units.smallSpacing
232 topMargin: Kirigami.Units.smallSpacing
233 }
234
235 states: [
236 State {
237 name: "multi-line"
238 when: contentLayout.atBottom || label.height > icon.height * 1.7
239 AnchorChanges {
240 target: icon
241 anchors.top: icon.parent.top
242 anchors.verticalCenter: undefined
243 }
244 },
245 // States are evaluated in the order they are declared.
246 // This is a fallback state.
247 State {
248 name: "single-line"
249 when: true
250 AnchorChanges {
251 target: icon
252 anchors.top: undefined
253 anchors.verticalCenter: parent.verticalCenter
254 }
255 }
256 ]
257
258 source: {
259 if (root.icon.name) {
260 return root.icon.name;
261 } else if (root.icon.source) {
262 return root.icon.source;
263 }
264
265 switch (root.type) {
266 case Kirigami.MessageType.Positive:
267 return "emblem-success";
268 case Kirigami.MessageType.Warning:
269 return "emblem-warning";
270 case Kirigami.MessageType.Error:
271 return "emblem-error";
272 default:
273 return "emblem-information";
274 }
275 }
276
277 color: root.icon.color
278 }
279
280 Kirigami.SelectableLabel {
281 id: label
282
283 anchors {
284 left: icon.right
285 leftMargin: Kirigami.Units.largeSpacing
286 right: root.showCloseButton ? closeButton.left : parent.right
287 rightMargin: root.showCloseButton ? Kirigami.Units.smallSpacing : 0
288 top: parent.top
289 }
290
291 color: Kirigami.Theme.textColor
292 wrapMode: Text.WordWrap
293
294 text: root.text
295
296 verticalAlignment: Text.AlignVCenter
297
298 // QTBUG-117667 TextEdit (super-type of SelectableLabel) needs
299 // very specific state-management trick so it doesn't get stuck.
300 // State names serve purely as a description.
301 states: [
302 State {
303 name: "multi-line"
304 when: contentLayout.multiline
305 AnchorChanges {
306 target: label
307 anchors.bottom: undefined
308 }
309 PropertyChanges {
310 target: label
311 height: label.implicitHeight
312 }
313 },
314 // States are evaluated in the order they are declared.
315 // This is a fallback state.
316 State {
317 name: "single-line"
318 when: true
319 AnchorChanges {
320 target: label
321 anchors.bottom: label.parent.bottom
322 }
323 }
324 ]
325
326 onLinkHovered: link => root.linkHovered(link)
327 onLinkActivated: link => root.linkActivated(link)
328 }
329
330 Kirigami.ActionToolBar {
331 id: actionsLayout
332
333 flat: false
334 actions: root.actions
335 visible: root.actions.length > 0
336 alignment: Qt.AlignRight
337
338 anchors {
339 left: parent.left
340 top: contentLayout.atBottom ? label.bottom : parent.top
341 topMargin: contentLayout.atBottom ? Kirigami.Units.largeSpacing : 0
342 right: (!contentLayout.atBottom && root.showCloseButton) ? closeButton.left : parent.right
343 rightMargin: !contentLayout.atBottom && root.showCloseButton ? Kirigami.Units.smallSpacing : 0
344 }
345 }
346
347 QQC2.ToolButton {
348 id: closeButton
349
350 visible: root.showCloseButton
351
352 anchors.right: parent.right
353
354 // Incompatible anchors need to be evaluated in a given order,
355 // which simple declarative bindings cannot assure
356 states: [
357 State {
358 name: "onTop"
359 when: contentLayout.atBottom
360 AnchorChanges {
361 target: closeButton
362 anchors.top: parent.top
363 anchors.verticalCenter: undefined
364 }
365 } ,
366 State {
367 name: "centered"
368 AnchorChanges {
369 target: closeButton
370 anchors.top: undefined
371 anchors.verticalCenter: parent.verticalCenter
372 }
373 }
374 ]
375
376 height: contentLayout.atBottom ? implicitHeight : implicitHeight
377
378 icon.name: "dialog-close"
379
380 onClicked: root.visible = false
381 }
382
383 Component.onCompleted: complete = true
384 }
385}
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
QString name(StandardAction id)
QString label(StandardShortcut id)
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:16:21 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.