Hyprland: - Windows round at 8px, concentric with the porthole's 18px corners at the 10px gap, instead of square corners inside a rounded opening. - Group tabs are solid hull slabs; the titles used to float over the wallpaper. The current tab is lifted a step with its title in the light. - Motion rewritten to glide and settle: no overshoot curve, gentler popin, workspaces slide-fade a short way instead of sweeping the whole screen, and layers only fade so they never stack on quickshell's own slides. Quickshell: - Album art in the bar and the media popout is square in a hairline frame, not masked to a leaning chamfered shape; the accent slab under the popout art is gone, and a track change dips the title instead of tilting the art. - The bar's equaliser is a five-hairline signal meter that rests as dots. - Segment meters (system, battery, OSD) are 4px rows instead of 10-12px blocks; the toast fuse is a hairline; the clock's accent slab is a neutral divider. - No hover pops: rail icons, tray icons, media transport buttons and P5Button no longer scale up or lunge sideways; the icon bump is reduced. Terminal: ANSI bright black drops to #464d44. TUIs use it as a panel fill, and at the outline grey it read as a flat light slab. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
176 lines
6.3 KiB
QML
176 lines
6.3 KiB
QML
import QtQuick
|
|
import "root:/config"
|
|
|
|
// NieR menu button: a hairline box with a square marker that lights when the
|
|
// button is pointed at or chosen. One activation path for pointer and keyboard.
|
|
FocusScope {
|
|
id: root
|
|
|
|
property string text: ""
|
|
property string icon: ""
|
|
property color accent: Theme.primary
|
|
property bool destructive: false
|
|
property bool selected: false
|
|
property real lean: Theme.skew
|
|
// Sideways nudge on hover. Zero: NieR buttons do not move, the marker
|
|
// and the inversion carry the state.
|
|
property real lunge: 0
|
|
property bool wide: false
|
|
|
|
signal clicked()
|
|
|
|
readonly property bool hovered: root.enabled && hover.hovered
|
|
readonly property bool pressed: tap.pressed
|
|
readonly property bool focusedOrSelected: root.activeFocus || root.selected
|
|
readonly property bool highlighted: root.hovered || root.focusedOrSelected
|
|
|
|
// Keyboard focus and roving selection invert the slab to solid accent.
|
|
// Pointer hover stays a keyline change, so the two never look alike and a
|
|
// mouse user never sees the "selected" treatment by accident. Destructive
|
|
// buttons keep their own red inversion for both.
|
|
readonly property bool inverted: root.enabled && !root.destructive && root.focusedOrSelected
|
|
|
|
// Pointer activation must not turn a transient action into the black/white
|
|
// keyboard-focus treatment. Tab still reaches it, and programmatic focus
|
|
// (power-menu roving selection / pinned popouts) still works.
|
|
focusPolicy: root.enabled ? Qt.TabFocus : Qt.NoFocus
|
|
|
|
function activate(): void {
|
|
if (root.enabled)
|
|
root.clicked();
|
|
}
|
|
|
|
function activateFromKey(event): void {
|
|
if (!event.isAutoRepeat)
|
|
root.activate();
|
|
}
|
|
|
|
implicitWidth: wide ? 260 : (row.implicitWidth + panel.contentPad * 2)
|
|
implicitHeight: 44
|
|
|
|
P5Panel {
|
|
id: panel
|
|
anchors.fill: parent
|
|
lean: root.lean
|
|
padding: Theme.padS
|
|
fill: {
|
|
if (!root.enabled) return Theme.treatmentDisabledFill;
|
|
if (root.destructive)
|
|
return root.highlighted ? Theme.treatmentDestructiveActiveFill
|
|
: Theme.treatmentDestructiveFill;
|
|
if (root.inverted) return Theme.treatmentFocusFill;
|
|
if (root.highlighted) return Theme.treatmentHoverFill;
|
|
return Theme.treatmentRestFill;
|
|
}
|
|
fillOpacity: root.enabled ? 1.0 : 0.72
|
|
border: {
|
|
if (!root.enabled) return Theme.treatmentDisabledMark;
|
|
if (root.destructive)
|
|
return root.highlighted ? Theme.treatmentDestructiveActiveMark
|
|
: Theme.treatmentDestructiveMark;
|
|
if (root.inverted) return Theme.treatmentFocusMark;
|
|
if (root.highlighted) return Theme.treatmentHoverMark;
|
|
return Theme.alpha(root.accent, 0.55);
|
|
}
|
|
borderWidth: Theme.stroke
|
|
|
|
Behavior on fillOpacity {
|
|
NumberAnimation { duration: Theme.durFast }
|
|
}
|
|
|
|
Row {
|
|
id: row
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
spacing: Theme.padM
|
|
|
|
// The marker. Dim at rest, full strength under the pointer or the
|
|
// cursor, in whatever colour the label is wearing.
|
|
Rectangle {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: Theme.marker
|
|
height: Theme.marker
|
|
color: label.color
|
|
opacity: root.highlighted ? 1.0 : 0.35
|
|
|
|
Behavior on opacity {
|
|
NumberAnimation { duration: Theme.durFast }
|
|
}
|
|
}
|
|
|
|
Icon {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
visible: root.icon !== ""
|
|
text: root.icon
|
|
font.pixelSize: Theme.fsTitle
|
|
color: {
|
|
if (!root.enabled) return Theme.treatmentDisabledText;
|
|
if (root.destructive)
|
|
return root.highlighted ? Theme.treatmentDestructiveActiveText
|
|
: Theme.treatmentDestructiveText;
|
|
if (root.inverted) return Theme.treatmentFocusText;
|
|
if (root.highlighted) return Theme.treatmentHoverText;
|
|
return root.accent;
|
|
}
|
|
}
|
|
|
|
Text {
|
|
id: label
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: root.text
|
|
color: {
|
|
if (!root.enabled) return Theme.treatmentDisabledText;
|
|
if (root.destructive)
|
|
return root.highlighted ? Theme.treatmentDestructiveActiveText
|
|
: Theme.treatmentDestructiveText;
|
|
if (root.inverted) return Theme.treatmentFocusText;
|
|
if (root.highlighted) return Theme.treatmentHoverText;
|
|
return Theme.treatmentRestText;
|
|
}
|
|
font.family: Theme.fontDisplay
|
|
font.pixelSize: Theme.fsBody
|
|
font.weight: Theme.weightDisplay
|
|
font.letterSpacing: Theme.tracking
|
|
font.capitalization: Font.AllUppercase
|
|
renderType: Text.NativeRendering
|
|
|
|
Behavior on color {
|
|
ColorAnimation { duration: Theme.durFast }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
transform: Translate {
|
|
x: root.pressed ? 0 : (root.highlighted ? root.lunge : 0)
|
|
|
|
Behavior on x {
|
|
NumberAnimation {
|
|
duration: Theme.durBase
|
|
easing.type: Easing.OutCubic
|
|
}
|
|
}
|
|
}
|
|
|
|
scale: root.pressed ? 0.97 : 1.0
|
|
Behavior on scale {
|
|
NumberAnimation { duration: Theme.durFast; easing.type: Easing.OutExpo }
|
|
}
|
|
|
|
HoverHandler {
|
|
id: hover
|
|
enabled: root.enabled
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
|
|
TapHandler {
|
|
id: tap
|
|
enabled: root.enabled
|
|
onTapped: root.activate()
|
|
}
|
|
|
|
Keys.onReturnPressed: event => root.activateFromKey(event)
|
|
Keys.onEnterPressed: event => root.activateFromKey(event)
|
|
Keys.onSpacePressed: event => root.activateFromKey(event)
|
|
}
|