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 Accessible.role: Accessible.AlertMessage
156 Accessible.ignored: !visible
157
158 Behavior on implicitHeight {
159 enabled: !root.visible
160
161 SequentialAnimation {
162 PropertyAction { targets: root; property: "_animating"; value: true }
163 NumberAnimation { duration: Kirigami.Units.longDuration }
164 }
165 }
166
167 onVisibleChanged: {
168 if (!visible) {
169 contentLayout.opacity = 0;
170 }
171 }
172
173 opacity: visible ? 1 : 0
174
175 Behavior on opacity {
176 enabled: !root.visible
177
178 NumberAnimation { duration: Kirigami.Units.shortDuration }
179 }
180
181 onOpacityChanged: {
182 if (opacity === 0) {
183 contentLayout.opacity = 0;
184 } else if (opacity === 1) {
185 contentLayout.opacity = 1;
186 }
187 }
188
189 onImplicitHeightChanged: {
190 height = implicitHeight;
191 }
192
193 contentItem: Item {
194 id: contentLayout
195
196 // Used to defer opacity animation until we know if InlineMessage was
197 // initialized visible.
198 property bool complete: false
199
200 Behavior on opacity {
201 enabled: root.visible && contentLayout.complete
202
203 SequentialAnimation {
204 NumberAnimation { duration: Kirigami.Units.shortDuration * 2 }
205 PropertyAction { targets: root; property: "_animating"; value: false }
206 }
207 }
208
209 implicitHeight: {
210 let maximumTopHeight = Math.max(label.implicitHeight, icon.implicitHeight, (root.showCloseButton ? closeButton.implicitHeight : 0))
211 if (atBottom) {
212 return maximumTopHeight + actionsLayout.implicitHeight + Kirigami.Units.smallSpacing
213 } else {
214 return Math.max(maximumTopHeight, actionsLayout.implicitHeight)
215 }
216 }
217
218 Accessible.ignored: true
219
220 readonly property real fixedContentWidth: icon.width + Kirigami.Units.smallSpacing * 3 + (root.showCloseButton ? closeButton.width + Kirigami.Units.smallSpacing : 0)
221 readonly property real remainingWidth: width - fixedContentWidth - label.implicitWidth
222 readonly property bool multiline: remainingWidth <= 0 || atBottom
223 readonly property bool atBottom: (root.actions.length > 0) && (label.lineCount > 1 || actionsLayout.implicitWidth > remainingWidth)
224
225 Kirigami.Icon {
226 id: icon
227
228 width: Kirigami.Units.iconSizes.smallMedium
229 height: Kirigami.Units.iconSizes.smallMedium
230
231 anchors {
232 left: parent.left
233 leftMargin: Kirigami.Units.smallSpacing
234 topMargin: Kirigami.Units.smallSpacing
235 }
236
237 states: [
238 State {
239 name: "multi-line"
240 when: contentLayout.atBottom || label.height > icon.height * 1.7
241 AnchorChanges {
242 target: icon
243 anchors.top: icon.parent.top
244 anchors.verticalCenter: undefined
245 }
246 },
247 // States are evaluated in the order they are declared.
248 // This is a fallback state.
249 State {
250 name: "single-line"
251 when: true
252 AnchorChanges {
253 target: icon
254 anchors.top: undefined
255 anchors.verticalCenter: parent.verticalCenter
256 }
257 }
258 ]
259
260 source: {
261 if (root.icon.name) {
262 return root.icon.name;
263 } else if (root.icon.source) {
264 return root.icon.source;
265 }
266
267 switch (root.type) {
268 case Kirigami.MessageType.Positive:
269 return "emblem-success";
270 case Kirigami.MessageType.Warning:
271 return "emblem-warning";
272 case Kirigami.MessageType.Error:
273 return "emblem-error";
274 default:
275 return "emblem-information";
276 }
277 }
278
279 color: root.icon.color
280
281 Accessible.ignored: !root.visible
282 Accessible.name: {
283 switch (root.type) {
284 case Kirigami.MessageType.Positive:
285 return qsTr("Success");
286 case Kirigami.MessageType.Warning:
287 return qsTr("Warning");
288 case Kirigami.MessageType.Error:
289 return qsTr("Error");
290 default:
291 return qsTr("Note");
292 }
293 }
294 }
295
296 Kirigami.SelectableLabel {
297 id: label
298
299 anchors {
300 left: icon.right
301 leftMargin: Kirigami.Units.largeSpacing
302 top: parent.top
303 bottom: parent.bottom
304 }
305
306 width: Math.min(parent.width - parent.fixedContentWidth, implicitWidth)
307
308 color: Kirigami.Theme.textColor
309 wrapMode: Text.WordWrap
310
311 text: root.text
312
313 verticalAlignment: Text.AlignVCenter
314
315 // QTBUG-117667 TextEdit (super-type of SelectableLabel) needs
316 // very specific state-management trick so it doesn't get stuck.
317 // State names serve purely as a description.
318 states: [
319 State {
320 name: "multi-line"
321 when: contentLayout.multiline
322 AnchorChanges {
323 target: label
324 anchors.bottom: undefined
325 }
326 PropertyChanges {
327 target: label
328 height: label.implicitHeight
329 }
330 }
331 ]
332
333 onLinkHovered: link => root.linkHovered(link)
334 onLinkActivated: link => root.linkActivated(link)
335
336 Accessible.ignored: !root.visible
337 }
338
339 Kirigami.ActionToolBar {
340 id: actionsLayout
341
342 flat: false
343 actions: root.actions
344 visible: root.actions.length > 0
345 Accessible.ignored: !visible || !root.visible
346 alignment: Qt.AlignRight
347
348 anchors {
349 bottom: parent.bottom
350 right: (!contentLayout.atBottom && root.showCloseButton) ? closeButton.left : parent.right
351 rightMargin: !contentLayout.atBottom && root.showCloseButton ? Kirigami.Units.smallSpacing : 0
352 }
353
354 width: Math.min(implicitWidth, parent.width)
355 }
356
357 QQC2.ToolButton {
358 id: closeButton
359
360 visible: root.showCloseButton
361
362 anchors {
363 verticalCenter: parent.verticalCenter
364 right: parent.right
365 }
366
367 // Incompatible anchors need to be evaluated in a given order,
368 // which simple declarative bindings cannot assure
369 states: State {
370 name: "onTop"
371 when: contentLayout.atBottom
372 AnchorChanges {
373 target: closeButton
374 anchors.top: parent.top
375 anchors.verticalCenter: undefined
376 }
377 }
378
379 text: qsTr("Close")
380 display: QQC2.ToolButton.IconOnly
381 icon.name: "dialog-close"
382
383 onClicked: root.visible = false
384
385 Accessible.ignored: !root.visible
386 }
387
388 Component.onCompleted: complete = true
389 }
390}
Class for rendering an icon in UI.
Definition icon.h:35
listTAction actions
This property holds the list of actions to show.
bool animating
This property holds whether the current message item is animating.
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-2025 The KDE developers.
Generated on Fri Apr 18 2025 12:03:26 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.