forked from Shinonome/dots-hyprland
WallpaperOverview: remove unnecessary Variants and Item
This commit is contained in:
@@ -14,408 +14,396 @@ import Quickshell.Hyprland
|
|||||||
Scope {
|
Scope {
|
||||||
id: scope
|
id: scope
|
||||||
|
|
||||||
Variants {
|
PanelWindow {
|
||||||
id: variants
|
id: root
|
||||||
model: Quickshell.screens
|
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen)
|
||||||
|
property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor?.id)
|
||||||
|
visible: GlobalStates.wallpaperOverviewOpen
|
||||||
|
property var filteredWallpapers: Wallpapers.wallpapers
|
||||||
|
|
||||||
PanelWindow {
|
WlrLayershell.namespace: "quickshell:wallpaper-overview"
|
||||||
id: root
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
required property var modelData
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||||
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen)
|
color: "transparent"
|
||||||
property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor?.id)
|
|
||||||
screen: modelData
|
|
||||||
visible: GlobalStates.wallpaperOverviewOpen && monitorIsFocused
|
|
||||||
property var filteredWallpapers: Wallpapers.wallpapers
|
|
||||||
|
|
||||||
WlrLayershell.namespace: "quickshell:wallpaper-overview"
|
anchors {
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
top: true
|
||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
bottom: true
|
||||||
color: "transparent"
|
left: true
|
||||||
|
right: true
|
||||||
|
}
|
||||||
|
|
||||||
anchors {
|
ColumnLayout {
|
||||||
top: true
|
id: layout
|
||||||
bottom: true
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
left: true
|
anchors.top: parent.top
|
||||||
right: true
|
spacing: 8
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
TextField {
|
||||||
id: layout
|
id: filterField
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
Layout.preferredWidth: bg.implicitWidth
|
||||||
anchors.top: parent.top
|
Layout.alignment: Qt.AlignHcenter
|
||||||
spacing: 8
|
implicitHeight: 40
|
||||||
|
padding: 10
|
||||||
Item {
|
placeholderText: "Search wallpapers..."
|
||||||
width: 1
|
placeholderTextColor: Appearance.colors.colSubtext
|
||||||
height: 1
|
color: Appearance.colors.colPrimary
|
||||||
}
|
background: Rectangle {
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: filterField
|
|
||||||
Layout.preferredWidth: bg.implicitWidth
|
|
||||||
Layout.alignment: Qt.AlignHcenter
|
|
||||||
implicitHeight: 40
|
|
||||||
padding: 10
|
|
||||||
placeholderText: "Search wallpapers..."
|
|
||||||
placeholderTextColor: Appearance.colors.colSubtext
|
|
||||||
color: Appearance.colors.colPrimary
|
|
||||||
background: Rectangle {
|
|
||||||
color: Appearance.colors.colLayer0
|
|
||||||
border.color: Appearance.colors.colLayer0Border
|
|
||||||
border.width: 1
|
|
||||||
radius: Appearance.rounding.small
|
|
||||||
}
|
|
||||||
font.family: Appearance.font.family.main
|
|
||||||
font.pixelSize: Appearance.font.pixelSize.normal
|
|
||||||
|
|
||||||
onTextChanged: {
|
|
||||||
let newModel = [];
|
|
||||||
if (text.length > 0) {
|
|
||||||
for (let i = 0; i < Wallpapers.wallpapers.length; ++i) {
|
|
||||||
let wallpaperPath = Wallpapers.wallpapers[i];
|
|
||||||
if (wallpaperPath.toLowerCase().includes(text.toLowerCase())) {
|
|
||||||
newModel.push(wallpaperPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
root.filteredWallpapers = newModel;
|
|
||||||
} else {
|
|
||||||
root.filteredWallpapers = Wallpapers.wallpapers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onPressed: event => {
|
|
||||||
if (text.length === 0) {
|
|
||||||
if (event.key === Qt.Key_Down || event.key === Qt.Key_Left || event.key === Qt.Key_Right) {
|
|
||||||
bg.forceActiveFocus();
|
|
||||||
if (event.key === Qt.Key_Down)
|
|
||||||
grid.moveSelection(grid.columns);
|
|
||||||
else if (event.key === Qt.Key_Left)
|
|
||||||
grid.moveSelection(-1);
|
|
||||||
else if (event.key === Qt.Key_Right)
|
|
||||||
grid.moveSelection(1);
|
|
||||||
event.accepted = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (event.key === Qt.Key_Down) {
|
|
||||||
grid.moveSelection(grid.columns);
|
|
||||||
event.accepted = true;
|
|
||||||
bg.forceActiveFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
|
||||||
grid.activateCurrent();
|
|
||||||
event.accepted = true;
|
|
||||||
} else if (event.key === Qt.Key_Escape) {
|
|
||||||
if (filterField.text.length > 0) {
|
|
||||||
filterField.text = "";
|
|
||||||
} else {
|
|
||||||
GlobalStates.wallpaperOverviewOpen = false;
|
|
||||||
}
|
|
||||||
event.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: bg
|
|
||||||
focus: true
|
|
||||||
color: Appearance.colors.colLayer0
|
color: Appearance.colors.colLayer0
|
||||||
border.width: 1
|
|
||||||
border.color: Appearance.colors.colLayer0Border
|
border.color: Appearance.colors.colLayer0Border
|
||||||
radius: Appearance.rounding.screenRounding
|
border.width: 1
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
}
|
||||||
|
font.family: Appearance.font.family.main
|
||||||
|
font.pixelSize: Appearance.font.pixelSize.normal
|
||||||
|
|
||||||
property int calculatedRows: Math.ceil(grid.count / grid.columns)
|
onTextChanged: {
|
||||||
|
let newModel = [];
|
||||||
implicitWidth: {
|
if (text.length > 0) {
|
||||||
if (root.filteredWallpapers.length === 0) {
|
for (let i = 0; i < Wallpapers.wallpapers.length; ++i) {
|
||||||
return 300;
|
let wallpaperPath = Wallpapers.wallpapers[i];
|
||||||
} else if (root.filteredWallpapers.length < grid.columns) {
|
if (wallpaperPath.toLowerCase().includes(text.toLowerCase())) {
|
||||||
return root.filteredWallpapers.length * grid.cellWidth + 16;
|
newModel.push(wallpaperPath);
|
||||||
} else {
|
|
||||||
return Math.min(root.width * 0.7, 900);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitHeight: {
|
|
||||||
if (root.filteredWallpapers.length === 0) {
|
|
||||||
return 100;
|
|
||||||
} else {
|
|
||||||
return Math.min(root.height * 0.6, Math.min(calculatedRows, 3) * grid.cellHeight + 16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on implicitWidth {
|
|
||||||
SpringAnimation {
|
|
||||||
spring: 3
|
|
||||||
damping: 0.2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
|
||||||
SpringAnimation {
|
|
||||||
spring: 3
|
|
||||||
damping: 0.2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onPressed: event => {
|
|
||||||
if (event.key === Qt.Key_Escape) {
|
|
||||||
GlobalStates.wallpaperOverviewOpen = false;
|
|
||||||
event.accepted = true;
|
|
||||||
} else if (event.key === Qt.Key_Left) {
|
|
||||||
grid.moveSelection(-1);
|
|
||||||
event.accepted = true;
|
|
||||||
} else if (event.key === Qt.Key_Right) {
|
|
||||||
grid.moveSelection(1);
|
|
||||||
event.accepted = true;
|
|
||||||
} else if (event.key === Qt.Key_Up) {
|
|
||||||
if (grid.currentIndex < grid.columns) {
|
|
||||||
filterField.forceActiveFocus();
|
|
||||||
} else {
|
|
||||||
grid.moveSelection(-grid.columns);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
root.filteredWallpapers = newModel;
|
||||||
|
} else {
|
||||||
|
root.filteredWallpapers = Wallpapers.wallpapers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (text.length === 0) {
|
||||||
|
if (event.key === Qt.Key_Down || event.key === Qt.Key_Left || event.key === Qt.Key_Right) {
|
||||||
|
bg.forceActiveFocus();
|
||||||
|
if (event.key === Qt.Key_Down)
|
||||||
|
grid.moveSelection(grid.columns);
|
||||||
|
else if (event.key === Qt.Key_Left)
|
||||||
|
grid.moveSelection(-1);
|
||||||
|
else if (event.key === Qt.Key_Right)
|
||||||
|
grid.moveSelection(1);
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_Down) {
|
}
|
||||||
|
} else {
|
||||||
|
if (event.key === Qt.Key_Down) {
|
||||||
grid.moveSelection(grid.columns);
|
grid.moveSelection(grid.columns);
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
bg.forceActiveFocus();
|
||||||
grid.activateCurrent();
|
|
||||||
event.accepted = true;
|
|
||||||
} else if (event.key === Qt.Key_Backspace) {
|
|
||||||
if (filterField.text.length > 0) {
|
|
||||||
filterField.text = filterField.text.substring(0, filterField.text.length - 1);
|
|
||||||
}
|
|
||||||
filterField.forceActiveFocus();
|
|
||||||
event.accepted = true;
|
|
||||||
} else {
|
|
||||||
filterField.forceActiveFocus();
|
|
||||||
if (event.text.length > 0) {
|
|
||||||
filterField.text += event.text;
|
|
||||||
filterField.cursorPosition = filterField.text.length;
|
|
||||||
}
|
|
||||||
event.accepted = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||||
ColumnLayout {
|
grid.activateCurrent();
|
||||||
anchors.fill: parent
|
event.accepted = true;
|
||||||
anchors.margins: 8
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
spacing: 8
|
if (filterField.text.length > 0) {
|
||||||
|
filterField.text = "";
|
||||||
GridView {
|
} else {
|
||||||
id: grid
|
GlobalStates.wallpaperOverviewOpen = false;
|
||||||
visible: root.filteredWallpapers.length > 0
|
|
||||||
|
|
||||||
readonly property int columns: 4
|
|
||||||
property int currentIndex: 0
|
|
||||||
readonly property int rows: Math.max(1, Math.ceil(count / columns))
|
|
||||||
|
|
||||||
Layout.preferredWidth: columns * cellWidth
|
|
||||||
Layout.alignment: Qt.AlignHcenter
|
|
||||||
Layout.fillHeight: true
|
|
||||||
cellWidth: 220
|
|
||||||
cellHeight: 140
|
|
||||||
clip: true
|
|
||||||
interactive: true
|
|
||||||
keyNavigationWraps: true
|
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
|
||||||
|
|
||||||
cacheBuffer: cellHeight * 2
|
|
||||||
ScrollBar.horizontal: ScrollBar {
|
|
||||||
policy: ScrollBar.AsNeeded
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
|
||||||
policy: ScrollBar.AsNeeded
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
model: root.filteredWallpapers
|
|
||||||
onModelChanged: currentIndex = 0
|
|
||||||
|
|
||||||
function moveSelection(delta) {
|
|
||||||
for (let i = 0; i < count; i++) {
|
|
||||||
const item = itemAtIndex(i);
|
|
||||||
if (item) {
|
|
||||||
item.isHovered = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentIndex = Math.max(0, Math.min(count - 1, currentIndex + delta));
|
|
||||||
positionViewAtIndex(currentIndex, GridView.Contain);
|
|
||||||
}
|
|
||||||
function activateCurrent() {
|
|
||||||
const path = model[currentIndex];
|
|
||||||
if (!path)
|
|
||||||
return;
|
|
||||||
GlobalStates.wallpaperOverviewOpen = false;
|
|
||||||
filterField.text = "";
|
|
||||||
Wallpapers.apply(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: Item {
|
|
||||||
width: grid.cellWidth
|
|
||||||
height: grid.cellHeight
|
|
||||||
property bool isHovered: false
|
|
||||||
|
|
||||||
Behavior on width {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: animationCurves.expressiveDefaultSpatialDuration
|
|
||||||
easing.bezierCurve: animationCurves.expressiveDefaultSpatial
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on height {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: animationCurves.expressiveDefaultSpatialDuration
|
|
||||||
easing.bezierCurve: animationCurves.expressiveDefaultSpatial
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Appearance.rounding.windowRounding
|
|
||||||
color: Appearance.colors.colLayer1
|
|
||||||
border.width: (index === grid.currentIndex || parent.isHovered) ? 3 : 0
|
|
||||||
border.color: Appearance.colors.colSecondary
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: 8
|
|
||||||
color: Appearance.colors.colLayer2
|
|
||||||
radius: Appearance.rounding.elementRounding
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: Math.min(parent.width * 0.4, 32)
|
|
||||||
height: Math.min(parent.height * 0.4, 32)
|
|
||||||
radius: Appearance.rounding.elementRounding
|
|
||||||
color: Appearance.colors.colLayer3
|
|
||||||
visible: thumbnailImage.status !== Image.Ready
|
|
||||||
|
|
||||||
opacity: 0.3
|
|
||||||
SequentialAnimation on opacity {
|
|
||||||
running: parent.visible
|
|
||||||
loops: Animation.Infinite
|
|
||||||
NumberAnimation {
|
|
||||||
to: 1.0
|
|
||||||
duration: 800
|
|
||||||
easing.type: Easing.InOutSine
|
|
||||||
}
|
|
||||||
NumberAnimation {
|
|
||||||
to: 0.3
|
|
||||||
duration: 800
|
|
||||||
easing.type: Easing.InOutSine
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: thumbnailImage
|
|
||||||
anchors.fill: parent
|
|
||||||
source: `file://${modelData}`
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
asynchronous: true
|
|
||||||
cache: false
|
|
||||||
smooth: true
|
|
||||||
|
|
||||||
sourceSize.width: Math.min(128, grid.cellWidth - 16)
|
|
||||||
sourceSize.height: Math.min(96, grid.cellHeight - 16)
|
|
||||||
|
|
||||||
mipmap: false
|
|
||||||
|
|
||||||
opacity: status === Image.Ready ? 1 : 0
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 200
|
|
||||||
easing.type: Easing.OutCubic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
onEntered: {
|
|
||||||
for (let i = 0; i < grid.count; i++) {
|
|
||||||
const item = grid.itemAtIndex(i);
|
|
||||||
if (item && item !== parent) {
|
|
||||||
item.isHovered = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parent.isHovered = true;
|
|
||||||
grid.currentIndex = index;
|
|
||||||
}
|
|
||||||
onExited: {
|
|
||||||
parent.isHovered = false;
|
|
||||||
}
|
|
||||||
onClicked: {
|
|
||||||
GlobalStates.wallpaperOverviewOpen = false;
|
|
||||||
filterField.text = "";
|
|
||||||
Wallpapers.apply(modelData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add: Transition {
|
|
||||||
from: "*"
|
|
||||||
to: "*"
|
|
||||||
ParallelAnimation {
|
|
||||||
PropertyAnimation {
|
|
||||||
property: "x"
|
|
||||||
from: grid.contentX + (grid.width / 2) - width / 2
|
|
||||||
}
|
|
||||||
PropertyAnimation {
|
|
||||||
property: "y"
|
|
||||||
from: grid.contentY + (grid.height / 2) - height / 2
|
|
||||||
}
|
|
||||||
NumberAnimation {
|
|
||||||
property: "scale"
|
|
||||||
from: 0.0
|
|
||||||
to: 1.0
|
|
||||||
duration: animationCurves.expressiveDefaultSpatialDuration
|
|
||||||
easing.bezierCurve: animationCurves.expressiveDefaultSpatial
|
|
||||||
}
|
|
||||||
NumberAnimation {
|
|
||||||
property: "opacity"
|
|
||||||
from: 0.0
|
|
||||||
to: 1.0
|
|
||||||
duration: animationCurves.expressiveDefaultSpatialDuration
|
|
||||||
easing.bezierCurve: animationCurves.expressiveDefaultSpatial
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// show when no wallpaper found
|
|
||||||
ColumnLayout {
|
|
||||||
id: noWallpapersFoundLayout
|
|
||||||
visible: root.filteredWallpapers.length === 0
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
implicitHeight: noWallpapersFoundLabel.implicitHeight
|
|
||||||
implicitWidth: noWallpapersFoundLabel.implicitWidth
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: noWallpapersFoundLabel
|
|
||||||
text: "No wallpapers found"
|
|
||||||
font.family: Appearance.font.family.main
|
|
||||||
font.pixelSize: Appearance.font.pixelSize.normal
|
|
||||||
color: Appearance.colors.colSubtext
|
|
||||||
Layout.alignment: Qt.AlignHcenter | Qt.AlignVCenter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Rectangle {
|
||||||
target: GlobalStates
|
id: bg
|
||||||
function onWallpaperOverviewOpenChanged() {
|
focus: true
|
||||||
if (GlobalStates.wallpaperOverviewOpen && monitorIsFocused) {
|
color: Appearance.colors.colLayer0
|
||||||
filterField.forceActiveFocus();
|
border.width: 1
|
||||||
|
border.color: Appearance.colors.colLayer0Border
|
||||||
|
radius: Appearance.rounding.screenRounding
|
||||||
|
|
||||||
|
property int calculatedRows: Math.ceil(grid.count / grid.columns)
|
||||||
|
|
||||||
|
implicitWidth: {
|
||||||
|
if (root.filteredWallpapers.length === 0) {
|
||||||
|
return 300;
|
||||||
|
} else if (root.filteredWallpapers.length < grid.columns) {
|
||||||
|
return root.filteredWallpapers.length * grid.cellWidth + 16;
|
||||||
|
} else {
|
||||||
|
return Math.min(root.width * 0.7, 900);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
implicitHeight: {
|
||||||
|
if (root.filteredWallpapers.length === 0) {
|
||||||
|
return 100;
|
||||||
|
} else {
|
||||||
|
return Math.min(root.height * 0.6, Math.min(calculatedRows, 3) * grid.cellHeight + 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
SpringAnimation {
|
||||||
|
spring: 3
|
||||||
|
damping: 0.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
SpringAnimation {
|
||||||
|
spring: 3
|
||||||
|
damping: 0.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Escape) {
|
||||||
|
GlobalStates.wallpaperOverviewOpen = false;
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Left) {
|
||||||
|
grid.moveSelection(-1);
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Right) {
|
||||||
|
grid.moveSelection(1);
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Up) {
|
||||||
|
if (grid.currentIndex < grid.columns) {
|
||||||
|
filterField.forceActiveFocus();
|
||||||
|
} else {
|
||||||
|
grid.moveSelection(-grid.columns);
|
||||||
|
}
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Down) {
|
||||||
|
grid.moveSelection(grid.columns);
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||||
|
grid.activateCurrent();
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Backspace) {
|
||||||
|
if (filterField.text.length > 0) {
|
||||||
|
filterField.text = filterField.text.substring(0, filterField.text.length - 1);
|
||||||
|
}
|
||||||
|
filterField.forceActiveFocus();
|
||||||
|
event.accepted = true;
|
||||||
|
} else {
|
||||||
|
filterField.forceActiveFocus();
|
||||||
|
if (event.text.length > 0) {
|
||||||
|
filterField.text += event.text;
|
||||||
|
filterField.cursorPosition = filterField.text.length;
|
||||||
|
}
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 8
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
id: grid
|
||||||
|
visible: root.filteredWallpapers.length > 0
|
||||||
|
|
||||||
|
readonly property int columns: 4
|
||||||
|
property int currentIndex: 0
|
||||||
|
readonly property int rows: Math.max(1, Math.ceil(count / columns))
|
||||||
|
|
||||||
|
Layout.preferredWidth: columns * cellWidth
|
||||||
|
Layout.alignment: Qt.AlignHcenter
|
||||||
|
Layout.fillHeight: true
|
||||||
|
cellWidth: 220
|
||||||
|
cellHeight: 140
|
||||||
|
clip: true
|
||||||
|
interactive: true
|
||||||
|
keyNavigationWraps: true
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
|
||||||
|
cacheBuffer: cellHeight * 2
|
||||||
|
ScrollBar.horizontal: ScrollBar {
|
||||||
|
policy: ScrollBar.AsNeeded
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
ScrollBar.vertical: ScrollBar {
|
||||||
|
policy: ScrollBar.AsNeeded
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
model: root.filteredWallpapers
|
||||||
|
onModelChanged: currentIndex = 0
|
||||||
|
|
||||||
|
function moveSelection(delta) {
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
const item = itemAtIndex(i);
|
||||||
|
if (item) {
|
||||||
|
item.isHovered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentIndex = Math.max(0, Math.min(count - 1, currentIndex + delta));
|
||||||
|
positionViewAtIndex(currentIndex, GridView.Contain);
|
||||||
|
}
|
||||||
|
function activateCurrent() {
|
||||||
|
const path = model[currentIndex];
|
||||||
|
if (!path)
|
||||||
|
return;
|
||||||
|
GlobalStates.wallpaperOverviewOpen = false;
|
||||||
|
filterField.text = "";
|
||||||
|
Wallpapers.apply(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
width: grid.cellWidth
|
||||||
|
height: grid.cellHeight
|
||||||
|
property bool isHovered: false
|
||||||
|
|
||||||
|
Behavior on width {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: animationCurves.expressiveDefaultSpatialDuration
|
||||||
|
easing.bezierCurve: animationCurves.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: animationCurves.expressiveDefaultSpatialDuration
|
||||||
|
easing.bezierCurve: animationCurves.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Appearance.rounding.windowRounding
|
||||||
|
color: Appearance.colors.colLayer1
|
||||||
|
border.width: (index === grid.currentIndex || parent.isHovered) ? 3 : 0
|
||||||
|
border.color: Appearance.colors.colSecondary
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 8
|
||||||
|
color: Appearance.colors.colLayer2
|
||||||
|
radius: Appearance.rounding.elementRounding
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: Math.min(parent.width * 0.4, 32)
|
||||||
|
height: Math.min(parent.height * 0.4, 32)
|
||||||
|
radius: Appearance.rounding.elementRounding
|
||||||
|
color: Appearance.colors.colLayer3
|
||||||
|
visible: thumbnailImage.status !== Image.Ready
|
||||||
|
|
||||||
|
opacity: 0.3
|
||||||
|
SequentialAnimation on opacity {
|
||||||
|
running: parent.visible
|
||||||
|
loops: Animation.Infinite
|
||||||
|
NumberAnimation {
|
||||||
|
to: 1.0
|
||||||
|
duration: 800
|
||||||
|
easing.type: Easing.InOutSine
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
to: 0.3
|
||||||
|
duration: 800
|
||||||
|
easing.type: Easing.InOutSine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: thumbnailImage
|
||||||
|
anchors.fill: parent
|
||||||
|
source: `file://${modelData}`
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
asynchronous: true
|
||||||
|
cache: false
|
||||||
|
smooth: true
|
||||||
|
|
||||||
|
sourceSize.width: Math.min(128, grid.cellWidth - 16)
|
||||||
|
sourceSize.height: Math.min(96, grid.cellHeight - 16)
|
||||||
|
|
||||||
|
mipmap: false
|
||||||
|
|
||||||
|
opacity: status === Image.Ready ? 1 : 0
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 200
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onEntered: {
|
||||||
|
for (let i = 0; i < grid.count; i++) {
|
||||||
|
const item = grid.itemAtIndex(i);
|
||||||
|
if (item && item !== parent) {
|
||||||
|
item.isHovered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent.isHovered = true;
|
||||||
|
grid.currentIndex = index;
|
||||||
|
}
|
||||||
|
onExited: {
|
||||||
|
parent.isHovered = false;
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
GlobalStates.wallpaperOverviewOpen = false;
|
||||||
|
filterField.text = "";
|
||||||
|
Wallpapers.apply(modelData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add: Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "*"
|
||||||
|
ParallelAnimation {
|
||||||
|
PropertyAnimation {
|
||||||
|
property: "x"
|
||||||
|
from: grid.contentX + (grid.width / 2) - width / 2
|
||||||
|
}
|
||||||
|
PropertyAnimation {
|
||||||
|
property: "y"
|
||||||
|
from: grid.contentY + (grid.height / 2) - height / 2
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
property: "scale"
|
||||||
|
from: 0.0
|
||||||
|
to: 1.0
|
||||||
|
duration: animationCurves.expressiveDefaultSpatialDuration
|
||||||
|
easing.bezierCurve: animationCurves.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
from: 0.0
|
||||||
|
to: 1.0
|
||||||
|
duration: animationCurves.expressiveDefaultSpatialDuration
|
||||||
|
easing.bezierCurve: animationCurves.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// show when no wallpaper found
|
||||||
|
ColumnLayout {
|
||||||
|
id: noWallpapersFoundLayout
|
||||||
|
visible: root.filteredWallpapers.length === 0
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
implicitHeight: noWallpapersFoundLabel.implicitHeight
|
||||||
|
implicitWidth: noWallpapersFoundLabel.implicitWidth
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: noWallpapersFoundLabel
|
||||||
|
text: "No wallpapers found"
|
||||||
|
font.family: Appearance.font.family.main
|
||||||
|
font.pixelSize: Appearance.font.pixelSize.normal
|
||||||
|
color: Appearance.colors.colSubtext
|
||||||
|
Layout.alignment: Qt.AlignHcenter | Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: GlobalStates
|
||||||
|
function onWallpaperOverviewOpenChanged() {
|
||||||
|
if (GlobalStates.wallpaperOverviewOpen && monitorIsFocused) {
|
||||||
|
filterField.forceActiveFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user