Skip to content
Snippets Groups Projects
MaterialButton.qml 6.37 KiB
Newer Older
Sébastien Blin's avatar
Sébastien Blin committed
/*
 * Copyright (C) 2020 by Savoir-faire Linux
 * Author: Sébastien blin <sebastien.blin@savoirfairelinux.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
// TODO: this component suffers from excessive responsibility
// and should have fixed width and content width defined variations
// as well as better handling for the animated icon
Sébastien Blin's avatar
Sébastien Blin committed
Button {
    id: root

    property bool outlined: false
    property alias toolTipText: toolTip.text
    property alias iconSource: icon.source_
    property alias animatedIconSource: icon.animatedSource_
    property real iconSize: 18
    property var color: JamiTheme.buttonTintedBlue
    property var hoveredColor: JamiTheme.buttonTintedBlueHovered
    property var pressedColor: JamiTheme.buttonTintedBluePressed
    property var keysNavigationFocusColor: Qt.darker(hoveredColor, 2)
    property bool hasIcon: animatedIconSource.length !== 0 ||
                           iconSource.length !== 0

    property var preferredWidth
    Binding on width {
        when: root.preferredWidth !== undefined ||
              root.Layout.fillWidth
        value: root.preferredWidth
    }
    Binding on Layout.preferredWidth {
        when: root.preferredWidth !== undefined ||
              root.Layout.fillWidth
        value: width
    }
    property real preferredHeight: 36
    height: preferredHeight
    Layout.preferredHeight: height
    focusPolicy: Qt.TabFocus
    MaterialToolTip {
        id: toolTip

        parent: root
        visible: hovered && (toolTipText.length > 0)
        delay: Qt.styleHints.mousePressAndHoldInterval
    }

    property string contentColorProvider: {
        if (!root.outlined)
            return "white"
        if (root.hovered)
            return root.hoveredColor
        if (root.down)
            return root.pressedColor
        return root.color
    }

Sébastien Blin's avatar
Sébastien Blin committed
    contentItem: Item {
        id: item

        Binding on implicitWidth {
            when: root.preferredWidth === undefined ||
                  !root.Layout.fillWidth
            value: item.childrenRect.width
        }
        implicitHeight: childrenRect.height
        RowLayout {
            anchors.verticalCenter: parent.verticalCenter
            Binding on width {
                when: root.preferredWidth !== undefined ||
                      root.Layout.fillWidth
                value: root.availableWidth
            }
            spacing: hasIcon ?
                         JamiTheme.preferredMarginSize :
                         0

            Component {
                id: iconComponent

                ResponsiveImage {
                    source: source_
                    Layout.preferredWidth: iconSize
                    Layout.preferredHeight: iconSize
                    color: contentColorProvider
                }
            Component {
                id: animatedIconComponent

                AnimatedImage {
                    source: animatedSource_
                    Layout.preferredWidth: iconSize
                    Layout.preferredHeight: iconSize
                    width: iconSize
                    height: iconSize
                    playing: true
                    fillMode: Image.PreserveAspectFit
                    mipmap: true
            Loader {
                id: icon
                property string source_
                property string animatedSource_
                active: hasIcon
                Layout.preferredWidth: active * width
                Layout.alignment: Qt.AlignVCenter
                Layout.leftMargin: hasIcon ?
                                       JamiTheme.preferredMarginSize / 2 :
                                       undefined
                sourceComponent: animatedSource_.length !== 0 ?
                                     animatedIconComponent :
                                     iconComponent
            }
            Text {
                // this right margin will make the text visually
                // centered within button
                Layout.rightMargin: {
                    if ((!hasIcon || root.preferredWidth === undefined) &&
                            !root.Layout.fillWidth)
                        return undefined
                    return icon.width + JamiTheme.preferredMarginSize / 2 +
                            parent.spacing
                Layout.fillWidth: true
                Layout.alignment: Qt.AlignHCenter
                text: root.text
                font: root.font
                elide: Text.ElideRight
                verticalAlignment: Text.AlignVCenter
                horizontalAlignment: Text.AlignHCenter
                color: contentColorProvider
Sébastien Blin's avatar
Sébastien Blin committed
            }
        }
    }

    background: Rectangle {
        anchors.fill: parent
        color: {
            if (root.outlined)
                return "transparent"
            if (root.hovered)
                return root.hoveredColor
            if (root.down)
                return root.pressedColor
            return root.focus ?
                        root.keysNavigationFocusColor :
                        root.color
        }
        border.color: {
            if (!root.outlined)
                return "transparent"
            if (root.hovered)
                return root.hoveredColor
            if (root.down)
                return root.pressedColor
            return root.focus ?
                        root.keysNavigationFocusColor :
                        root.color
        radius: JamiTheme.primaryRadius

    Keys.onPressed: function (keyEvent) {
        if (keyEvent.key === Qt.Key_Enter ||
                keyEvent.key === Qt.Key_Return) {
            clicked()
            keyEvent.accepted = true
        }
    }