mirror of
https://github.com/belsabbagh/dotfiles.git
synced 2026-04-11 09:36:46 +00:00
quickshell and hyprland additions
This commit is contained in:
257
.config/quickshell/caelestia/modules/launcher/AppList.qml
Normal file
257
.config/quickshell/caelestia/modules/launcher/AppList.qml
Normal file
@@ -0,0 +1,257 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import "items"
|
||||
import "services"
|
||||
import qs.components
|
||||
import qs.components.controls
|
||||
import qs.components.containers
|
||||
import qs.services
|
||||
import qs.config
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
StyledListView {
|
||||
id: root
|
||||
|
||||
required property StyledTextField search
|
||||
required property PersistentProperties visibilities
|
||||
|
||||
model: ScriptModel {
|
||||
id: model
|
||||
|
||||
onValuesChanged: root.currentIndex = 0
|
||||
}
|
||||
|
||||
spacing: Appearance.spacing.small
|
||||
orientation: Qt.Vertical
|
||||
implicitHeight: (Config.launcher.sizes.itemHeight + spacing) * Math.min(Config.launcher.maxShown, count) - spacing
|
||||
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: height
|
||||
highlightRangeMode: ListView.ApplyRange
|
||||
|
||||
highlightFollowsCurrentItem: false
|
||||
highlight: StyledRect {
|
||||
radius: Appearance.rounding.normal
|
||||
color: Colours.palette.m3onSurface
|
||||
opacity: 0.08
|
||||
|
||||
y: root.currentItem?.y ?? 0
|
||||
implicitWidth: root.width
|
||||
implicitHeight: root.currentItem?.implicitHeight ?? 0
|
||||
|
||||
Behavior on y {
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state: {
|
||||
const text = search.text;
|
||||
const prefix = Config.launcher.actionPrefix;
|
||||
if (text.startsWith(prefix)) {
|
||||
for (const action of ["calc", "scheme", "variant"])
|
||||
if (text.startsWith(`${prefix}${action} `))
|
||||
return action;
|
||||
|
||||
return "actions";
|
||||
}
|
||||
|
||||
return "apps";
|
||||
}
|
||||
|
||||
onStateChanged: {
|
||||
if (state === "scheme" || state === "variant")
|
||||
Schemes.reload();
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "apps"
|
||||
|
||||
PropertyChanges {
|
||||
model.values: Apps.search(search.text)
|
||||
root.delegate: appItem
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "actions"
|
||||
|
||||
PropertyChanges {
|
||||
model.values: Actions.query(search.text)
|
||||
root.delegate: actionItem
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "calc"
|
||||
|
||||
PropertyChanges {
|
||||
model.values: [0]
|
||||
root.delegate: calcItem
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "scheme"
|
||||
|
||||
PropertyChanges {
|
||||
model.values: Schemes.query(search.text)
|
||||
root.delegate: schemeItem
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "variant"
|
||||
|
||||
PropertyChanges {
|
||||
model.values: M3Variants.query(search.text)
|
||||
root.delegate: variantItem
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: Transition {
|
||||
SequentialAnimation {
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
target: root
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.standardAccel
|
||||
}
|
||||
Anim {
|
||||
target: root
|
||||
property: "scale"
|
||||
from: 1
|
||||
to: 0.9
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.standardAccel
|
||||
}
|
||||
}
|
||||
PropertyAction {
|
||||
targets: [model, root]
|
||||
properties: "values,delegate"
|
||||
}
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
target: root
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.standardDecel
|
||||
}
|
||||
Anim {
|
||||
target: root
|
||||
property: "scale"
|
||||
from: 0.9
|
||||
to: 1
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.standardDecel
|
||||
}
|
||||
}
|
||||
PropertyAction {
|
||||
targets: [root.add, root.remove]
|
||||
property: "enabled"
|
||||
value: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledScrollBar.vertical: StyledScrollBar {
|
||||
flickable: root
|
||||
}
|
||||
|
||||
add: Transition {
|
||||
enabled: !root.state
|
||||
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
remove: Transition {
|
||||
enabled: !root.state
|
||||
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
from: 1
|
||||
to: 0
|
||||
}
|
||||
}
|
||||
|
||||
move: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
addDisplaced: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
duration: Appearance.anim.durations.small
|
||||
}
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
displaced: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: appItem
|
||||
|
||||
AppItem {
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: actionItem
|
||||
|
||||
ActionItem {
|
||||
list: root
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: calcItem
|
||||
|
||||
CalcItem {
|
||||
list: root
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: schemeItem
|
||||
|
||||
SchemeItem {
|
||||
list: root
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: variantItem
|
||||
|
||||
VariantItem {
|
||||
list: root
|
||||
}
|
||||
}
|
||||
}
|
||||
60
.config/quickshell/caelestia/modules/launcher/Background.qml
Normal file
60
.config/quickshell/caelestia/modules/launcher/Background.qml
Normal file
@@ -0,0 +1,60 @@
|
||||
import qs.components
|
||||
import qs.services
|
||||
import qs.config
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
|
||||
ShapePath {
|
||||
id: root
|
||||
|
||||
required property Wrapper wrapper
|
||||
readonly property real rounding: Config.border.rounding
|
||||
readonly property bool flatten: wrapper.height < rounding * 2
|
||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||
|
||||
strokeWidth: -1
|
||||
fillColor: Colours.palette.m3surface
|
||||
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
direction: PathArc.Counterclockwise
|
||||
}
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: -(root.wrapper.height - root.roundingY * 2)
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
}
|
||||
PathLine {
|
||||
relativeX: root.wrapper.width - root.rounding * 2
|
||||
relativeY: 0
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
}
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: root.wrapper.height - root.roundingY * 2
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
direction: PathArc.Counterclockwise
|
||||
}
|
||||
|
||||
Behavior on fillColor {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
191
.config/quickshell/caelestia/modules/launcher/Content.qml
Normal file
191
.config/quickshell/caelestia/modules/launcher/Content.qml
Normal file
@@ -0,0 +1,191 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import "services"
|
||||
import qs.components
|
||||
import qs.components.controls
|
||||
import qs.services
|
||||
import qs.config
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property PersistentProperties visibilities
|
||||
required property var panels
|
||||
required property real maxHeight
|
||||
|
||||
readonly property int padding: Appearance.padding.large
|
||||
readonly property int rounding: Appearance.rounding.large
|
||||
|
||||
implicitWidth: listWrapper.width + padding * 2
|
||||
implicitHeight: searchWrapper.height + listWrapper.height + padding * 2
|
||||
|
||||
Item {
|
||||
id: listWrapper
|
||||
|
||||
implicitWidth: list.width
|
||||
implicitHeight: list.height + root.padding
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: searchWrapper.top
|
||||
anchors.bottomMargin: root.padding
|
||||
|
||||
ContentList {
|
||||
id: list
|
||||
|
||||
content: root
|
||||
visibilities: root.visibilities
|
||||
panels: root.panels
|
||||
maxHeight: root.maxHeight - searchWrapper.implicitHeight - root.padding * 3
|
||||
search: search
|
||||
padding: root.padding
|
||||
rounding: root.rounding
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
id: searchWrapper
|
||||
|
||||
color: Colours.layer(Colours.palette.m3surfaceContainer, 2)
|
||||
radius: Appearance.rounding.full
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: root.padding
|
||||
|
||||
implicitHeight: Math.max(searchIcon.implicitHeight, search.implicitHeight, clearIcon.implicitHeight)
|
||||
|
||||
MaterialIcon {
|
||||
id: searchIcon
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.padding
|
||||
|
||||
text: "search"
|
||||
color: Colours.palette.m3onSurfaceVariant
|
||||
}
|
||||
|
||||
StyledTextField {
|
||||
id: search
|
||||
|
||||
anchors.left: searchIcon.right
|
||||
anchors.right: clearIcon.left
|
||||
anchors.leftMargin: Appearance.spacing.small
|
||||
anchors.rightMargin: Appearance.spacing.small
|
||||
|
||||
topPadding: Appearance.padding.larger
|
||||
bottomPadding: Appearance.padding.larger
|
||||
|
||||
placeholderText: qsTr("Type \"%1\" for commands").arg(Config.launcher.actionPrefix)
|
||||
|
||||
onAccepted: {
|
||||
const currentItem = list.currentList?.currentItem;
|
||||
if (currentItem) {
|
||||
if (list.showWallpapers) {
|
||||
if (Colours.scheme === "dynamic" && currentItem.modelData.path !== Wallpapers.actualCurrent)
|
||||
Wallpapers.previewColourLock = true;
|
||||
Wallpapers.setWallpaper(currentItem.modelData.path);
|
||||
root.visibilities.launcher = false;
|
||||
} else if (text.startsWith(Config.launcher.actionPrefix)) {
|
||||
if (text.startsWith(`${Config.launcher.actionPrefix}calc `))
|
||||
currentItem.onClicked();
|
||||
else
|
||||
currentItem.modelData.onClicked(list.currentList);
|
||||
} else {
|
||||
Apps.launch(currentItem.modelData);
|
||||
root.visibilities.launcher = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onUpPressed: list.currentList?.decrementCurrentIndex()
|
||||
Keys.onDownPressed: list.currentList?.incrementCurrentIndex()
|
||||
|
||||
Keys.onEscapePressed: root.visibilities.launcher = false
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (!Config.launcher.vimKeybinds)
|
||||
return;
|
||||
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
if (event.key === Qt.Key_J) {
|
||||
list.currentList?.incrementCurrentIndex();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_K) {
|
||||
list.currentList?.decrementCurrentIndex();
|
||||
event.accepted = true;
|
||||
}
|
||||
} else if (event.key === Qt.Key_Tab) {
|
||||
list.currentList?.incrementCurrentIndex();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier))) {
|
||||
list.currentList?.decrementCurrentIndex();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: forceActiveFocus()
|
||||
|
||||
Connections {
|
||||
target: root.visibilities
|
||||
|
||||
function onLauncherChanged(): void {
|
||||
if (!root.visibilities.launcher)
|
||||
search.text = "";
|
||||
}
|
||||
|
||||
function onSessionChanged(): void {
|
||||
if (!root.visibilities.session)
|
||||
search.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
id: clearIcon
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: root.padding
|
||||
|
||||
width: search.text ? implicitWidth : implicitWidth / 2
|
||||
opacity: {
|
||||
if (!search.text)
|
||||
return 0;
|
||||
if (mouse.pressed)
|
||||
return 0.7;
|
||||
if (mouse.containsMouse)
|
||||
return 0.8;
|
||||
return 1;
|
||||
}
|
||||
|
||||
text: "close"
|
||||
color: Colours.palette.m3onSurfaceVariant
|
||||
|
||||
MouseArea {
|
||||
id: mouse
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: search.text ? Qt.PointingHandCursor : undefined
|
||||
|
||||
onClicked: search.text = ""
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.small
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.small
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
170
.config/quickshell/caelestia/modules/launcher/ContentList.qml
Normal file
170
.config/quickshell/caelestia/modules/launcher/ContentList.qml
Normal file
@@ -0,0 +1,170 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.components
|
||||
import qs.components.controls
|
||||
import qs.services
|
||||
import qs.config
|
||||
import qs.utils
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var content
|
||||
required property PersistentProperties visibilities
|
||||
required property var panels
|
||||
required property real maxHeight
|
||||
required property StyledTextField search
|
||||
required property int padding
|
||||
required property int rounding
|
||||
|
||||
readonly property bool showWallpapers: search.text.startsWith(`${Config.launcher.actionPrefix}wallpaper `)
|
||||
readonly property Item currentList: showWallpapers ? wallpaperList.item : appList.item
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
clip: true
|
||||
state: showWallpapers ? "wallpapers" : "apps"
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "apps"
|
||||
|
||||
PropertyChanges {
|
||||
root.implicitWidth: Config.launcher.sizes.itemWidth
|
||||
root.implicitHeight: Math.min(root.maxHeight, appList.implicitHeight > 0 ? appList.implicitHeight : empty.implicitHeight)
|
||||
appList.active: true
|
||||
}
|
||||
|
||||
AnchorChanges {
|
||||
anchors.left: root.parent.left
|
||||
anchors.right: root.parent.right
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "wallpapers"
|
||||
|
||||
PropertyChanges {
|
||||
root.implicitWidth: Math.max(Config.launcher.sizes.itemWidth * 1.2, wallpaperList.implicitWidth)
|
||||
root.implicitHeight: Config.launcher.sizes.wallpaperHeight
|
||||
wallpaperList.active: true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Behavior on state {
|
||||
SequentialAnimation {
|
||||
Anim {
|
||||
target: root
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
duration: Appearance.anim.durations.small
|
||||
}
|
||||
PropertyAction {}
|
||||
Anim {
|
||||
target: root
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: Appearance.anim.durations.small
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: appList
|
||||
|
||||
active: false
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
sourceComponent: AppList {
|
||||
search: root.search
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: wallpaperList
|
||||
|
||||
active: false
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
sourceComponent: WallpaperList {
|
||||
search: root.search
|
||||
visibilities: root.visibilities
|
||||
panels: root.panels
|
||||
content: root.content
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: empty
|
||||
|
||||
opacity: root.currentList?.count === 0 ? 1 : 0
|
||||
scale: root.currentList?.count === 0 ? 1 : 0.5
|
||||
|
||||
spacing: Appearance.spacing.normal
|
||||
padding: Appearance.padding.large
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MaterialIcon {
|
||||
text: root.state === "wallpapers" ? "wallpaper_slideshow" : "manage_search"
|
||||
color: Colours.palette.m3onSurfaceVariant
|
||||
font.pointSize: Appearance.font.size.extraLarge
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: root.state === "wallpapers" ? qsTr("No wallpapers found") : qsTr("No results")
|
||||
color: Colours.palette.m3onSurfaceVariant
|
||||
font.pointSize: Appearance.font.size.larger
|
||||
font.weight: 500
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.state === "wallpapers" && Wallpapers.list.length === 0 ? qsTr("Try putting some wallpapers in %1").arg(Paths.shortenHome(Paths.wallsdir)) : qsTr("Try searching for something else")
|
||||
color: Colours.palette.m3onSurfaceVariant
|
||||
font.pointSize: Appearance.font.size.normal
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitWidth {
|
||||
enabled: root.visibilities.launcher
|
||||
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.large
|
||||
easing.bezierCurve: Appearance.anim.curves.emphasizedDecel
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitHeight {
|
||||
enabled: root.visibilities.launcher
|
||||
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.large
|
||||
easing.bezierCurve: Appearance.anim.curves.emphasizedDecel
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import "items"
|
||||
import qs.components.controls
|
||||
import qs.services
|
||||
import qs.config
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
PathView {
|
||||
id: root
|
||||
|
||||
required property StyledTextField search
|
||||
required property var visibilities
|
||||
required property var panels
|
||||
required property var content
|
||||
|
||||
readonly property int itemWidth: Config.launcher.sizes.wallpaperWidth * 0.8 + Appearance.padding.larger * 2
|
||||
|
||||
readonly property int numItems: {
|
||||
const screen = QsWindow.window?.screen;
|
||||
if (!screen)
|
||||
return 0;
|
||||
|
||||
// Screen width - 4x outer rounding - 2x max side thickness (cause centered)
|
||||
const barMargins = Math.max(Config.border.thickness, panels.bar.implicitWidth);
|
||||
let outerMargins = 0;
|
||||
if (panels.popouts.hasCurrent && panels.popouts.currentCenter + panels.popouts.nonAnimHeight / 2 > screen.height - content.implicitHeight - Config.border.thickness * 2)
|
||||
outerMargins = panels.popouts.nonAnimWidth;
|
||||
if ((visibilities.utilities || visibilities.sidebar) && panels.utilities.implicitWidth > outerMargins)
|
||||
outerMargins = panels.utilities.implicitWidth;
|
||||
const maxWidth = screen.width - Config.border.rounding * 4 - (barMargins + outerMargins) * 2;
|
||||
|
||||
if (maxWidth <= 0)
|
||||
return 0;
|
||||
|
||||
const maxItemsOnScreen = Math.floor(maxWidth / itemWidth);
|
||||
const visible = Math.min(maxItemsOnScreen, Config.launcher.maxWallpapers, scriptModel.values.length);
|
||||
|
||||
if (visible === 2)
|
||||
return 1;
|
||||
if (visible > 1 && visible % 2 === 0)
|
||||
return visible - 1;
|
||||
return visible;
|
||||
}
|
||||
|
||||
model: ScriptModel {
|
||||
id: scriptModel
|
||||
|
||||
readonly property string search: root.search.text.split(" ").slice(1).join(" ")
|
||||
|
||||
values: Wallpapers.query(search)
|
||||
onValuesChanged: root.currentIndex = search ? 0 : values.findIndex(w => w.path === Wallpapers.actualCurrent)
|
||||
}
|
||||
|
||||
Component.onCompleted: currentIndex = Wallpapers.list.findIndex(w => w.path === Wallpapers.actualCurrent)
|
||||
Component.onDestruction: Wallpapers.stopPreview()
|
||||
|
||||
onCurrentItemChanged: {
|
||||
if (currentItem)
|
||||
Wallpapers.preview(currentItem.modelData.path);
|
||||
}
|
||||
|
||||
implicitWidth: Math.min(numItems, count) * itemWidth
|
||||
pathItemCount: numItems
|
||||
cacheItemCount: 4
|
||||
|
||||
snapMode: PathView.SnapToItem
|
||||
preferredHighlightBegin: 0.5
|
||||
preferredHighlightEnd: 0.5
|
||||
highlightRangeMode: PathView.StrictlyEnforceRange
|
||||
|
||||
delegate: WallpaperItem {
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
|
||||
path: Path {
|
||||
startY: root.height / 2
|
||||
|
||||
PathAttribute {
|
||||
name: "z"
|
||||
value: 0
|
||||
}
|
||||
PathLine {
|
||||
x: root.width / 2
|
||||
relativeY: 0
|
||||
}
|
||||
PathAttribute {
|
||||
name: "z"
|
||||
value: 1
|
||||
}
|
||||
PathLine {
|
||||
x: root.width
|
||||
relativeY: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
130
.config/quickshell/caelestia/modules/launcher/Wrapper.qml
Normal file
130
.config/quickshell/caelestia/modules/launcher/Wrapper.qml
Normal file
@@ -0,0 +1,130 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.components
|
||||
import qs.config
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property ShellScreen screen
|
||||
required property PersistentProperties visibilities
|
||||
required property var panels
|
||||
|
||||
readonly property bool shouldBeActive: visibilities.launcher && Config.launcher.enabled
|
||||
property int contentHeight
|
||||
|
||||
readonly property real maxHeight: {
|
||||
let max = screen.height - Config.border.thickness * 2 - Appearance.spacing.large;
|
||||
if (visibilities.dashboard)
|
||||
max -= panels.dashboard.nonAnimHeight;
|
||||
return max;
|
||||
}
|
||||
|
||||
onMaxHeightChanged: timer.start()
|
||||
|
||||
visible: height > 0
|
||||
implicitHeight: 0
|
||||
implicitWidth: content.implicitWidth
|
||||
|
||||
onShouldBeActiveChanged: {
|
||||
if (shouldBeActive) {
|
||||
timer.stop();
|
||||
hideAnim.stop();
|
||||
showAnim.start();
|
||||
} else {
|
||||
showAnim.stop();
|
||||
hideAnim.start();
|
||||
}
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: showAnim
|
||||
|
||||
Anim {
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
to: root.contentHeight
|
||||
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||
}
|
||||
ScriptAction {
|
||||
script: root.implicitHeight = Qt.binding(() => content.implicitHeight)
|
||||
}
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: hideAnim
|
||||
|
||||
ScriptAction {
|
||||
script: root.implicitHeight = root.implicitHeight
|
||||
}
|
||||
Anim {
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
to: 0
|
||||
easing.bezierCurve: Appearance.anim.curves.emphasized
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Config.launcher
|
||||
|
||||
function onEnabledChanged(): void {
|
||||
timer.start();
|
||||
}
|
||||
|
||||
function onMaxShownChanged(): void {
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DesktopEntries.applications
|
||||
|
||||
function onValuesChanged(): void {
|
||||
if (DesktopEntries.applications.values.length < Config.launcher.maxShown)
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
|
||||
interval: Appearance.anim.durations.extraLarge
|
||||
onRunningChanged: {
|
||||
if (running && !root.shouldBeActive) {
|
||||
content.visible = false;
|
||||
content.active = true;
|
||||
} else {
|
||||
root.contentHeight = Math.min(root.maxHeight, content.implicitHeight);
|
||||
content.active = Qt.binding(() => root.shouldBeActive || root.visible);
|
||||
content.visible = true;
|
||||
if (showAnim.running) {
|
||||
showAnim.stop();
|
||||
showAnim.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
visible: false
|
||||
active: false
|
||||
Component.onCompleted: timer.start()
|
||||
|
||||
sourceComponent: Content {
|
||||
visibilities: root.visibilities
|
||||
panels: root.panels
|
||||
maxHeight: root.maxHeight
|
||||
|
||||
Component.onCompleted: root.contentHeight = implicitHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import "../services"
|
||||
import qs.components
|
||||
import qs.services
|
||||
import qs.config
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var modelData
|
||||
required property var list
|
||||
|
||||
implicitHeight: Config.launcher.sizes.itemHeight
|
||||
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
|
||||
StateLayer {
|
||||
radius: Appearance.rounding.normal
|
||||
|
||||
function onClicked(): void {
|
||||
root.modelData?.onClicked(root.list);
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Appearance.padding.larger
|
||||
anchors.rightMargin: Appearance.padding.larger
|
||||
anchors.margins: Appearance.padding.smaller
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
text: root.modelData?.icon ?? ""
|
||||
font.pointSize: Appearance.font.size.extraLarge
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.left: icon.right
|
||||
anchors.leftMargin: Appearance.spacing.normal
|
||||
anchors.verticalCenter: icon.verticalCenter
|
||||
|
||||
implicitWidth: parent.width - icon.width
|
||||
implicitHeight: name.implicitHeight + desc.implicitHeight
|
||||
|
||||
StyledText {
|
||||
id: name
|
||||
|
||||
text: root.modelData?.name ?? ""
|
||||
font.pointSize: Appearance.font.size.normal
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: desc
|
||||
|
||||
text: root.modelData?.desc ?? ""
|
||||
font.pointSize: Appearance.font.size.small
|
||||
color: Colours.palette.m3outline
|
||||
|
||||
elide: Text.ElideRight
|
||||
width: root.width - icon.width - Appearance.rounding.normal * 2
|
||||
|
||||
anchors.top: name.bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import "../services"
|
||||
import qs.components
|
||||
import qs.services
|
||||
import qs.config
|
||||
import qs.utils
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property DesktopEntry modelData
|
||||
required property PersistentProperties visibilities
|
||||
|
||||
implicitHeight: Config.launcher.sizes.itemHeight
|
||||
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
|
||||
StateLayer {
|
||||
radius: Appearance.rounding.normal
|
||||
|
||||
function onClicked(): void {
|
||||
Apps.launch(root.modelData);
|
||||
root.visibilities.launcher = false;
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Appearance.padding.larger
|
||||
anchors.rightMargin: Appearance.padding.larger
|
||||
anchors.margins: Appearance.padding.smaller
|
||||
|
||||
IconImage {
|
||||
id: icon
|
||||
|
||||
source: Quickshell.iconPath(root.modelData?.icon, "image-missing")
|
||||
implicitSize: parent.height * 0.8
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.left: icon.right
|
||||
anchors.leftMargin: Appearance.spacing.normal
|
||||
anchors.verticalCenter: icon.verticalCenter
|
||||
|
||||
implicitWidth: parent.width - icon.width - favouriteIcon.width
|
||||
implicitHeight: name.implicitHeight + comment.implicitHeight
|
||||
|
||||
StyledText {
|
||||
id: name
|
||||
|
||||
text: root.modelData?.name ?? ""
|
||||
font.pointSize: Appearance.font.size.normal
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: comment
|
||||
|
||||
text: (root.modelData?.comment || root.modelData?.genericName || root.modelData?.name) ?? ""
|
||||
font.pointSize: Appearance.font.size.small
|
||||
color: Colours.palette.m3outline
|
||||
|
||||
elide: Text.ElideRight
|
||||
width: root.width - icon.width - favouriteIcon.width - Appearance.rounding.normal * 2
|
||||
|
||||
anchors.top: name.bottom
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: favouriteIcon
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
active: modelData && Strings.testRegexList(Config.launcher.favouriteApps, modelData.id)
|
||||
|
||||
sourceComponent: MaterialIcon {
|
||||
text: "favorite"
|
||||
fill: 1
|
||||
color: Colours.palette.m3primary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
123
.config/quickshell/caelestia/modules/launcher/items/CalcItem.qml
Normal file
123
.config/quickshell/caelestia/modules/launcher/items/CalcItem.qml
Normal file
@@ -0,0 +1,123 @@
|
||||
import qs.components
|
||||
import qs.services
|
||||
import qs.config
|
||||
import Caelestia
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var list
|
||||
readonly property string math: list.search.text.slice(`${Config.launcher.actionPrefix}calc `.length)
|
||||
|
||||
function onClicked(): void {
|
||||
Quickshell.execDetached(["wl-copy", Qalculator.eval(math, false)]);
|
||||
root.list.visibilities.launcher = false;
|
||||
}
|
||||
|
||||
implicitHeight: Config.launcher.sizes.itemHeight
|
||||
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
|
||||
StateLayer {
|
||||
radius: Appearance.rounding.normal
|
||||
|
||||
function onClicked(): void {
|
||||
root.onClicked();
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.margins: Appearance.padding.larger
|
||||
|
||||
spacing: Appearance.spacing.normal
|
||||
|
||||
MaterialIcon {
|
||||
text: "function"
|
||||
font.pointSize: Appearance.font.size.extraLarge
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: result
|
||||
|
||||
color: {
|
||||
if (text.includes("error: ") || text.includes("warning: "))
|
||||
return Colours.palette.m3error;
|
||||
if (!root.math)
|
||||
return Colours.palette.m3onSurfaceVariant;
|
||||
return Colours.palette.m3onSurface;
|
||||
}
|
||||
|
||||
text: root.math.length > 0 ? Qalculator.eval(root.math) : qsTr("Type an expression to calculate")
|
||||
elide: Text.ElideLeft
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
color: Colours.palette.m3tertiary
|
||||
radius: Appearance.rounding.normal
|
||||
clip: true
|
||||
|
||||
implicitWidth: (stateLayer.containsMouse ? label.implicitWidth + label.anchors.rightMargin : 0) + icon.implicitWidth + Appearance.padding.normal * 2
|
||||
implicitHeight: Math.max(label.implicitHeight, icon.implicitHeight) + Appearance.padding.small * 2
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
StateLayer {
|
||||
id: stateLayer
|
||||
|
||||
color: Colours.palette.m3onTertiary
|
||||
|
||||
function onClicked(): void {
|
||||
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.terminal, "fish", "-C", `exec qalc -i '${root.math}'`]);
|
||||
root.list.visibilities.launcher = false;
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: label
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: icon.left
|
||||
anchors.rightMargin: Appearance.spacing.small
|
||||
|
||||
text: qsTr("Open in calculator")
|
||||
color: Colours.palette.m3onTertiary
|
||||
font.pointSize: Appearance.font.size.normal
|
||||
|
||||
opacity: stateLayer.containsMouse ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Appearance.padding.normal
|
||||
|
||||
text: "open_in_new"
|
||||
color: Colours.palette.m3onTertiary
|
||||
font.pointSize: Appearance.font.size.large
|
||||
}
|
||||
|
||||
Behavior on implicitWidth {
|
||||
Anim {
|
||||
easing.bezierCurve: Appearance.anim.curves.emphasized
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import "../services"
|
||||
import qs.components
|
||||
import qs.services
|
||||
import qs.config
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property Schemes.Scheme modelData
|
||||
required property var list
|
||||
|
||||
implicitHeight: Config.launcher.sizes.itemHeight
|
||||
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
|
||||
StateLayer {
|
||||
radius: Appearance.rounding.normal
|
||||
|
||||
function onClicked(): void {
|
||||
root.modelData?.onClicked(root.list);
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Appearance.padding.larger
|
||||
anchors.rightMargin: Appearance.padding.larger
|
||||
anchors.margins: Appearance.padding.smaller
|
||||
|
||||
StyledRect {
|
||||
id: preview
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
border.width: 1
|
||||
border.color: Qt.alpha(`#${root.modelData?.colours?.outline}`, 0.5)
|
||||
|
||||
color: `#${root.modelData?.colours?.surface}`
|
||||
radius: Appearance.rounding.full
|
||||
implicitWidth: parent.height * 0.8
|
||||
implicitHeight: parent.height * 0.8
|
||||
|
||||
Item {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
|
||||
implicitWidth: parent.implicitWidth / 2
|
||||
clip: true
|
||||
|
||||
StyledRect {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
|
||||
implicitWidth: preview.implicitWidth
|
||||
color: `#${root.modelData?.colours?.primary}`
|
||||
radius: Appearance.rounding.full
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: preview.right
|
||||
anchors.leftMargin: Appearance.spacing.normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
width: parent.width - preview.width - anchors.leftMargin - (current.active ? current.width + Appearance.spacing.normal : 0)
|
||||
spacing: 0
|
||||
|
||||
StyledText {
|
||||
text: root.modelData?.flavour ?? ""
|
||||
font.pointSize: Appearance.font.size.normal
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.modelData?.name ?? ""
|
||||
font.pointSize: Appearance.font.size.small
|
||||
color: Colours.palette.m3outline
|
||||
|
||||
elide: Text.ElideRight
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: current
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
active: `${root.modelData?.name} ${root.modelData?.flavour}` === Schemes.currentScheme
|
||||
|
||||
sourceComponent: MaterialIcon {
|
||||
text: "check"
|
||||
color: Colours.palette.m3onSurfaceVariant
|
||||
font.pointSize: Appearance.font.size.large
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import "../services"
|
||||
import qs.components
|
||||
import qs.services
|
||||
import qs.config
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property M3Variants.Variant modelData
|
||||
required property var list
|
||||
|
||||
implicitHeight: Config.launcher.sizes.itemHeight
|
||||
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
|
||||
StateLayer {
|
||||
radius: Appearance.rounding.normal
|
||||
|
||||
function onClicked(): void {
|
||||
root.modelData?.onClicked(root.list);
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Appearance.padding.larger
|
||||
anchors.rightMargin: Appearance.padding.larger
|
||||
anchors.margins: Appearance.padding.smaller
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
text: root.modelData?.icon ?? ""
|
||||
font.pointSize: Appearance.font.size.extraLarge
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: icon.right
|
||||
anchors.leftMargin: Appearance.spacing.larger
|
||||
anchors.verticalCenter: icon.verticalCenter
|
||||
|
||||
width: parent.width - icon.width - anchors.leftMargin - (current.active ? current.width + Appearance.spacing.normal : 0)
|
||||
spacing: 0
|
||||
|
||||
StyledText {
|
||||
text: root.modelData?.name ?? ""
|
||||
font.pointSize: Appearance.font.size.normal
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.modelData?.description ?? ""
|
||||
font.pointSize: Appearance.font.size.small
|
||||
color: Colours.palette.m3outline
|
||||
|
||||
elide: Text.ElideRight
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: current
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
active: root.modelData?.variant === Schemes.currentVariant
|
||||
|
||||
sourceComponent: MaterialIcon {
|
||||
text: "check"
|
||||
color: Colours.palette.m3onSurfaceVariant
|
||||
font.pointSize: Appearance.font.size.large
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import qs.components
|
||||
import qs.components.effects
|
||||
import qs.components.images
|
||||
import qs.services
|
||||
import qs.config
|
||||
import Caelestia.Models
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property FileSystemEntry modelData
|
||||
required property PersistentProperties visibilities
|
||||
|
||||
scale: 0.5
|
||||
opacity: 0
|
||||
z: PathView.z ?? 0
|
||||
|
||||
Component.onCompleted: {
|
||||
scale = Qt.binding(() => PathView.isCurrentItem ? 1 : PathView.onPath ? 0.8 : 0);
|
||||
opacity = Qt.binding(() => PathView.onPath ? 1 : 0);
|
||||
}
|
||||
|
||||
implicitWidth: image.width + Appearance.padding.larger * 2
|
||||
implicitHeight: image.height + label.height + Appearance.spacing.small / 2 + Appearance.padding.large + Appearance.padding.normal
|
||||
|
||||
StateLayer {
|
||||
radius: Appearance.rounding.normal
|
||||
|
||||
function onClicked(): void {
|
||||
Wallpapers.setWallpaper(root.modelData.path);
|
||||
root.visibilities.launcher = false;
|
||||
}
|
||||
}
|
||||
|
||||
Elevation {
|
||||
anchors.fill: image
|
||||
radius: image.radius
|
||||
opacity: root.PathView.isCurrentItem ? 1 : 0
|
||||
level: 4
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
StyledClippingRect {
|
||||
id: image
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: Appearance.padding.large
|
||||
color: Colours.tPalette.m3surfaceContainer
|
||||
radius: Appearance.rounding.normal
|
||||
|
||||
implicitWidth: Config.launcher.sizes.wallpaperWidth
|
||||
implicitHeight: implicitWidth / 16 * 9
|
||||
|
||||
MaterialIcon {
|
||||
anchors.centerIn: parent
|
||||
text: "image"
|
||||
color: Colours.tPalette.m3outline
|
||||
font.pointSize: Appearance.font.size.extraLarge * 2
|
||||
font.weight: 600
|
||||
}
|
||||
|
||||
CachingImage {
|
||||
path: root.modelData.path
|
||||
smooth: !root.PathView.view.moving
|
||||
cache: true
|
||||
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: label
|
||||
|
||||
anchors.top: image.bottom
|
||||
anchors.topMargin: Appearance.spacing.small / 2
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
width: image.width - Appearance.padding.normal * 2
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
renderType: Text.QtRendering
|
||||
text: root.modelData.relativePath
|
||||
font.pointSize: Appearance.font.size.normal
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
pragma Singleton
|
||||
|
||||
import ".."
|
||||
import qs.services
|
||||
import qs.config
|
||||
import qs.utils
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Searcher {
|
||||
id: root
|
||||
|
||||
function transformSearch(search: string): string {
|
||||
return search.slice(Config.launcher.actionPrefix.length);
|
||||
}
|
||||
|
||||
list: variants.instances
|
||||
useFuzzy: Config.launcher.useFuzzy.actions
|
||||
|
||||
Variants {
|
||||
id: variants
|
||||
|
||||
model: Config.launcher.actions.filter(a => (a.enabled ?? true) && (Config.launcher.enableDangerousActions || !(a.dangerous ?? false)))
|
||||
|
||||
Action {}
|
||||
}
|
||||
|
||||
component Action: QtObject {
|
||||
required property var modelData
|
||||
readonly property string name: modelData.name ?? qsTr("Unnamed")
|
||||
readonly property string desc: modelData.description ?? qsTr("No description")
|
||||
readonly property string icon: modelData.icon ?? "help_outline"
|
||||
readonly property list<string> command: modelData.command ?? []
|
||||
readonly property bool enabled: modelData.enabled ?? true
|
||||
readonly property bool dangerous: modelData.dangerous ?? false
|
||||
|
||||
function onClicked(list: AppList): void {
|
||||
if (command.length === 0)
|
||||
return;
|
||||
|
||||
if (command[0] === "autocomplete" && command.length > 1) {
|
||||
list.search.text = `${Config.launcher.actionPrefix}${command[1]} `;
|
||||
} else if (command[0] === "setMode" && command.length > 1) {
|
||||
list.visibilities.launcher = false;
|
||||
Colours.setMode(command[1]);
|
||||
} else {
|
||||
list.visibilities.launcher = false;
|
||||
Quickshell.execDetached(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
pragma Singleton
|
||||
|
||||
import qs.config
|
||||
import qs.utils
|
||||
import Caelestia
|
||||
import Quickshell
|
||||
|
||||
Searcher {
|
||||
id: root
|
||||
|
||||
function launch(entry: DesktopEntry): void {
|
||||
appDb.incrementFrequency(entry.id);
|
||||
|
||||
if (entry.runInTerminal)
|
||||
Quickshell.execDetached({
|
||||
command: ["app2unit", "--", ...Config.general.apps.terminal, `${Quickshell.shellDir}/assets/wrap_term_launch.sh`, ...entry.command],
|
||||
workingDirectory: entry.workingDirectory
|
||||
});
|
||||
else
|
||||
Quickshell.execDetached({
|
||||
command: ["app2unit", "--", ...entry.command],
|
||||
workingDirectory: entry.workingDirectory
|
||||
});
|
||||
}
|
||||
|
||||
function search(search: string): list<var> {
|
||||
const prefix = Config.launcher.specialPrefix;
|
||||
|
||||
if (search.startsWith(`${prefix}i `)) {
|
||||
keys = ["id", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}c `)) {
|
||||
keys = ["categories", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}d `)) {
|
||||
keys = ["comment", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}e `)) {
|
||||
keys = ["execString", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}w `)) {
|
||||
keys = ["startupClass", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}g `)) {
|
||||
keys = ["genericName", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}k `)) {
|
||||
keys = ["keywords", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else {
|
||||
keys = ["name"];
|
||||
weights = [1];
|
||||
|
||||
if (!search.startsWith(`${prefix}t `))
|
||||
return query(search).map(e => e.entry);
|
||||
}
|
||||
|
||||
const results = query(search.slice(prefix.length + 2)).map(e => e.entry);
|
||||
if (search.startsWith(`${prefix}t `))
|
||||
return results.filter(a => a.runInTerminal);
|
||||
return results;
|
||||
}
|
||||
|
||||
function selector(item: var): string {
|
||||
return keys.map(k => item[k]).join(" ");
|
||||
}
|
||||
|
||||
list: appDb.apps
|
||||
useFuzzy: Config.launcher.useFuzzy.apps
|
||||
|
||||
AppDb {
|
||||
id: appDb
|
||||
|
||||
path: `${Paths.state}/apps.sqlite`
|
||||
// favouriteApps: Config.launcher.favouriteApps
|
||||
entries: DesktopEntries.applications.values.filter(a => !Strings.testRegexList(Config.launcher.hiddenApps, a.id))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
pragma Singleton
|
||||
|
||||
import ".."
|
||||
import qs.config
|
||||
import qs.utils
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Searcher {
|
||||
id: root
|
||||
|
||||
function transformSearch(search: string): string {
|
||||
return search.slice(`${Config.launcher.actionPrefix}variant `.length);
|
||||
}
|
||||
|
||||
list: [
|
||||
Variant {
|
||||
variant: "vibrant"
|
||||
icon: "sentiment_very_dissatisfied"
|
||||
name: qsTr("Vibrant")
|
||||
description: qsTr("A high chroma palette. The primary palette's chroma is at maximum.")
|
||||
},
|
||||
Variant {
|
||||
variant: "tonalspot"
|
||||
icon: "android"
|
||||
name: qsTr("Tonal Spot")
|
||||
description: qsTr("Default for Material theme colours. A pastel palette with a low chroma.")
|
||||
},
|
||||
Variant {
|
||||
variant: "expressive"
|
||||
icon: "compare_arrows"
|
||||
name: qsTr("Expressive")
|
||||
description: qsTr("A medium chroma palette. The primary palette's hue is different from the seed colour, for variety.")
|
||||
},
|
||||
Variant {
|
||||
variant: "fidelity"
|
||||
icon: "compare"
|
||||
name: qsTr("Fidelity")
|
||||
description: qsTr("Matches the seed colour, even if the seed colour is very bright (high chroma).")
|
||||
},
|
||||
Variant {
|
||||
variant: "content"
|
||||
icon: "sentiment_calm"
|
||||
name: qsTr("Content")
|
||||
description: qsTr("Almost identical to fidelity.")
|
||||
},
|
||||
Variant {
|
||||
variant: "fruitsalad"
|
||||
icon: "nutrition"
|
||||
name: qsTr("Fruit Salad")
|
||||
description: qsTr("A playful theme - the seed colour's hue does not appear in the theme.")
|
||||
},
|
||||
Variant {
|
||||
variant: "rainbow"
|
||||
icon: "looks"
|
||||
name: qsTr("Rainbow")
|
||||
description: qsTr("A playful theme - the seed colour's hue does not appear in the theme.")
|
||||
},
|
||||
Variant {
|
||||
variant: "neutral"
|
||||
icon: "contrast"
|
||||
name: qsTr("Neutral")
|
||||
description: qsTr("Close to grayscale, a hint of chroma.")
|
||||
},
|
||||
Variant {
|
||||
variant: "monochrome"
|
||||
icon: "filter_b_and_w"
|
||||
name: qsTr("Monochrome")
|
||||
description: qsTr("All colours are grayscale, no chroma.")
|
||||
}
|
||||
]
|
||||
useFuzzy: Config.launcher.useFuzzy.variants
|
||||
|
||||
component Variant: QtObject {
|
||||
required property string variant
|
||||
required property string icon
|
||||
required property string name
|
||||
required property string description
|
||||
|
||||
function onClicked(list: AppList): void {
|
||||
list.visibilities.launcher = false;
|
||||
Quickshell.execDetached(["caelestia", "scheme", "set", "-v", variant]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
pragma Singleton
|
||||
|
||||
import ".."
|
||||
import qs.config
|
||||
import qs.utils
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
Searcher {
|
||||
id: root
|
||||
|
||||
property string currentScheme
|
||||
property string currentVariant
|
||||
|
||||
function transformSearch(search: string): string {
|
||||
return search.slice(`${Config.launcher.actionPrefix}scheme `.length);
|
||||
}
|
||||
|
||||
function selector(item: var): string {
|
||||
return `${item.name} ${item.flavour}`;
|
||||
}
|
||||
|
||||
function reload(): void {
|
||||
getCurrent.running = true;
|
||||
}
|
||||
|
||||
list: schemes.instances
|
||||
useFuzzy: Config.launcher.useFuzzy.schemes
|
||||
keys: ["name", "flavour"]
|
||||
weights: [0.9, 0.1]
|
||||
|
||||
Variants {
|
||||
id: schemes
|
||||
|
||||
Scheme {}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getSchemes
|
||||
|
||||
running: true
|
||||
command: ["caelestia", "scheme", "list"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const schemeData = JSON.parse(text);
|
||||
const list = Object.entries(schemeData).map(([name, f]) => Object.entries(f).map(([flavour, colours]) => ({
|
||||
name,
|
||||
flavour,
|
||||
colours
|
||||
})));
|
||||
|
||||
const flat = [];
|
||||
for (const s of list)
|
||||
for (const f of s)
|
||||
flat.push(f);
|
||||
|
||||
schemes.model = flat.sort((a, b) => (a.name + a.flavour).localeCompare((b.name + b.flavour)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getCurrent
|
||||
|
||||
running: true
|
||||
command: ["caelestia", "scheme", "get", "-nfv"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const [name, flavour, variant] = text.trim().split("\n");
|
||||
root.currentScheme = `${name} ${flavour}`;
|
||||
root.currentVariant = variant;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component Scheme: QtObject {
|
||||
required property var modelData
|
||||
readonly property string name: modelData.name
|
||||
readonly property string flavour: modelData.flavour
|
||||
readonly property var colours: modelData.colours
|
||||
|
||||
function onClicked(list: AppList): void {
|
||||
list.visibilities.launcher = false;
|
||||
Quickshell.execDetached(["caelestia", "scheme", "set", "-n", name, "-f", flavour]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user