Warning, /frameworks/kirigami/src/controls/Avatar.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Carson Black <uhhadd@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 import QtQuick 2.13
0008 import QtQuick.Window 2.15
0009 import QtQuick.Controls 2.13 as QQC2
0010 import QtGraphicalEffects 1.0 as GE
0011 import org.kde.kirigami 2.14 as Kirigami
0012 import org.kde.kirigami.private 2.14 as KP
0013 import "templates/private" as TP
0014 
0015 //TODO KF6: generic enough or belongs to a different framework?
0016 /**
0017  * @brief An element that represents a user, either with initials, an icon, or a profile image.
0018  * @inherit QtQuick.Controls.Control
0019  */
0020 QQC2.Control {
0021     id: avatarRoot
0022 
0023     enum ImageMode {
0024         AlwaysShowImage,
0025         AdaptiveImageOrInitals,
0026         AlwaysShowInitials
0027     }
0028     enum InitialsMode {
0029         UseInitials,
0030         UseIcon
0031     }
0032 
0033 //BEGIN properties
0034     /**
0035      * @brief This property holds the given name of a user.
0036      *
0037      * The user's name will be used for generating initials and to provide the
0038      * accessible name for assistive technology.
0039      */
0040     property string name
0041 
0042     /**
0043      * @brief This property holds the source of the user's profile picture; an image.
0044      * @see <a href="https://doc.qt.io/qt-5/qml-qtquick-image.html#source-prop">Image.source</a>
0045      * @property url source
0046      */
0047     property alias source: avatarImage.source
0048 
0049     /**
0050      * @brief This property holds the avatar's icon source.
0051      *
0052      * The icon acts as a fallback in case the profile image set via `source`
0053      * takes too long to load or is undefined, or in case no `name` or `source`
0054      * has been set.
0055      *
0056      * To force display the icon when both ``name`` and ``source`` are set, you
0057      * may set ``imageMode`` to ``Kirigami.Avatar.ImageMode.AlwaysShowInitials``
0058      * to make it fallback to using initials, and then change ``initialsMode``
0059      * to ``Kirigami.Avatar.InitialsMode.UseIcon`` to display the icon.
0060      *
0061      * @see Icon::source
0062      * @property var iconSource
0063      */
0064     property alias iconSource: avatarIcon.source
0065 
0066     /**
0067      * @brief This property holds how the button should represent the user when no user-set image is available.
0068      *
0069      * The following values are allowed:
0070      * * ``Avatar.InitialsMode.UseInitials``: Show the user's initials.
0071      * * ``Avatar.InitialsMode.UseIcon``: Show a generic icon.
0072      *
0073      * @see ::InitialsMode
0074      */
0075     property int initialsMode: Kirigami.Avatar.InitialsMode.UseInitials
0076 
0077     /**
0078      * @brief This property holds how the avatar should be shown.
0079      *
0080      * This property holds whether the button should always show the image; show the image if one is
0081      * available and show initials when it is not; or always show initials.
0082      *
0083      * The following values are allowed:
0084      * * ``Avatar.ImageMode.AlwaysShowImage``: Always try to show the image; even if it hasn't loaded yet or is undefined.
0085      * * ``Avatar.ImageMode.AdaptiveImageOrInitals``: Show the image if it is valid; or show initials if it is not
0086      * * ``Avatar.ImageMode.AlwaysShowInitials``: Always show initials
0087      *
0088      * @see ::ImageMode
0089      */
0090     property int imageMode: Kirigami.Avatar.ImageMode.AdaptiveImageOrInitals
0091 
0092     /**
0093      * @brief This property sets whether the provided image should be cached.
0094      * @see <a href="https://doc.qt.io/qt-5/qml-qtquick-image.html#cache-prop">Image.cache</a>
0095      * @property bool cache
0096      */
0097     property alias cache: avatarImage.cache
0098 
0099     /**
0100      * @brief This property holds the source size of the user's profile picture.
0101      * @see <a href="https://doc.qt.io/qt-5/qml-qtquick-image.html#sourceSize-prop">Image.sourceSize</a>
0102      * @property int sourceSize
0103      */
0104     property alias sourceSize: avatarImage.sourceSize
0105 
0106     /**
0107      * @brief This property holds whether the provided image should be smoothed.
0108      * @see <a href="https://doc.qt.io/qt-5/qml-qtquick-image.html#smooth-prop">Image.smooth</a>
0109      * @property bool smooth
0110      */
0111     property alias smooth: avatarImage.smooth
0112 
0113     /**
0114      * @brief This property holds the color to use for this avatar.
0115      *
0116      * If not explicitly set, this defaults to generating a color from the name.
0117      *
0118      * @property color color
0119      */
0120     property var color: Kirigami.NameUtils.colorsFromString(name)
0121     // We use a var instead of a color here to allow setting the colour
0122     // as undefined, which will result in a generated colour being used.
0123 
0124     /**
0125      * @brief This property holds the main and secondary actions associated with this avatar.
0126      * @code{.qml}
0127      * Kirigami.Avatar {
0128      *     actions.main: Kirigami.Action {}
0129      *     actions.secondary: Kirigami.Action {}
0130      * }
0131      * @endcode
0132      *
0133      * Actions associated with this avatar.
0134      *
0135      * @note The secondary action should only be used for shortcuts of actions
0136      * elsewhere in your application's UI, and cannot be accessed on mobile platforms.
0137      */
0138     property KP.AvatarGroup actions: KP.AvatarGroup {}
0139 
0140     /**
0141      * @brief This property holds the border properties group.
0142      *
0143      * Example usage:
0144      * @code{.qml}
0145      * Kirigami.Avatar {
0146      *     border.width: 10
0147      *     border.color: "red"
0148      * }
0149      * @endcode
0150      */
0151     property TP.BorderPropertiesGroup border: TP.BorderPropertiesGroup {
0152         width: 0
0153         color: Qt.rgba(0,0,0,0.2)
0154     }
0155 //END properties
0156 
0157     padding: 0
0158     horizontalPadding: padding
0159     verticalPadding: padding
0160     leftPadding: horizontalPadding
0161     rightPadding: horizontalPadding
0162     topPadding: verticalPadding
0163     bottomPadding: verticalPadding
0164 
0165     implicitWidth: Kirigami.Units.iconSizes.large
0166     implicitHeight: Kirigami.Units.iconSizes.large
0167 
0168     activeFocusOnTab: !!actions.main
0169 
0170     Accessible.role: !!actions.main ? Accessible.Button : Accessible.Graphic
0171     Accessible.name: !!actions.main ? qsTr("%1 — %2").arg(name).arg(actions.main.text) : name
0172     Accessible.focusable: !!actions.main
0173     Accessible.onPressAction: __triggerMainAction()
0174     Keys.onReturnPressed: event => __triggerMainAction()
0175     Keys.onEnterPressed: event => __triggerMainAction()
0176     Keys.onSpacePressed: event => __triggerMainAction()
0177 
0178     function __triggerMainAction() {
0179         if (actions.main) {
0180             actions.main.trigger();
0181         }
0182     }
0183 
0184     background: Rectangle {
0185         radius: parent.width / 2
0186 
0187         color: __private.showImage ? Kirigami.Theme.backgroundColor : avatarRoot.color
0188 
0189         Rectangle {
0190             anchors.fill: parent
0191             anchors.margins: -border.width
0192 
0193             radius: width / 2
0194 
0195             color: "transparent"
0196             border.width: Kirigami.Units.smallSpacing
0197             border.color: Kirigami.Theme.focusColor
0198             visible: avatarRoot.focus
0199         }
0200 
0201         MouseArea {
0202             id: primaryMouse
0203 
0204             anchors.fill: parent
0205             hoverEnabled: true
0206             property bool mouseInCircle: {
0207                 const x = avatarRoot.width / 2, y = avatarRoot.height / 2
0208                 const xPrime = mouseX, yPrime = mouseY
0209 
0210                 const distance = (x - xPrime) ** 2 + (y - yPrime) ** 2
0211                 const radiusSquared = (Math.min(avatarRoot.width, avatarRoot.height) / 2) ** 2
0212 
0213                 return distance < radiusSquared
0214             }
0215 
0216             onClicked: mouse =>{
0217                 if (mouseY > avatarRoot.height - secondaryRect.height && !!avatarRoot.actions.secondary) {
0218                     avatarRoot.actions.secondary.trigger()
0219                     return
0220                 }
0221                 avatarRoot.__triggerMainAction()
0222             }
0223 
0224             enabled: !!avatarRoot.actions.main || !!avatarRoot.actions.secondary
0225             cursorShape: containsMouse && mouseInCircle && enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
0226 
0227             QQC2.ToolTip {
0228                 text: avatarRoot.actions.main && avatarRoot.actions.main.tooltip ? avatarRoot.actions.main.tooltip : ''
0229                 visible: primaryMouse.containsMouse && text
0230             }
0231 
0232             states: [
0233                 State {
0234                     name: "secondaryRevealed"
0235                     when: (!Kirigami.Settings.isMobile) && (!!avatarRoot.actions.secondary) && (primaryMouse.containsMouse && primaryMouse.mouseInCircle)
0236                     PropertyChanges {
0237                         target: secondaryRect
0238                         visible: true
0239                     }
0240                 }
0241             ]
0242         }
0243     }
0244 
0245     QtObject {
0246         id: __private
0247         property color textColor: Kirigami.ColorUtils.brightnessForColor(avatarRoot.color) === Kirigami.ColorUtils.Light
0248                                 ? "black"
0249                                 : "white"
0250         property bool showImage: {
0251             return (avatarRoot.imageMode === Kirigami.Avatar.ImageMode.AlwaysShowImage) ||
0252                    (avatarImage.status === Image.Ready && avatarRoot.imageMode === Kirigami.Avatar.ImageMode.AdaptiveImageOrInitals)
0253         }
0254     }
0255 
0256     contentItem: Item {
0257         Text {
0258             id: avatarText
0259             fontSizeMode: Text.Fit
0260             visible: avatarRoot.initialsMode === Kirigami.Avatar.InitialsMode.UseInitials &&
0261                     !__private.showImage &&
0262                     !Kirigami.NameUtils.isStringUnsuitableForInitials(avatarRoot.name) &&
0263                     avatarRoot.width > Kirigami.Units.gridUnit
0264 
0265             text: Kirigami.NameUtils.initialsFromString(name)
0266             color: __private.textColor
0267 
0268             anchors.fill: parent
0269             font {
0270                 // this ensures we don't get a both point and pixel size are set warning
0271                 pointSize: -1
0272                 pixelSize: (avatarRoot.height - Kirigami.Units.largeSpacing) / 2
0273             }
0274             verticalAlignment: Text.AlignVCenter
0275             horizontalAlignment: Text.AlignHCenter
0276         }
0277         Kirigami.Icon {
0278             id: avatarIcon
0279             visible: (avatarRoot.initialsMode === Kirigami.Avatar.InitialsMode.UseIcon && !__private.showImage) ||
0280                     (Kirigami.NameUtils.isStringUnsuitableForInitials(avatarRoot.name) && !__private.showImage)
0281 
0282             source: "user"
0283 
0284             anchors.fill: parent
0285             anchors.margins: Kirigami.Units.largeSpacing
0286 
0287             color: __private.textColor
0288         }
0289         Image {
0290             id: avatarImage
0291             visible: __private.showImage
0292 
0293             mipmap: true
0294             smooth: true
0295             sourceSize {
0296                 width: avatarRoot.width * Screen.devicePixelRatio
0297                 height: avatarRoot.height * Screen.devicePixelRatio
0298             }
0299 
0300             fillMode: Image.PreserveAspectCrop
0301             anchors.fill: parent
0302         }
0303 
0304         Rectangle {
0305             color: "transparent"
0306 
0307             radius: width / 2
0308             anchors.fill: parent
0309 
0310             border {
0311                 width: avatarRoot.border.width
0312                 color: avatarRoot.border.color
0313             }
0314         }
0315 
0316         Rectangle {
0317             id: secondaryRect
0318             visible: false
0319 
0320             anchors {
0321                 bottom: parent.bottom
0322                 left: parent.left
0323                 right: parent.right
0324             }
0325 
0326             height: Kirigami.Units.iconSizes.small + Kirigami.Units.smallSpacing*2
0327 
0328             color: Qt.rgba(0, 0, 0, 0.6)
0329 
0330             Kirigami.Icon {
0331                 Kirigami.Theme.textColor: "white"
0332                 source: (avatarRoot.actions.secondary || {iconName: ""}).iconName
0333 
0334                 width: Kirigami.Units.iconSizes.small
0335                 height: Kirigami.Units.iconSizes.small
0336 
0337                 x: Math.round((parent.width/2)-(this.width/2))
0338                 y: Math.round((parent.height/2)-(this.height/2))
0339             }
0340         }
0341 
0342         layer.enabled: true
0343         layer.effect: GE.OpacityMask {
0344             maskSource: Rectangle {
0345                 height: avatarRoot.height
0346                 width: avatarRoot.width
0347                 radius: height / 2
0348                 color: "black"
0349                 visible: false
0350             }
0351         }
0352     }
0353 }