Bring on gradient borders
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import qs.Commons
|
||||
import "../Commons/BorderGeometry.js" as Geometry
|
||||
|
||||
// Visual-only border renderer. It draws a filled rounded ring so borders can
|
||||
// have gradients and independent top/right/bottom/left widths. Flat uniform
|
||||
// borders should stay on Rectangle.border; this component is the fallback for
|
||||
// cases Rectangle cannot represent.
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var borderSpec: Border.none()
|
||||
property real radius: 0
|
||||
|
||||
readonly property var _widths: borderSpec && borderSpec.widths ? borderSpec.widths : Geometry.parseWidthSpec(0, 0)
|
||||
readonly property bool hasBorder: Geometry.maxWidth(_widths) > 0
|
||||
readonly property var _gradient: borderSpec && borderSpec.gradient ? borderSpec.gradient : ({ colors: [], angle: 0, enabled: false })
|
||||
readonly property var _colors: _gradient.enabled ? _gradient.colors : [Border.color(borderSpec), Border.color(borderSpec)]
|
||||
readonly property var _endpoints: Geometry.gradientEndpoints(width, height, _gradient.angle || 0)
|
||||
readonly property string _path: Geometry.ringPath(width, height, radius, _widths)
|
||||
|
||||
visible: hasBorder && width > 0 && height > 0
|
||||
anchors.fill: parent
|
||||
z: 100000
|
||||
|
||||
Shape {
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
|
||||
ShapePath {
|
||||
fillRule: ShapePath.OddEvenFill
|
||||
strokeWidth: 0
|
||||
fillGradient: LinearGradient {
|
||||
x1: root._endpoints.x1
|
||||
y1: root._endpoints.y1
|
||||
x2: root._endpoints.x2
|
||||
y2: root._endpoints.y2
|
||||
|
||||
GradientStop { position: Geometry.stopPosition(root._colors, 0); color: Geometry.stopColor(root._colors, 0) }
|
||||
GradientStop { position: Geometry.stopPosition(root._colors, 1); color: Geometry.stopColor(root._colors, 1) }
|
||||
GradientStop { position: Geometry.stopPosition(root._colors, 2); color: Geometry.stopColor(root._colors, 2) }
|
||||
GradientStop { position: Geometry.stopPosition(root._colors, 3); color: Geometry.stopColor(root._colors, 3) }
|
||||
GradientStop { position: Geometry.stopPosition(root._colors, 4); color: Geometry.stopColor(root._colors, 4) }
|
||||
GradientStop { position: Geometry.stopPosition(root._colors, 5); color: Geometry.stopColor(root._colors, 5) }
|
||||
GradientStop { position: Geometry.stopPosition(root._colors, 6); color: Geometry.stopColor(root._colors, 6) }
|
||||
GradientStop { position: Geometry.stopPosition(root._colors, 7); color: Geometry.stopColor(root._colors, 7) }
|
||||
GradientStop { position: Geometry.stopPosition(root._colors, 8); color: Geometry.stopColor(root._colors, 8) }
|
||||
GradientStop { position: Geometry.stopPosition(root._colors, 9); color: Geometry.stopColor(root._colors, 9) }
|
||||
}
|
||||
|
||||
PathSvg { path: root._path }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import QtQuick
|
||||
import qs.Commons
|
||||
|
||||
// Rectangle-compatible surface with Omarchy border specs. Uses native
|
||||
// Rectangle.border for cheap flat/uniform borders and BorderOverlay for
|
||||
// gradients or per-side widths.
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var borderSpec: Border.none()
|
||||
property real padding: 0
|
||||
property real topPadding: padding
|
||||
property real rightPadding: padding
|
||||
property real bottomPadding: padding
|
||||
property real leftPadding: padding
|
||||
|
||||
readonly property real borderTop: Border.top(borderSpec)
|
||||
readonly property real borderRight: Border.right(borderSpec)
|
||||
readonly property real borderBottom: Border.bottom(borderSpec)
|
||||
readonly property real borderLeft: Border.left(borderSpec)
|
||||
readonly property real contentTopInset: borderTop + topPadding
|
||||
readonly property real contentRightInset: borderRight + rightPadding
|
||||
readonly property real contentBottomInset: borderBottom + bottomPadding
|
||||
readonly property real contentLeftInset: borderLeft + leftPadding
|
||||
readonly property bool usesOverlayBorder: Border.needsOverlay(borderSpec)
|
||||
|
||||
border.color: Border.canUseNative(borderSpec) ? Border.color(borderSpec) : "transparent"
|
||||
border.width: Border.canUseNative(borderSpec) ? Border.uniformWidth(borderSpec) : 0
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
active: root.usesOverlayBorder
|
||||
|
||||
sourceComponent: BorderOverlay {
|
||||
anchors.fill: parent
|
||||
radius: root.radius
|
||||
borderSpec: root.borderSpec
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
-22
@@ -17,7 +17,7 @@ import qs.Commons
|
||||
//
|
||||
// Emits `hovered(bool)` so panels with their own keyboard cursor model
|
||||
// can update state on mouse enter/leave.
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: root
|
||||
|
||||
property string text: ""
|
||||
@@ -46,6 +46,11 @@ Rectangle {
|
||||
property real verticalPadding: Style.spacing.controlPaddingY
|
||||
property bool leftAlign: false
|
||||
|
||||
leftPadding: horizontalPadding
|
||||
rightPadding: horizontalPadding
|
||||
topPadding: verticalPadding
|
||||
bottomPadding: verticalPadding
|
||||
|
||||
// Tooltip palette. Auto-rendered if tooltipText is set. Defaults pull
|
||||
// from [tooltip] in shell.toml; override per-instance only when a button
|
||||
// intentionally wants a tooltip that diverges from the theme.
|
||||
@@ -62,13 +67,21 @@ Rectangle {
|
||||
Keys.onEnterPressed: if (focusable) root.clicked()
|
||||
Keys.onSpacePressed: if (focusable) root.clicked()
|
||||
|
||||
implicitWidth: row.implicitWidth + horizontalPadding * 2
|
||||
implicitHeight: row.implicitHeight + verticalPadding * 2
|
||||
implicitWidth: row.implicitWidth + horizontalPadding * 2 + borderLeft + borderRight
|
||||
implicitHeight: row.implicitHeight + verticalPadding * 2 + borderTop + borderBottom
|
||||
radius: Style.cornerRadius
|
||||
|
||||
readonly property bool hot: mouseArea.containsMouse || hasCursor
|
||||
readonly property bool _showFocusRing: focusable && activeFocus
|
||||
readonly property color _selectedColor: Style.selectedStateColor(root.foreground, root.accent)
|
||||
readonly property var _tooltipBorderSpec: Border.localOrSurfaceSpec("tooltip", "border", root.tooltipBorder, Color.tooltip.border, Math.max(1, Style.normalBorderWidth))
|
||||
readonly property var _selectedBorderSpec: Border.controlSpec("selected", root.foreground, root.accent)
|
||||
readonly property var _normalBorderSpec: Border.controlSpec("normal", root.foreground, root.accent)
|
||||
readonly property var _borderSpec: _showFocusRing ? Border.controlSpec("focus", root.foreground, root.accent)
|
||||
: hot ? Border.controlSpec("hover-cursor", root.foreground, root.accent)
|
||||
: selected ? (Border.controlHasWidth("selected") ? _selectedBorderSpec : (bordered ? _normalBorderSpec : Border.none()))
|
||||
: bordered ? _normalBorderSpec
|
||||
: Border.none()
|
||||
|
||||
color: mouseArea.pressed ? Style.pressedFillFor(root.foreground, root.accent)
|
||||
: _showFocusRing ? Style.focusFillFor(root.foreground, root.accent)
|
||||
@@ -84,17 +97,7 @@ Rectangle {
|
||||
// default for plain buttons; explicitly bordered buttons keep their
|
||||
// normal border when selected unless selected-border-width opts in to a
|
||||
// dedicated selected border.
|
||||
border.color: _showFocusRing ? Style.focusBorderFor(root.foreground, root.accent)
|
||||
: hot ? Style.hoverBorderFor(root.foreground, root.accent)
|
||||
: selected ? (Style.selectedBorderWidth > 0 ? Style.selectedBorderFor(root.foreground, root.accent) : Style.normalBorderFor(root.foreground, root.accent))
|
||||
: bordered ? Style.normalBorderFor(root.foreground, root.accent)
|
||||
: "transparent"
|
||||
|
||||
border.width: _showFocusRing ? Style.focusBorderWidth
|
||||
: hot ? Style.hoverBorderWidth
|
||||
: selected ? (Style.selectedBorderWidth > 0 ? Style.selectedBorderWidth : (bordered ? Style.normalBorderWidth : 0))
|
||||
: bordered ? Style.normalBorderWidth
|
||||
: 0
|
||||
borderSpec: _borderSpec
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 120 } }
|
||||
|
||||
@@ -103,10 +106,9 @@ Rectangle {
|
||||
text: root.tooltipText
|
||||
delay: 400
|
||||
padding: 0
|
||||
background: Rectangle {
|
||||
background: BorderSurface {
|
||||
color: root.tooltipBackground
|
||||
border.color: root.tooltipBorder
|
||||
border.width: Math.max(1, Style.normalBorderWidth)
|
||||
borderSpec: root._tooltipBorderSpec
|
||||
radius: 0
|
||||
}
|
||||
contentItem: Text {
|
||||
@@ -114,10 +116,10 @@ Rectangle {
|
||||
color: root.tooltipForeground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
leftPadding: Style.spacing.controlPaddingX
|
||||
rightPadding: Style.spacing.controlPaddingX
|
||||
topPadding: Style.spacing.controlPaddingY
|
||||
bottomPadding: Style.spacing.controlPaddingY
|
||||
leftPadding: Border.left(root._tooltipBorderSpec) + Style.spacing.controlPaddingX
|
||||
rightPadding: Border.right(root._tooltipBorderSpec) + Style.spacing.controlPaddingX
|
||||
topPadding: Border.top(root._tooltipBorderSpec) + Style.spacing.controlPaddingY
|
||||
bottomPadding: Border.bottom(root._tooltipBorderSpec) + Style.spacing.controlPaddingY
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +127,7 @@ Rectangle {
|
||||
id: row
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: root.leftAlign ? parent.left : undefined
|
||||
anchors.leftMargin: root.leftAlign ? root.horizontalPadding : 0
|
||||
anchors.leftMargin: root.leftAlign ? root.contentLeftInset : 0
|
||||
anchors.horizontalCenter: root.leftAlign ? undefined : parent.horizontalCenter
|
||||
spacing: Style.spacing.controlGap
|
||||
|
||||
|
||||
@@ -46,20 +46,24 @@ Item {
|
||||
|
||||
MouseArea { anchors.fill: parent; onClicked: root.canceled() }
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: card
|
||||
width: Math.min(parent.width - Style.space(96), Style.space(370))
|
||||
height: Style.space(132)
|
||||
anchors.centerIn: parent
|
||||
color: root.background
|
||||
border.color: root.selectedText
|
||||
border.width: Style.normalBorderWidth
|
||||
borderSpec: Border.flat(root.selectedText, Style.normalBorderWidth)
|
||||
padding: Style.space(18)
|
||||
radius: root.cornerRadius
|
||||
|
||||
MouseArea { anchors.fill: parent; onClicked: {} }
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.space(18)
|
||||
anchors.topMargin: card.contentTopInset
|
||||
anchors.rightMargin: card.contentRightInset
|
||||
anchors.bottomMargin: card.contentBottomInset
|
||||
anchors.leftMargin: card.contentLeftInset
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
@@ -80,7 +84,7 @@ Item {
|
||||
Repeater {
|
||||
model: [root.cancelText, root.confirmText]
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
required property int index
|
||||
required property string modelData
|
||||
|
||||
@@ -92,10 +96,9 @@ Item {
|
||||
color: selected
|
||||
? (destructive ? Util.alpha(Color.urgent, 0.22) : root.selectedBackground)
|
||||
: "transparent"
|
||||
border.color: destructive
|
||||
borderSpec: Border.flat(destructive
|
||||
? (selected ? Color.urgent : Util.alpha(Color.urgent, 0.56))
|
||||
: (selected ? root.selectedText : Util.alpha(root.foreground, 0.38))
|
||||
border.width: Style.normalBorderWidth
|
||||
: (selected ? root.selectedText : Util.alpha(root.foreground, 0.38)), Style.normalBorderWidth)
|
||||
radius: 0
|
||||
|
||||
Text {
|
||||
|
||||
@@ -11,7 +11,7 @@ import qs.Commons
|
||||
// hover-cursor border. `outline` remains as a compatibility flag for
|
||||
// callers that used to request border-only rows, but slider rows still
|
||||
// receive the same hover-cursor background as every other row.
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: root
|
||||
|
||||
property bool hasCursor: false
|
||||
@@ -27,19 +27,13 @@ Rectangle {
|
||||
radius: Style.cornerRadius
|
||||
|
||||
color: hasCursor ? fill : (current ? currentFill : "transparent")
|
||||
|
||||
border.color: root.hasCursor
|
||||
? Style.hoverBorderFor(root.foreground, root.accent)
|
||||
borderSpec: root.hasCursor
|
||||
? Border.controlSpec("hover-cursor", root.foreground, root.accent)
|
||||
: (root.current
|
||||
? Style.selectedBorderFor(root.foreground, root.accent)
|
||||
? Border.controlSpec("selected", root.foreground, root.accent)
|
||||
: (root.bordered
|
||||
? Style.normalBorderFor(root.foreground, root.accent)
|
||||
: "transparent"))
|
||||
border.width: root.hasCursor
|
||||
? Style.hoverBorderWidth
|
||||
: (root.current
|
||||
? Style.selectedBorderWidth
|
||||
: (root.bordered ? Style.normalBorderWidth : 0))
|
||||
? Border.controlSpec("normal", root.foreground, root.accent)
|
||||
: Border.none()))
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 60 }
|
||||
|
||||
+13
-9
@@ -26,6 +26,7 @@ Item {
|
||||
property color background: Color.popups.background
|
||||
property color popupBorder: Color.popups.border
|
||||
property color accent: Color.accent
|
||||
readonly property var popupBorderSpec: Border.localOrSurfaceSpec("popups", "border", popupBorder, Color.popups.border, Style.normalBorderWidth)
|
||||
property string fontFamily: Style.font.family
|
||||
property int rowHeight: Style.spacing.controlHeight
|
||||
property int popupRowHeight: Style.spacing.popupRowHeight
|
||||
@@ -78,7 +79,7 @@ Item {
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: trigger
|
||||
width: parent.width
|
||||
height: root.rowHeight
|
||||
@@ -86,10 +87,10 @@ Item {
|
||||
|
||||
readonly property bool _focused: trigger.activeFocus
|
||||
readonly property bool _hot: triggerHover.hovered || root.hasCursor
|
||||
readonly property var _borderSpec: Border.controlSpec(trigger._focused ? "focus" : (trigger._hot ? "hover-cursor" : "normal"), root.foreground, root.accent)
|
||||
|
||||
color: Style.controlFill(trigger._focused, trigger._hot, root.foreground, root.accent)
|
||||
border.color: Style.controlBorder(trigger._focused, trigger._hot, root.foreground, root.accent)
|
||||
border.width: Style.controlBorderWidth(trigger._focused, trigger._hot)
|
||||
borderSpec: _borderSpec
|
||||
|
||||
activeFocusOnTab: true
|
||||
|
||||
@@ -112,8 +113,8 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: chevron.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Style.spacing.controlPaddingX
|
||||
anchors.rightMargin: Style.spacing.md
|
||||
anchors.leftMargin: trigger.borderLeft + Style.spacing.controlPaddingX
|
||||
anchors.rightMargin: trigger.borderRight + Style.spacing.md
|
||||
text: root.currentLabel()
|
||||
color: root.foreground
|
||||
font.family: root.fontFamily
|
||||
@@ -125,7 +126,7 @@ Item {
|
||||
id: chevron
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.rightMargin: Style.spacing.controlGap
|
||||
anchors.rightMargin: trigger.borderRight + Style.spacing.controlGap
|
||||
text: ""
|
||||
color: Qt.darker(root.foreground, 1.2)
|
||||
font.family: root.fontFamily
|
||||
@@ -149,12 +150,15 @@ Item {
|
||||
implicitHeight: Math.min(root.options.length * root.popupRowHeight + Math.max(0, root.options.length - 1) * Style.spacing.labelGap + Style.spacing.xxs,
|
||||
root.popupRowHeight * 8 + 7 * Style.spacing.labelGap + Style.spacing.xxs)
|
||||
padding: Style.spacing.hairline
|
||||
leftPadding: Border.left(root.popupBorderSpec) + Style.spacing.hairline
|
||||
rightPadding: Border.right(root.popupBorderSpec) + Style.spacing.hairline
|
||||
topPadding: Border.top(root.popupBorderSpec) + Style.spacing.hairline
|
||||
bottomPadding: Border.bottom(root.popupBorderSpec) + Style.spacing.hairline
|
||||
focus: true
|
||||
|
||||
background: Rectangle {
|
||||
background: BorderSurface {
|
||||
color: root.background
|
||||
border.color: root.popupBorder
|
||||
border.width: Style.normalBorderWidth
|
||||
borderSpec: root.popupBorderSpec
|
||||
radius: Style.cornerRadius
|
||||
}
|
||||
|
||||
|
||||
@@ -285,15 +285,15 @@ PanelWindow {
|
||||
|
||||
// --- card ----------------------------------------------------------------
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: card
|
||||
x: root.cardOrigin.x
|
||||
y: root.cardOrigin.y
|
||||
width: root.contentWidth
|
||||
height: root.contentHeight
|
||||
color: Color.popups.background
|
||||
border.color: Color.popups.border
|
||||
border.width: Math.max(1, Style.space(2))
|
||||
borderSpec: Border.surfaceSpec("popups", "border", Color.popups.border, Math.max(1, Style.space(2)))
|
||||
padding: root.padding
|
||||
radius: Style.cornerRadius
|
||||
opacity: root.open || root.popoutSwitching ? 1.0 : 0
|
||||
|
||||
@@ -309,7 +309,10 @@ PanelWindow {
|
||||
Item {
|
||||
id: contentHolder
|
||||
anchors.fill: parent
|
||||
anchors.margins: root.padding
|
||||
anchors.topMargin: card.contentTopInset
|
||||
anchors.rightMargin: card.contentRightInset
|
||||
anchors.bottomMargin: card.contentBottomInset
|
||||
anchors.leftMargin: card.contentLeftInset
|
||||
opacity: root.popoutSwitching ? (root.open ? 1.0 : 0) : 1.0
|
||||
|
||||
Behavior on opacity {
|
||||
|
||||
+21
-19
@@ -37,6 +37,7 @@ Item {
|
||||
property color background: Color.popups.background
|
||||
property color popupBorder: Color.popups.border
|
||||
property color accent: Color.accent
|
||||
readonly property var popupBorderSpec: Border.localOrSurfaceSpec("popups", "border", popupBorder, Color.popups.border, Style.normalBorderWidth)
|
||||
property string fontFamily: Style.font.family
|
||||
property int rowHeight: Style.spacing.controlHeight
|
||||
property int popupRowHeight: Style.spacing.popupRowHeight
|
||||
@@ -266,7 +267,7 @@ Item {
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: trigger
|
||||
width: parent.width
|
||||
height: root.rowHeight
|
||||
@@ -274,10 +275,10 @@ Item {
|
||||
|
||||
readonly property bool _focused: trigger.activeFocus
|
||||
readonly property bool _hot: triggerHover.hovered || root.hasCursor
|
||||
readonly property var _borderSpec: Border.controlSpec(trigger._focused ? "focus" : (trigger._hot ? "hover-cursor" : "normal"), root.foreground, root.accent)
|
||||
|
||||
color: Style.controlFill(trigger._focused, trigger._hot, root.foreground, root.accent)
|
||||
border.color: Style.controlBorder(trigger._focused, trigger._hot, root.foreground, root.accent)
|
||||
border.width: Style.controlBorderWidth(trigger._focused, trigger._hot)
|
||||
borderSpec: _borderSpec
|
||||
|
||||
activeFocusOnTab: true
|
||||
|
||||
@@ -300,8 +301,8 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: chevron.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Style.spacing.controlPaddingX
|
||||
anchors.rightMargin: Style.spacing.md
|
||||
anchors.leftMargin: trigger.borderLeft + Style.spacing.controlPaddingX
|
||||
anchors.rightMargin: trigger.borderRight + Style.spacing.md
|
||||
text: root.selectionLabel() || root.triggerLabel || root.noSelectionText
|
||||
color: root.selectionLabel() ? root.foreground : Qt.darker(root.foreground, 1.5)
|
||||
font.family: root.fontFamily
|
||||
@@ -313,7 +314,7 @@ Item {
|
||||
id: chevron
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.rightMargin: Style.spacing.controlGap
|
||||
anchors.rightMargin: trigger.borderRight + Style.spacing.controlGap
|
||||
text: ""
|
||||
color: Qt.darker(root.foreground, 1.2)
|
||||
font.family: root.fontFamily
|
||||
@@ -359,6 +360,10 @@ Item {
|
||||
// when there isn't room, otherwise the popup overflows the window.
|
||||
implicitHeight: Math.min(_availableBelow, _idealContent, _maxRowsHeight)
|
||||
padding: Style.spacing.hairline
|
||||
leftPadding: Border.left(root.popupBorderSpec) + Style.spacing.hairline
|
||||
rightPadding: Border.right(root.popupBorderSpec) + Style.spacing.hairline
|
||||
topPadding: Border.top(root.popupBorderSpec) + Style.spacing.hairline
|
||||
bottomPadding: Border.bottom(root.popupBorderSpec) + Style.spacing.hairline
|
||||
focus: true
|
||||
|
||||
Connections {
|
||||
@@ -369,10 +374,9 @@ Item {
|
||||
function onHeightChanged() { popup.reposition() }
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
background: BorderSurface {
|
||||
color: root.background
|
||||
border.color: root.popupBorder
|
||||
border.width: Style.normalBorderWidth
|
||||
borderSpec: root.popupBorderSpec
|
||||
radius: Style.cornerRadius
|
||||
}
|
||||
|
||||
@@ -432,7 +436,7 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: refreshButton
|
||||
visible: root.arrayFrom(root.optionsCommand).length > 0
|
||||
enabled: !root.loadingOptions
|
||||
@@ -442,10 +446,9 @@ Item {
|
||||
color: refreshHover.hovered
|
||||
? Style.hoverFillFor(root.foreground, root.accent)
|
||||
: Style.normalFillFor(root.foreground, root.accent)
|
||||
border.color: refreshHover.hovered
|
||||
? Style.hoverBorderFor(root.foreground, root.accent)
|
||||
: Style.normalBorderFor(root.foreground, root.accent)
|
||||
border.width: refreshHover.hovered ? Style.hoverBorderWidth : Style.normalBorderWidth
|
||||
borderSpec: refreshHover.hovered
|
||||
? Border.controlSpec("hover-cursor", root.foreground, root.accent)
|
||||
: Border.controlSpec("normal", root.foreground, root.accent)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
@@ -550,17 +553,16 @@ Item {
|
||||
anchors.rightMargin: Style.spacing.controlPaddingX
|
||||
spacing: Style.spacing.rowGap
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: checkbox
|
||||
width: Style.space(16)
|
||||
height: Style.space(16)
|
||||
radius: Math.max(2, Style.cornerRadius / 2)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: selected ? Style.selectedFillFor(root.foreground, root.accent) : "transparent"
|
||||
border.color: selected
|
||||
? Style.selectedBorderFor(root.foreground, root.accent)
|
||||
: Style.normalBorderFor(root.foreground, root.accent)
|
||||
border.width: selected ? Style.selectedBorderWidth : Style.normalBorderWidth
|
||||
borderSpec: selected
|
||||
? Border.controlSpec("selected", root.foreground, root.accent)
|
||||
: Border.controlSpec("normal", root.foreground, root.accent)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
|
||||
@@ -44,15 +44,20 @@ Column {
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: root.fontSize
|
||||
|
||||
readonly property bool _focused: spin.activeFocus
|
||||
readonly property bool _hot: root._hovered || root.hasCursor
|
||||
readonly property var _borderSpec: Border.controlSpec(_focused ? "focus" : (_hot ? "hover-cursor" : "normal"), root.foreground, root.accent)
|
||||
|
||||
leftPadding: Border.left(_borderSpec) + Style.spacing.controlPaddingX
|
||||
rightPadding: Border.right(_borderSpec) + Style.spacing.controlPaddingX
|
||||
topPadding: Border.top(_borderSpec)
|
||||
bottomPadding: Border.bottom(_borderSpec)
|
||||
|
||||
onValueModified: root.modified(value)
|
||||
|
||||
background: Rectangle {
|
||||
readonly property bool _focused: spin.activeFocus
|
||||
readonly property bool _hot: root._hovered || root.hasCursor
|
||||
|
||||
color: Style.controlFill(_focused, _hot, root.foreground, root.accent)
|
||||
border.color: Style.controlBorder(_focused, _hot, root.foreground, root.accent)
|
||||
border.width: Style.controlBorderWidth(_focused, _hot)
|
||||
background: BorderSurface {
|
||||
color: Style.controlFill(spin._focused, spin._hot, root.foreground, root.accent)
|
||||
borderSpec: spin._borderSpec
|
||||
radius: Style.cornerRadius
|
||||
|
||||
HoverHandler {
|
||||
|
||||
@@ -24,7 +24,7 @@ import qs.Commons
|
||||
// Use this when a PanelActionButton is itself the cursor target (rather
|
||||
// than living inside a CursorSurface row). Emits `hovered(bool)` on
|
||||
// pointer enter/leave so the panel can update its cursor state to match.
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: root
|
||||
|
||||
property string iconText: ""
|
||||
@@ -53,22 +53,18 @@ Rectangle {
|
||||
|
||||
readonly property bool _showFocusRing: focusable && activeFocus
|
||||
readonly property bool _hot: (mouse.containsMouse || root.hasCursor) && root.enabled
|
||||
readonly property var _borderSpec: _showFocusRing
|
||||
? Border.controlSpec("focus", hoverColor, hoverColor)
|
||||
: (_hot && bordered
|
||||
? Border.controlSpec("hover-cursor", hoverColor, hoverColor)
|
||||
: (bordered ? Border.controlSpec("normal", foreground, Color.accent) : Border.none()))
|
||||
|
||||
color: _showFocusRing
|
||||
? Style.focusFillFor(hoverColor, hoverColor)
|
||||
: (_hot
|
||||
? Style.hoverFillFor(hoverColor, hoverColor)
|
||||
: "transparent")
|
||||
border.width: _showFocusRing
|
||||
? Style.focusBorderWidth
|
||||
: (_hot && bordered
|
||||
? Style.hoverBorderWidth
|
||||
: (bordered ? Style.normalBorderWidth : 0))
|
||||
border.color: _showFocusRing
|
||||
? Style.focusBorderFor(hoverColor, hoverColor)
|
||||
: (_hot && bordered
|
||||
? Style.hoverBorderFor(hoverColor, hoverColor)
|
||||
: Style.normalBorderFor(foreground, Color.accent))
|
||||
borderSpec: _borderSpec
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 60 } }
|
||||
|
||||
|
||||
@@ -56,15 +56,14 @@ Item {
|
||||
height: 1
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: detailPill
|
||||
visible: root.detail !== ""
|
||||
implicitWidth: detailText.implicitWidth + Style.space(10)
|
||||
implicitHeight: detailText.implicitHeight + Style.space(4)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: "transparent"
|
||||
border.color: Style.normalBorderFor(root.foreground)
|
||||
border.width: Style.normalBorderWidth
|
||||
borderSpec: Border.controlSpec("normal", root.foreground, Color.accent)
|
||||
radius: Style.cornerRadius
|
||||
|
||||
Text {
|
||||
|
||||
@@ -55,14 +55,13 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: knob
|
||||
width: root.knobSize
|
||||
height: root.knobSize
|
||||
radius: root.knobSize / 2
|
||||
color: root.knobColor
|
||||
border.color: root.bar ? root.bar.background : "#101315"
|
||||
border.width: Math.max(1, Style.space(2))
|
||||
borderSpec: Border.flat(root.bar ? root.bar.background : "#101315", Math.max(1, Style.space(2)))
|
||||
anchors.verticalCenter: track.verticalCenter
|
||||
x: Math.max(0, Math.min(track.width - width, track.width * root.progress - width / 2))
|
||||
scale: root._hot ? 1.15 : 1.0
|
||||
|
||||
@@ -24,13 +24,14 @@ ToolTip {
|
||||
property string fontFamily: Style.font.family
|
||||
property real fontSize: Style.font.bodySmall
|
||||
|
||||
readonly property var panelBorderSpec: Border.localOrSurfaceSpec("tooltip", "border", panelBorder, Color.tooltip.border, Style.normalBorderWidth)
|
||||
|
||||
delay: 400
|
||||
padding: 0
|
||||
|
||||
background: Rectangle {
|
||||
background: BorderSurface {
|
||||
color: root.panelBackground
|
||||
border.color: root.panelBorder
|
||||
border.width: Style.normalBorderWidth
|
||||
borderSpec: root.panelBorderSpec
|
||||
radius: Style.cornerRadius
|
||||
}
|
||||
|
||||
@@ -39,9 +40,9 @@ ToolTip {
|
||||
color: root.panelForeground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: root.fontSize
|
||||
leftPadding: Style.spacing.controlPaddingX
|
||||
rightPadding: Style.spacing.controlPaddingX
|
||||
topPadding: Style.spacing.controlPaddingY
|
||||
bottomPadding: Style.spacing.controlPaddingY
|
||||
leftPadding: Border.left(root.panelBorderSpec) + Style.spacing.controlPaddingX
|
||||
rightPadding: Border.right(root.panelBorderSpec) + Style.spacing.controlPaddingX
|
||||
topPadding: Border.top(root.panelBorderSpec) + Style.spacing.controlPaddingY
|
||||
bottomPadding: Border.bottom(root.panelBorderSpec) + Style.spacing.controlPaddingY
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ PopupWindow {
|
||||
property int contentWidth: Style.space(280)
|
||||
property int contentHeight: Style.space(200)
|
||||
property color borderColor: Color.popups.border
|
||||
property var borderSpec: Border.localOrSurfaceSpec("popups", "border", borderColor, Color.popups.border, Math.max(1, Style.space(2)))
|
||||
property bool open: false
|
||||
property bool centerOnBar: false
|
||||
// "click" — uses HyprlandFocusGrab so clicking outside dismisses the popup.
|
||||
@@ -145,12 +146,12 @@ PopupWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: card
|
||||
anchors.fill: parent
|
||||
color: Color.popups.background
|
||||
border.color: root.borderColor
|
||||
border.width: Math.max(1, Style.space(2))
|
||||
borderSpec: root.borderSpec
|
||||
padding: root.padding
|
||||
radius: Style.cornerRadius
|
||||
opacity: root.open ? 1.0 : 0
|
||||
|
||||
@@ -161,7 +162,10 @@ PopupWindow {
|
||||
Item {
|
||||
id: contentHolder
|
||||
anchors.fill: parent
|
||||
anchors.margins: root.padding
|
||||
anchors.topMargin: card.contentTopInset
|
||||
anchors.rightMargin: card.contentRightInset
|
||||
anchors.bottomMargin: card.contentBottomInset
|
||||
anchors.leftMargin: card.contentLeftInset
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
|
||||
@@ -29,6 +29,7 @@ Item {
|
||||
property color background: Color.popups.background
|
||||
property color popupBorder: Color.popups.border
|
||||
property color accent: Color.accent
|
||||
readonly property var popupBorderSpec: Border.localOrSurfaceSpec("popups", "border", popupBorder, Color.popups.border, Style.normalBorderWidth)
|
||||
property string fontFamily: Style.font.family
|
||||
property int rowHeight: Style.spacing.controlHeight
|
||||
property int popupRowHeight: Style.spacing.popupRowHeight
|
||||
@@ -100,7 +101,7 @@ Item {
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: trigger
|
||||
width: parent.width
|
||||
height: root.rowHeight
|
||||
@@ -108,10 +109,10 @@ Item {
|
||||
|
||||
readonly property bool _focused: trigger.activeFocus
|
||||
readonly property bool _hot: triggerHover.hovered || root.hasCursor
|
||||
readonly property var _borderSpec: Border.controlSpec(trigger._focused ? "focus" : (trigger._hot ? "hover-cursor" : "normal"), root.foreground, root.accent)
|
||||
|
||||
color: Style.controlFill(trigger._focused, trigger._hot, root.foreground, root.accent)
|
||||
border.color: Style.controlBorder(trigger._focused, trigger._hot, root.foreground, root.accent)
|
||||
border.width: Style.controlBorderWidth(trigger._focused, trigger._hot)
|
||||
borderSpec: _borderSpec
|
||||
|
||||
activeFocusOnTab: true
|
||||
|
||||
@@ -134,8 +135,8 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: chevron.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Style.spacing.controlPaddingX
|
||||
anchors.rightMargin: Style.spacing.md
|
||||
anchors.leftMargin: trigger.borderLeft + Style.spacing.controlPaddingX
|
||||
anchors.rightMargin: trigger.borderRight + Style.spacing.md
|
||||
text: root.currentLabel() || root.triggerLabel || root.placeholderText
|
||||
color: (root.currentLabel() || root.triggerLabel) ? root.foreground : Qt.darker(root.foreground, 1.5)
|
||||
font.family: root.fontFamily
|
||||
@@ -147,7 +148,7 @@ Item {
|
||||
id: chevron
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.rightMargin: Style.spacing.controlGap
|
||||
anchors.rightMargin: trigger.borderRight + Style.spacing.controlGap
|
||||
text: ""
|
||||
color: Qt.darker(root.foreground, 1.2)
|
||||
font.family: root.fontFamily
|
||||
@@ -172,12 +173,15 @@ Item {
|
||||
Math.min(resultList.contentHeight + Style.space(50),
|
||||
root.popupRowHeight * 6 + 5 * Style.spacing.labelGap + Style.space(50)))
|
||||
padding: Style.spacing.hairline
|
||||
leftPadding: Border.left(root.popupBorderSpec) + Style.spacing.hairline
|
||||
rightPadding: Border.right(root.popupBorderSpec) + Style.spacing.hairline
|
||||
topPadding: Border.top(root.popupBorderSpec) + Style.spacing.hairline
|
||||
bottomPadding: Border.bottom(root.popupBorderSpec) + Style.spacing.hairline
|
||||
focus: true
|
||||
|
||||
background: Rectangle {
|
||||
background: BorderSurface {
|
||||
color: root.background
|
||||
border.color: root.popupBorder
|
||||
border.width: Style.normalBorderWidth
|
||||
borderSpec: root.popupBorderSpec
|
||||
radius: Style.cornerRadius
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ TextField {
|
||||
|
||||
readonly property bool _focused: activeFocus
|
||||
readonly property bool _hot: hovered || hasCursor
|
||||
readonly property var _borderSpec: Border.controlSpec(_focused ? "focus" : (_hot ? "hover-cursor" : "normal"), root.foreground, root.accent)
|
||||
|
||||
echoMode: password ? TextInput.Password : TextInput.Normal
|
||||
font.family: Style.font.family
|
||||
@@ -43,15 +44,14 @@ TextField {
|
||||
selectedTextColor: foreground
|
||||
placeholderTextColor: Qt.darker(foreground, 1.6)
|
||||
|
||||
leftPadding: horizontalPadding
|
||||
rightPadding: horizontalPadding
|
||||
topPadding: verticalPadding
|
||||
bottomPadding: verticalPadding
|
||||
leftPadding: horizontalPadding + Border.left(_borderSpec)
|
||||
rightPadding: horizontalPadding + Border.right(_borderSpec)
|
||||
topPadding: verticalPadding + Border.top(_borderSpec)
|
||||
bottomPadding: verticalPadding + Border.bottom(_borderSpec)
|
||||
|
||||
background: Rectangle {
|
||||
background: BorderSurface {
|
||||
color: Style.controlFill(root._focused, root._hot, root.foreground, root.accent)
|
||||
border.color: Style.controlBorder(root._focused, root._hot, root.foreground, root.accent)
|
||||
border.width: Style.controlBorderWidth(root._focused, root._hot)
|
||||
borderSpec: root._borderSpec
|
||||
radius: Style.cornerRadius
|
||||
}
|
||||
}
|
||||
|
||||
+9
-10
@@ -12,7 +12,7 @@ import qs.Commons
|
||||
// `rounded` auto-detects from Style.cornerRadius so the switch follows
|
||||
// the theme: pill shape when Hyprland corners are rounded, square on sharp.
|
||||
// Callers can override per-instance.
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: root
|
||||
|
||||
property string label: ""
|
||||
@@ -52,10 +52,10 @@ Rectangle {
|
||||
radius: Style.cornerRadius
|
||||
|
||||
readonly property bool _hot: hasCursor || mouse.containsMouse
|
||||
readonly property var _borderSpec: Border.controlSpec(activeFocus ? "focus" : (_hot ? "hover-cursor" : "normal"), foreground, accent)
|
||||
|
||||
color: Style.controlFill(activeFocus, _hot, foreground, accent)
|
||||
border.color: Style.controlBorder(activeFocus, _hot, foreground, accent)
|
||||
border.width: Style.controlBorderWidth(activeFocus, _hot)
|
||||
borderSpec: _borderSpec
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 100 } }
|
||||
|
||||
@@ -64,8 +64,8 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Style.spacing.rowPaddingX
|
||||
anchors.rightMargin: Style.spacing.rowPaddingX
|
||||
anchors.leftMargin: root.borderLeft + Style.spacing.rowPaddingX
|
||||
anchors.rightMargin: root.borderRight + Style.spacing.rowPaddingX
|
||||
spacing: Style.spacing.rowPaddingX
|
||||
|
||||
Column {
|
||||
@@ -94,7 +94,7 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
BorderSurface {
|
||||
id: track
|
||||
width: root.trackWidth
|
||||
height: root.trackHeight
|
||||
@@ -102,10 +102,9 @@ Rectangle {
|
||||
color: root.checked
|
||||
? Style.selectedFillFor(root.foreground, root.accent)
|
||||
: Style.normalFillFor(root.foreground, root.accent)
|
||||
border.color: root.checked
|
||||
? Style.selectedBorderFor(root.foreground, root.accent)
|
||||
: Style.normalBorderFor(root.foreground, root.accent)
|
||||
border.width: root.checked ? Style.selectedBorderWidth : Style.normalBorderWidth
|
||||
borderSpec: root.checked
|
||||
? Border.controlSpec("selected", root.foreground, root.accent)
|
||||
: Border.controlSpec("normal", root.foreground, root.accent)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 120 } }
|
||||
|
||||
@@ -2,6 +2,8 @@ module qs.Ui
|
||||
|
||||
BarIndicator 1.0 BarIndicator.qml
|
||||
BarWidget 1.0 BarWidget.qml
|
||||
BorderOverlay 1.0 BorderOverlay.qml
|
||||
BorderSurface 1.0 BorderSurface.qml
|
||||
Button 1.0 Button.qml
|
||||
ButtonGroup 1.0 ButtonGroup.qml
|
||||
ConfirmDialog 1.0 ConfirmDialog.qml
|
||||
|
||||
Reference in New Issue
Block a user