import Colors 1.0 import Fonts 1.0 import QtQuick 2.7 import QtQuick.Controls 2.0 // IconAndTextButton // Button which contains a horizontally centered and text. // Consumers need to do the following when adding it: // Define the file asset of the icon using imageControl // Define the text value of the label via textControl // Left and right anchors // Declare onClicked behavior // Set onClicked, Keys.onReturnPressed, Keys.onSpacePressed and Accessible.onPressAction Button { id: root // Exposed properties for setting image and text values property alias textControl: txt property alias imageControl: img property bool isAnimated: false property bool animateOnHover: false // Fixed width, but anchors to top/bottom of parent anchors.top: parent.top anchors.topMargin: 8 anchors.bottom: parent.bottom anchors.bottomMargin: 8 width: 80 // Setting text value of the base button object will take care of accessible name text: txt.text // Only let the button show as a part of the accessibility tree if it is enabled Accessible.ignored: !enabled // Function that plays the animation for a specified number of loops. Passing numLoops = 0 will play // the animation forever. function startAnimation(numLoops) { img.startAnimation(numLoops); } function stopAnimation() { img.stopAnimation(); } MouseArea { id: hoverArea anchors.fill: parent enabled: parent.animateOnHover hoverEnabled: enabled // Needed because MouseArea steals mouse events from parent Button when enabled Accessible.onPressAction: root.clicked() onClicked: root.clicked() onEntered: { // numLoops = 0 indicates it should play forever img.startAnimation(0 /* numLoops */) } onExited: { img.stopAnimation(); } } // Accepts focus by tabbing to avoid mouse click changing focus. When disabled, accept no focus focusPolicy: enabled ? Qt.TabFocus : Qt.NoFocus background: Rectangle { radius: 3 border.width: (root.activeFocus || colorThemeManager.highContrastEnabled) ? 1 : 0 border.color: Colors.activity_center.footer2.button_focused_border color : root.pressed ? Colors.activity_center.footer2.button_pressed : (root.hovered ? Colors.activity_center.footer2.button_hovered : Colors.activity_center.footer2.button) } // A vertical column which holds the icon and label of the button. contentItem: Column { // padding from top of button to the Icon anchors.top: root.top topPadding: 13 // Spacing between Icon and Text spacing: 9 opacity: enabled ? 1 : 0.3 // Icon on the button with optional animation AnimatedImage { id: img property bool isEndless: false property int numLoopsRemaining: 0 property int previousFrame: 0 function startAnimation(numLoops) { if (numLoops == 0) { isEndless = true; } else if (numLoops > 0) { isEndless = false; } numLoopsRemaining = numLoops; playing = true; } function stopAnimation() { isEndless = false; playing = false; currentFrame = 0; previousFrame = 0; } playing: false anchors.horizontalCenter: parent.horizontalCenter height: 20 width: 20 opacity: (root.hovered || root.pressed) ? 1 : 0.79 onFrameChanged: { if (numLoopsRemaining > 0) { // Need to also check previous frame to ensure we are actually completing a loop and // not just starting the first loop. if ((currentFrame == 0) && (previousFrame == frameCount - 1)) { numLoopsRemaining--; if (numLoopsRemaining == 0) { playing = false; previousFrame = 0; } } previousFrame = currentFrame; } } } // Text label on the button Text { id: txt width: root.width anchors.horizontalCenter: parent.horizontalCenter horizontalAlignment: Text.AlignHCenter font.pixelSize: 12 font.underline: root.activeFocus font.family: Fonts.standard color: root.hovered ? Colors.activity_center.common.text_hover : Colors.activity_center.common.text wrapMode: Text.WordWrap elide: Text.ElideRight } } }