The binary now links Core, Gui, Quick and QuickShapes, nothing else. Qt Widgets was there for one reason, QSystemTrayIcon, so the tray icon is gone and QApplication is back to QGuiApplication. The cat itself is the whole interface: right-click or long-press opens the settings window, which carries the tricks and a quit button. Ctrl+C in the terminal works as well. The settings window is rebuilt from Qt Quick primitives. AppButton, AppSlider, AppToggle and SettingsGroup replace the Controls types, keyboard handling and accessible roles included, and a Flickable with plain positioners replaces QtQuick.Layouts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
115 lines
3.4 KiB
QML
115 lines
3.4 KiB
QML
pragma ComponentBehavior: Bound
|
|
import QtQuick
|
|
|
|
// A horizontal slider built from primitives. Reports every change through
|
|
// moved() rather than writing back, so the owner stays the single source.
|
|
Item {
|
|
id: slider
|
|
|
|
property real from: 0
|
|
property real to: 100
|
|
property real stepSize: 1
|
|
property real value: 0
|
|
property string suffix: ""
|
|
|
|
signal moved(real value)
|
|
|
|
readonly property real span: Math.max(0.0001, to - from)
|
|
readonly property real position: Math.min(1, Math.max(0, (value - from) / span))
|
|
|
|
function valueAt(px) {
|
|
const usable = Math.max(1, track.width - handle.width)
|
|
const ratio = Math.min(1, Math.max(0, (px - handle.width / 2) / usable))
|
|
const raw = from + ratio * span
|
|
return Math.min(to, Math.max(from, Math.round(raw / stepSize) * stepSize))
|
|
}
|
|
|
|
function nudge(steps) {
|
|
slider.moved(Math.min(to, Math.max(from, value + steps * stepSize)))
|
|
}
|
|
|
|
implicitWidth: 220
|
|
implicitHeight: 26
|
|
activeFocusOnTab: true
|
|
|
|
Accessible.role: Accessible.Slider
|
|
Accessible.name: qsTr("Slider")
|
|
Accessible.onIncreaseAction: slider.nudge(1)
|
|
Accessible.onDecreaseAction: slider.nudge(-1)
|
|
|
|
Text {
|
|
id: readout
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: slider.suffix.length > 0 ? 52 : 0
|
|
visible: slider.suffix.length > 0
|
|
horizontalAlignment: Text.AlignRight
|
|
text: Math.round(slider.value) + " " + slider.suffix
|
|
color: "#7a7484"
|
|
font.pixelSize: 12
|
|
}
|
|
|
|
Item {
|
|
id: track
|
|
anchors.left: parent.left
|
|
anchors.right: readout.visible ? readout.left : parent.right
|
|
anchors.rightMargin: readout.visible ? 8 : 0
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
height: parent.height
|
|
|
|
Rectangle {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: parent.width
|
|
height: 4
|
|
radius: 2
|
|
color: "#ded8cf"
|
|
antialiasing: true
|
|
|
|
Rectangle {
|
|
width: parent.width * slider.position
|
|
height: parent.height
|
|
radius: parent.radius
|
|
color: "#4d7ea8"
|
|
antialiasing: true
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: handle
|
|
x: (track.width - width) * slider.position
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: 18
|
|
height: 18
|
|
radius: 9
|
|
color: "white"
|
|
border.width: slider.activeFocus ? 3 : 2
|
|
border.color: slider.activeFocus ? "#2f5f85" : "#4d7ea8"
|
|
antialiasing: true
|
|
}
|
|
|
|
TapHandler {
|
|
onTapped: function(point) { slider.moved(slider.valueAt(point.position.x)) }
|
|
}
|
|
|
|
DragHandler {
|
|
target: null
|
|
xAxis.enabled: true
|
|
yAxis.enabled: false
|
|
onCentroidChanged: {
|
|
if (active)
|
|
slider.moved(slider.valueAt(centroid.position.x))
|
|
}
|
|
}
|
|
}
|
|
|
|
Keys.onPressed: function(event) {
|
|
if (event.key === Qt.Key_Left || event.key === Qt.Key_Down) {
|
|
slider.nudge(-1)
|
|
event.accepted = true
|
|
} else if (event.key === Qt.Key_Right || event.key === Qt.Key_Up) {
|
|
slider.nudge(1)
|
|
event.accepted = true
|
|
}
|
|
}
|
|
}
|