See-through keyboard background with optional blur
- Opacity slider for the panel behind the keys (10–100%); keys stay opaque - Blur Behind: asks the compositor (KWin) to blur under the rounded panel via KF6 WindowSystem; skipped at full opacity - Settings panel draws over the window background so changes show live, and scrolls when it doesn't fit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+10
-2
@@ -18,6 +18,10 @@ Window {
|
||||
readonly property rect inputRegion: keyboard.alternates.open
|
||||
? Qt.rect(0, 0, width, height)
|
||||
: Qt.rect(panel.x, panel.y, panel.width, panel.height)
|
||||
// Empty when nothing shows through, so the compositor skips the blur.
|
||||
readonly property rect blurRegion: settings.blurBackground && settings.backgroundOpacity < 1
|
||||
? Qt.rect(panel.x, panel.y, panel.width, panel.height)
|
||||
: Qt.rect(0, 0, 0, 0)
|
||||
|
||||
width: 1000
|
||||
height: 340 + popupMargin
|
||||
@@ -27,13 +31,17 @@ Window {
|
||||
color: "transparent"
|
||||
|
||||
onInputRegionChanged: placement?.setInputRegion(inputRegion)
|
||||
onPlacementChanged: placement?.setInputRegion(inputRegion)
|
||||
onBlurRegionChanged: placement?.setBlurRegion(blurRegion, Theme.windowRadius)
|
||||
onPlacementChanged: {
|
||||
placement?.setInputRegion(inputRegion);
|
||||
placement?.setBlurRegion(blurRegion, Theme.windowRadius);
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: panel
|
||||
anchors { fill: parent; topMargin: root.popupMargin }
|
||||
radius: Theme.windowRadius
|
||||
color: Theme.background
|
||||
color: Qt.rgba(Theme.background.r, Theme.background.g, Theme.background.b, root.settings.backgroundOpacity)
|
||||
|
||||
Keyboard {
|
||||
id: keyboard
|
||||
|
||||
+27
-5
@@ -1,21 +1,25 @@
|
||||
import QtQuick
|
||||
import Sloposk
|
||||
|
||||
// Replaces the keys while open. Binds straight to Settings, which persists.
|
||||
Rectangle {
|
||||
// Replaces the keys while open, over the window's own background so
|
||||
// opacity changes show live. Binds straight to Settings, which persists.
|
||||
Flickable {
|
||||
id: panel
|
||||
|
||||
required property Settings settings
|
||||
required property LayoutModel layoutModel
|
||||
|
||||
color: Theme.background
|
||||
radius: Theme.windowRadius
|
||||
clip: true
|
||||
contentHeight: columns.height + 2 * columns.y
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Row {
|
||||
id: columns
|
||||
readonly property real columnWidth: (width - spacing) / 2
|
||||
|
||||
anchors { fill: parent; margins: 16 }
|
||||
x: 16
|
||||
y: 16
|
||||
width: panel.width - 2 * x
|
||||
spacing: 32
|
||||
|
||||
Column {
|
||||
@@ -55,6 +59,24 @@ Rectangle {
|
||||
checked: panel.settings.doubleSpacePeriod
|
||||
onToggled: checked => panel.settings.doubleSpacePeriod = checked
|
||||
}
|
||||
|
||||
SectionHeader { text: qsTr("Appearance"); topPadding: 12 }
|
||||
|
||||
SliderRow {
|
||||
width: parent.width
|
||||
text: qsTr("Background")
|
||||
from: 0.1 // Settings::MinBackgroundOpacity
|
||||
value: panel.settings.backgroundOpacity
|
||||
onMoved: value => panel.settings.backgroundOpacity = value
|
||||
}
|
||||
|
||||
ToggleRow {
|
||||
width: parent.width
|
||||
text: qsTr("Blur Behind")
|
||||
detail: qsTr("Frosted glass under a see-through background, if the desktop supports it")
|
||||
checked: panel.settings.blurBackground
|
||||
onToggled: checked => panel.settings.blurBackground = checked
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import QtQuick
|
||||
|
||||
// A labelled slider in the iOS style; value runs from `from` to 1.
|
||||
Item {
|
||||
id: row
|
||||
|
||||
required property string text
|
||||
property real from: 0
|
||||
property real value: 1
|
||||
signal moved(real value)
|
||||
|
||||
implicitHeight: 52
|
||||
|
||||
function moveTo(x) {
|
||||
const fraction = Math.max(0, Math.min(1, (x - knob.width / 2) / (track.width - knob.width)));
|
||||
row.moved(row.from + fraction * (1 - row.from));
|
||||
}
|
||||
|
||||
Text {
|
||||
id: label
|
||||
anchors { left: parent.left; verticalCenter: parent.verticalCenter }
|
||||
width: Math.min(implicitWidth, parent.width / 3)
|
||||
text: row.text
|
||||
color: Theme.text
|
||||
font.pixelSize: 16
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
id: percent
|
||||
anchors { right: parent.right; verticalCenter: parent.verticalCenter }
|
||||
width: 44
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: Math.round(row.value * 100) + "%"
|
||||
color: Theme.secondaryText
|
||||
font.pixelSize: 14
|
||||
}
|
||||
|
||||
Item {
|
||||
id: track
|
||||
anchors { left: label.right; leftMargin: 12; right: percent.left; rightMargin: 8 }
|
||||
height: parent.height
|
||||
|
||||
readonly property real fraction: (row.value - row.from) / (1 - row.from)
|
||||
|
||||
Rectangle {
|
||||
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
|
||||
height: 4
|
||||
radius: 2
|
||||
color: Theme.functionKey
|
||||
|
||||
Rectangle {
|
||||
width: knob.x + knob.width / 2
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
color: Theme.accent
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: knob
|
||||
x: track.fraction * (track.width - width)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 26
|
||||
height: width
|
||||
radius: width / 2
|
||||
color: "#ffffff"
|
||||
border { color: Theme.keyShadow; width: 0.5 }
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
onTapped: eventPoint => row.moveTo(eventPoint.position.x)
|
||||
}
|
||||
DragHandler {
|
||||
target: null
|
||||
xAxis.enabled: true
|
||||
yAxis.enabled: false
|
||||
onCentroidChanged: if (active) row.moveTo(centroid.position.x)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user