import QtQuick import qs.config Item { id: root default property alias trailingData: trailing.data property string icon: "" property string label: "" // The headline's colour. Foreground for every ordinary row; ErrorRow sets // it to Theme.danger so a failure reads as one at a glance. property color labelColor: Theme.fg property string detail: "" property string value: "" property bool divider: true property int controlWidth: 150 // Rows are inert by default. A row that represents a choice -- picking a // timezone from a list, say -- opts into being clickable across its whole // width, which is a much larger target than the trailing control alone. property bool activatable: false signal activated // Keyboard and screen-reader reach, added without changing a single thing // about how the row looks or behaves under the pointer. // // Only an activatable row becomes a Tab stop. A row that does nothing when // clicked must not collect focus either -- Tab landing on inert text is how // keyboard navigation stops being usable long before it stops working. function activate(): void { if (root.activatable) root.activated(); } width: parent ? parent.width : 620 implicitHeight: Math.max(56, copy.implicitHeight + 20) activeFocusOnTab: root.activatable Accessible.role: root.activatable ? Accessible.Button : Accessible.StaticText Accessible.name: root.label Accessible.description: root.detail Accessible.focusable: root.activatable Accessible.focused: root.activeFocus Accessible.onPressAction: root.activate() Keys.onReturnPressed: root.activate() Keys.onEnterPressed: root.activate() Keys.onSpacePressed: root.activate() Text { id: iconLabel anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter width: root.icon === "" ? 0 : 28 visible: root.icon !== "" text: root.icon color: Theme.accent font.family: Theme.fontMono font.pixelSize: 17 horizontalAlignment: Text.AlignHCenter } Column { id: copy anchors.left: iconLabel.visible ? iconLabel.right : parent.left anchors.leftMargin: iconLabel.visible ? 10 : 0 anchors.right: trailing.left anchors.rightMargin: 16 anchors.verticalCenter: parent.verticalCenter spacing: 3 Text { width: parent.width text: root.label color: root.labelColor font.family: Theme.fontFamily font.pixelSize: Theme.fontSize font.weight: Font.Medium elide: Text.ElideRight } Text { width: parent.width visible: root.detail !== "" text: root.detail color: Theme.fgDim font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall wrapMode: Text.WordWrap } } Item { id: trailing anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter width: root.controlWidth height: 32 Text { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter visible: root.value !== "" text: root.value color: Theme.fgDim font.family: Theme.fontFamily font.features: Theme.tabularFigures font.pixelSize: Theme.fontSize } } Rectangle { anchors.left: copy.left anchors.right: parent.right anchors.bottom: parent.bottom height: 1 visible: root.divider color: Theme.alpha(Theme.fg, 0.065) } // Declared in this component's own body, so it is a child of the row rather // than of the trailing slot that `trailingData` routes external children to. Rectangle { anchors.fill: parent anchors.bottomMargin: 1 radius: 8 z: -1 visible: root.activatable && rowHover.hovered color: Theme.alpha(Theme.fg, 0.05) border.width: 0 } // The focus ring: the hover plate's geometry with a border added, so a row // reached by Tab reads as the same target the pointer would have hit. Drawn // only while this row holds keyboard focus, so nothing changes at rest. Rectangle { anchors.fill: parent anchors.bottomMargin: 1 radius: 8 z: -1 visible: root.activatable && root.activeFocus color: Theme.alpha(Theme.fg, 0.05) border.width: 2 border.color: Theme.accentSecondary } HoverHandler { id: rowHover enabled: root.activatable cursorShape: Qt.PointingHandCursor } TapHandler { enabled: root.activatable onTapped: root.activated() } }