import QtQuick import QtQuick.Templates as T import Quickshell.Widgets FocusScope { id: root required property Theme theme property string text: "" property string icon: "" property url iconSource: "" property string role: "normal" property bool showText: true property string accessibleName: text property string tooltip: accessibleName property bool checked: false property int iconSize: 14 property bool primary: role === "primary" property bool interactive: true property bool hoverable: interactive property alias radius: background.radius property alias color: background.color property alias border: background.border signal clicked property bool destructive: role === "destructive" readonly property color stateColor: destructive ? theme.error : (primary || checked ? theme.ui.accent : theme.ui.normal) readonly property color foregroundColor: primary ? theme.content.backdrop : (destructive ? theme.error : theme.content.normal) readonly property bool pressed: activation.down || activation.enterHeld readonly property bool hovered: hover.hovered readonly property bool visualFocus: activation.visualFocus readonly property bool controlFocused: activation.activeFocus readonly property bool tooltipVisible: tip.visible implicitWidth: Math.min(320, (label.visible ? label.implicitWidth : 0) + (root.iconSource.toString().length > 0 ? iconSize : (glyph.visible ? glyph.implicitWidth : 0)) + (label.visible && (glyph.visible || root.iconSource.toString().length > 0) ? labelRow.spacing : 0) + 24) implicitHeight: 34 activeFocusOnTab: interactive && enabled opacity: enabled ? 1 : 0.48 Accessible.role: Accessible.Button Accessible.name: accessibleName Accessible.checked: checked Accessible.focusable: interactive && enabled Accessible.onPressAction: if (interactive && enabled) activation.click() Rectangle { id: background anchors.fill: parent radius: 8 color: root.theme.withAlpha(root.stateColor, root.primary ? (root.pressed ? 0.7 : root.hovered ? 0.88 : 1) : (root.pressed ? 0.24 : (root.hovered ? 0.14 : (root.checked ? 0.16 : (root.role === "ghost" ? 0 : 0.06))))) border.width: root.controlFocused ? 2 : (root.checked ? 1 : 0) border.color: root.controlFocused ? root.theme.content.focus : root.theme.withAlpha(root.stateColor, 0.65) Behavior on color { ColorAnimation { duration: root.theme.lowPowerMode ? 0 : 90 } } } // Native pointer, Space activation and cancellation; the wrapper retains // the caller's string icon, checked binding and Rectangle styling API. T.Button { id: activation property bool enterHeld: false anchors.fill: parent enabled: root.interactive && root.enabled focus: true focusPolicy: Qt.ClickFocus autoRepeat: false Accessible.ignored: true onClicked: root.clicked() onActiveFocusChanged: if (!activeFocus) enterHeld = false onEnabledChanged: if (!enabled) enterHeld = false Keys.onPressed: event => { const enter = event.key === Qt.Key_Return || event.key === Qt.Key_Enter; if (enter || event.key === Qt.Key_Space && event.isAutoRepeat) { event.accepted = true; if (enter && !event.isAutoRepeat) enterHeld = true; } } Keys.onReleased: event => { const enter = event.key === Qt.Key_Return || event.key === Qt.Key_Enter; if (enter || event.key === Qt.Key_Space && event.isAutoRepeat) { event.accepted = true; if (enter && !event.isAutoRepeat) { const activate = enterHeld && enabled; enterHeld = false; if (activate) root.clicked(); } } } } Item { anchors.fill: parent anchors.margins: 4 clip: true Row { id: labelRow anchors.centerIn: parent spacing: 7 IconImage { visible: root.iconSource.toString().length > 0 anchors.verticalCenter: parent.verticalCenter width: root.iconSize height: root.iconSize source: root.iconSource Accessible.ignored: true } Text { id: glyph visible: root.icon.length > 0 && root.iconSource.toString().length === 0 anchors.verticalCenter: parent.verticalCenter color: root.foregroundColor font.family: "Symbols Nerd Font Mono" font.pixelSize: root.iconSize text: root.icon Accessible.ignored: true } NuguText { id: label visible: root.showText && root.text.length > 0 anchors.verticalCenter: parent.verticalCenter width: Math.min(implicitWidth, Math.max(0, root.width - 24 - (root.iconSource.toString().length > 0 ? root.iconSize + labelRow.spacing : (glyph.visible ? glyph.implicitWidth + labelRow.spacing : 0)))) theme: root.theme color: root.foregroundColor text: root.text Accessible.ignored: true } } } HoverHandler { id: hover enabled: root.hoverable cursorShape: root.enabled && root.interactive ? Qt.PointingHandCursor : Qt.ArrowCursor } PopupToolTip { id: tip theme: root.theme text: root.tooltip visible: root.visible && text.length > 0 && !root.pressed && (root.visualFocus || (root.hovered && !root.activeFocus)) } }