Kirigami2

Avatar.qml
1 /*
2  * SPDX-FileCopyrightText: 2020 Carson Black <[email protected]>
3  *
4  * SPDX-License-Identifier: LGPL-2.0-or-later
5  */
6 
7 import QtQuick 2.13
8 import QtQuick.Window 2.15
9 import QtQuick.Controls 2.13 as QQC2
10 import QtGraphicalEffects 1.0 as GE
11 import org.kde.kirigami 2.14 as Kirigami
12 import org.kde.kirigami.private 2.14 as KP
13 import "templates/private" as TP
14 
15 //TODO KF6: generic enough or belongs to a different framework?
16 /**
17  * @brief An element that represents a user, either with initials, an icon, or a profile image.
18  * @inherit QtQuick.Controls.Control
19  */
20 QQC2.Control {
21  id: avatarRoot
22 
23  enum ImageMode {
24  AlwaysShowImage,
25  AdaptiveImageOrInitals,
26  AlwaysShowInitials
27  }
28  enum InitialsMode {
29  UseInitials,
30  UseIcon
31  }
32 
33 //BEGIN properties
34  /**
35  * @brief This property holds the given name of a user.
36  *
37  * The user's name will be used for generating initials and to provide the
38  * accessible name for assistive technology.
39  */
40  property string name
41 
42  /**
43  * @brief This property holds the source of the user's profile picture; an image.
44  * @see QtQuick.Image::source
45  * @property url source
46  */
47  property alias source: avatarImage.source
48 
49  /**
50  * @brief This property holds avatar's icon source.
51  *
52  * This icon is displayed when using an icon with ``Avatar.InitialsMode.UseIcon`` and
53  * ``Avatar.ImageNode.AlwaysShowInitials`` enabled.
54  *
55  * @see org::kde::kirigami::Icon::source
56  * @property var iconSource
57  */
58  property alias iconSource: avatarIcon.source
59 
60  /**
61  * @brief This property holds how the button should represent the user when no user-set image is available.
62  *
63  * Possible values are:
64  * * ``Avatar.InitialsMode.UseInitials``: Show the user's initials.
65  * * ``Avatar.InitialsMode.UseIcon``: Show a generic icon.
66  *
67  * @see org::kde::kirigami::Avatar::InitialsMode
68  */
69  property int initialsMode: Kirigami.Avatar.InitialsMode.UseInitials
70 
71  /**
72  * @brief This property holds how the avatar should be shown.
73  *
74  * This property holds whether the button should always show the image; show the image if one is
75  * available and show initials when it is not; or always show initials.
76  *
77  * Possible values are:
78  * * ``Avatar.ImageMode.AlwaysShowImage``: Always try to show the image; even if it hasn't loaded yet or is undefined.
79  * * ``Avatar.ImageMode.AdaptiveImageOrInitals``: Show the image if it is valid; or show initials if it is not
80  * * ``Avatar.ImageMode.AlwaysShowInitials``: Always show initials
81  *
82  * @see org::kde::kirigami::Avatar::ImageMode
83  */
84  property int imageMode: Kirigami.Avatar.ImageMode.AdaptiveImageOrInitals
85 
86  /**
87  * @brief This property sets whether the provided image should be cached.
88  * @see QtQuick.Image::cache
89  * @property bool cache
90  */
91  property alias cache: avatarImage.cache
92 
93  /**
94  * @brief This property holds the source size of the user's profile picture.
95  * @see QtQuick.Image::sourceSize
96  * @property int sourceSize
97  */
98  property alias sourceSize: avatarImage.sourceSize
99 
100  /**
101  * @brief This property holds whether the provided image should be smoothed.
102  * @see QtQuick.Image::smooth
103  * @property bool smooth
104  */
105  property alias smooth: avatarImage.smooth
106 
107  /**
108  * @brief This property holds the color to use for this avatar.
109  *
110  * If not explicitly set, this defaults to generating a color from the name.
111  *
112  * @property color color
113  */
114  property var color: Kirigami.NameUtils.colorsFromString(name)
115  // We use a var instead of a color here to allow setting the colour
116  // as undefined, which will result in a generated colour being used.
117 
118  /**
119  * @brief This property holds the main and secondary actions associated with this avatar.
120  * @code
121  * Kirigami.Avatar {
122  * actions.main: Kirigami.Action {}
123  * actions.secondary: Kirigami.Action {}
124  * }
125  * @endcode
126  *
127  * Actions associated with this avatar.
128  *
129  * @note The secondary action should only be used for shortcuts of actions
130  * elsewhere in your application's UI, and cannot be accessed on mobile platforms.
131  */
132  property KP.AvatarGroup actions: KP.AvatarGroup {}
133 
134  /**
135  * @brief This property holds the border properties group.
136  * @code
137  * Kirigami.Avatar {
138  * border.width: 10
139  * border.color: 'red'
140  * }
141  * @endcode
142  */
143  property TP.BorderPropertiesGroup border: TP.BorderPropertiesGroup {
144  width: 0
145  color: Qt.rgba(0,0,0,0.2)
146  }
147 //END properties
148 
149  padding: 0
150  horizontalPadding: padding
151  verticalPadding: padding
152  leftPadding: horizontalPadding
153  rightPadding: horizontalPadding
154  topPadding: verticalPadding
155  bottomPadding: verticalPadding
156 
157  implicitWidth: Kirigami.Units.iconSizes.large
158  implicitHeight: Kirigami.Units.iconSizes.large
159 
160  activeFocusOnTab: !!actions.main
161 
162  Accessible.role: !!actions.main ? Accessible.Button : Accessible.Graphic
163  Accessible.name: !!actions.main ? qsTr("%1 — %2").arg(name).arg(actions.main.text) : name
164  Accessible.focusable: !!actions.main
165  Accessible.onPressAction: __triggerMainAction()
166  Keys.onReturnPressed: event => __triggerMainAction()
167  Keys.onEnterPressed: event => __triggerMainAction()
168  Keys.onSpacePressed: event => __triggerMainAction()
169 
170  function __triggerMainAction() {
171  if (actions.main) {
172  actions.main.trigger();
173  }
174  }
175 
176  background: Rectangle {
177  radius: parent.width / 2
178 
179  color: __private.showImage ? Kirigami.Theme.backgroundColor : avatarRoot.color
180 
181  Rectangle {
182  anchors.fill: parent
183  anchors.margins: -border.width
184 
185  radius: width / 2
186 
187  color: "transparent"
188  border.width: Kirigami.Units.smallSpacing
189  border.color: Kirigami.Theme.focusColor
190  visible: avatarRoot.focus
191  }
192 
193  MouseArea {
194  id: primaryMouse
195 
196  anchors.fill: parent
197  hoverEnabled: true
198  property bool mouseInCircle: {
199  const x = avatarRoot.width / 2, y = avatarRoot.height / 2
200  const xPrime = mouseX, yPrime = mouseY
201 
202  const distance = (x - xPrime) ** 2 + (y - yPrime) ** 2
203  const radiusSquared = (Math.min(avatarRoot.width, avatarRoot.height) / 2) ** 2
204 
205  return distance < radiusSquared
206  }
207 
208  onClicked: mouse =>{
209  if (mouseY > avatarRoot.height - secondaryRect.height && !!avatarRoot.actions.secondary) {
210  avatarRoot.actions.secondary.trigger()
211  return
212  }
213  avatarRoot.__triggerMainAction()
214  }
215 
216  enabled: !!avatarRoot.actions.main || !!avatarRoot.actions.secondary
217  cursorShape: containsMouse && mouseInCircle && enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
218 
219  QQC2.ToolTip {
220  text: avatarRoot.actions.main && avatarRoot.actions.main.tooltip ? avatarRoot.actions.main.tooltip : ''
221  visible: primaryMouse.containsMouse && text
222  }
223 
224  states: [
225  State {
226  name: "secondaryRevealed"
227  when: (!Kirigami.Settings.isMobile) && (!!avatarRoot.actions.secondary) && (primaryMouse.containsMouse && primaryMouse.mouseInCircle)
228  PropertyChanges {
229  target: secondaryRect
230  visible: true
231  }
232  }
233  ]
234  }
235  }
236 
237  QtObject {
238  id: __private
239  property color textColor: Kirigami.ColorUtils.brightnessForColor(avatarRoot.color) === Kirigami.ColorUtils.Light
240  ? "black"
241  : "white"
242  property bool showImage: {
243  return (avatarRoot.imageMode === Kirigami.Avatar.ImageMode.AlwaysShowImage) ||
244  (avatarImage.status === Image.Ready && avatarRoot.imageMode === Kirigami.Avatar.ImageMode.AdaptiveImageOrInitals)
245  }
246  }
247 
248  contentItem: Item {
249  Text {
250  id: avatarText
251  fontSizeMode: Text.Fit
252  visible: avatarRoot.initialsMode === Kirigami.Avatar.InitialsMode.UseInitials &&
253  !__private.showImage &&
254  !Kirigami.NameUtils.isStringUnsuitableForInitials(avatarRoot.name) &&
255  avatarRoot.width > Kirigami.Units.gridUnit
256 
257  text: Kirigami.NameUtils.initialsFromString(name)
258  color: __private.textColor
259 
260  anchors.fill: parent
261  font {
262  // this ensures we don't get a both point and pixel size are set warning
263  pointSize: -1
264  pixelSize: (avatarRoot.height - Kirigami.Units.largeSpacing) / 2
265  }
266  verticalAlignment: Text.AlignVCenter
267  horizontalAlignment: Text.AlignHCenter
268  }
269  Kirigami.Icon {
270  id: avatarIcon
271  visible: (avatarRoot.initialsMode === Kirigami.Avatar.InitialsMode.UseIcon && !__private.showImage) ||
272  (Kirigami.NameUtils.isStringUnsuitableForInitials(avatarRoot.name) && !__private.showImage)
273 
274  source: "user"
275 
276  anchors.fill: parent
277  anchors.margins: Kirigami.Units.largeSpacing
278 
279  color: __private.textColor
280  }
281  Image {
282  id: avatarImage
283  visible: __private.showImage
284 
285  mipmap: true
286  smooth: true
287  sourceSize {
288  width: avatarRoot.width * Screen.devicePixelRatio
289  height: avatarRoot.height * Screen.devicePixelRatio
290  }
291 
292  fillMode: Image.PreserveAspectCrop
293  anchors.fill: parent
294  }
295 
296  Rectangle {
297  color: "transparent"
298 
299  radius: width / 2
300  anchors.fill: parent
301 
302  border {
303  width: avatarRoot.border.width
304  color: avatarRoot.border.color
305  }
306  }
307 
308  Rectangle {
309  id: secondaryRect
310  visible: false
311 
312  anchors {
313  bottom: parent.bottom
314  left: parent.left
315  right: parent.right
316  }
317 
318  height: Kirigami.Units.iconSizes.small + Kirigami.Units.smallSpacing*2
319 
320  color: Qt.rgba(0, 0, 0, 0.6)
321 
322  Kirigami.Icon {
323  Kirigami.Theme.textColor: "white"
324  source: (avatarRoot.actions.secondary || {iconName: ""}).iconName
325 
326  width: Kirigami.Units.iconSizes.small
327  height: Kirigami.Units.iconSizes.small
328 
329  x: Math.round((parent.width/2)-(this.width/2))
330  y: Math.round((parent.height/2)-(this.height/2))
331  }
332  }
333 
334  layer.enabled: true
335  layer.effect: GE.OpacityMask {
336  maskSource: Rectangle {
337  height: avatarRoot.height
338  width: avatarRoot.width
339  radius: height / 2
340  color: "black"
341  visible: false
342  }
343  }
344  }
345 }
QTextStream & right(QTextStream &stream)
QTextStream & left(QTextStream &stream)
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
QTextStream & left(QTextStream &s)
QTextStream & right(QTextStream &s)
QString name(StandardShortcut id)
QString & fill(QChar ch, int size)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Jan 29 2023 04:11:03 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.