launcher overhaul
This commit is contained in:
@@ -4,6 +4,7 @@ import QtQuick
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import qs.Components
|
||||
import qs.Modules
|
||||
import qs.Modules.Bar
|
||||
@@ -25,7 +26,7 @@ Variants {
|
||||
|
||||
WlrLayershell.namespace: "ZShell-Bar"
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
|
||||
WlrLayershell.keyboardFocus: visibilities.launcher ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
||||
PanelWindow {
|
||||
id: exclusionZone
|
||||
WlrLayershell.namespace: "ZShell-Bar-Exclusion"
|
||||
@@ -78,6 +79,19 @@ Variants {
|
||||
}
|
||||
}
|
||||
|
||||
HyprlandFocusGrab {
|
||||
id: focusGrab
|
||||
|
||||
active: visibilities.launcher || visibilities.sidebar || visibilities.dashboard || visibilities.osd
|
||||
windows: [bar]
|
||||
onCleared: {
|
||||
visibilities.launcher = false;
|
||||
visibilities.sidebar = false;
|
||||
visibilities.dashboard = false;
|
||||
visibilities.osd = false;
|
||||
}
|
||||
}
|
||||
|
||||
CustomShortcut {
|
||||
name: "toggle-nc"
|
||||
|
||||
@@ -93,6 +107,7 @@ Variants {
|
||||
property bool dashboard
|
||||
property bool bar
|
||||
property bool osd
|
||||
property bool launcher
|
||||
|
||||
Component.onCompleted: Visibilities.load(scope.modelData, this)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
import qs.Modules
|
||||
|
||||
TextField {
|
||||
id: root
|
||||
|
||||
color: DynamicColors.palette.m3onSurface
|
||||
placeholderTextColor: DynamicColors.palette.m3outline
|
||||
font.family: Appearance.font.family.sans
|
||||
font.pointSize: Appearance.font.size.smaller
|
||||
renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering
|
||||
cursorVisible: !readOnly
|
||||
|
||||
background: null
|
||||
|
||||
cursorDelegate: CustomRect {
|
||||
id: cursor
|
||||
|
||||
property bool disableBlink
|
||||
|
||||
implicitWidth: 2
|
||||
color: DynamicColors.palette.m3primary
|
||||
radius: Appearance.rounding.normal
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
|
||||
function onCursorPositionChanged(): void {
|
||||
if (root.activeFocus && root.cursorVisible) {
|
||||
cursor.opacity = 1;
|
||||
cursor.disableBlink = true;
|
||||
enableBlink.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: enableBlink
|
||||
|
||||
interval: 100
|
||||
onTriggered: cursor.disableBlink = false
|
||||
}
|
||||
|
||||
Timer {
|
||||
running: root.activeFocus && root.cursorVisible && !cursor.disableBlink
|
||||
repeat: true
|
||||
triggeredOnStart: true
|
||||
interval: 500
|
||||
onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1
|
||||
}
|
||||
|
||||
Binding {
|
||||
when: !root.activeFocus || !root.cursorVisible
|
||||
cursor.opacity: 0
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.small
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
|
||||
Behavior on placeholderTextColor {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import Quickshell.Io
|
||||
|
||||
JsonObject {
|
||||
property bool autoHide: false
|
||||
property int rounding: 8
|
||||
property Popouts popouts: Popouts {}
|
||||
|
||||
property list<var> entries: [
|
||||
|
||||
+23
-1
@@ -101,6 +101,7 @@ Singleton {
|
||||
function serializeBar(): var {
|
||||
return {
|
||||
autoHide: barConfig.autoHide,
|
||||
rounding: barConfig.rounding,
|
||||
popouts: {
|
||||
tray: barConfig.popouts.tray,
|
||||
audio: barConfig.popouts.audio,
|
||||
@@ -132,6 +133,12 @@ Singleton {
|
||||
logo: general.logo,
|
||||
wallpaperPath: general.wallpaperPath,
|
||||
wallust: general.wallust,
|
||||
apps: {
|
||||
terminal: general.apps.terminal,
|
||||
audio: general.apps.audio,
|
||||
playback: general.apps.playback,
|
||||
explorer: general.apps.explorer,
|
||||
},
|
||||
idle: {
|
||||
timouts: general.idle.timeouts
|
||||
}
|
||||
@@ -245,7 +252,22 @@ Singleton {
|
||||
return {
|
||||
maxAppsShown: launcher.maxAppsShown,
|
||||
maxWallpapers: launcher.maxWallpapers,
|
||||
wallpaperPrefix: launcher.wallpaperPrefix
|
||||
actionPrefix: launcher.actionPrefix,
|
||||
specialPrefix: launcher.specialPrefix,
|
||||
useFuzzy: {
|
||||
apps: launcher.useFuzzy.apps,
|
||||
actions: launcher.useFuzzy.actions,
|
||||
schemes: launcher.useFuzzy.schemes,
|
||||
variants: launcher.useFuzzy.variants,
|
||||
wallpapers: launcher.useFuzzy.wallpapers
|
||||
},
|
||||
sizes: {
|
||||
itemWidth: launcher.sizes.itemWidth,
|
||||
itemHeight: launcher.sizes.itemHeight,
|
||||
wallpaperWidth: launcher.sizes.wallpaperWidth,
|
||||
wallpaperHeight: launcher.sizes.wallpaperHeight
|
||||
},
|
||||
actions: launcher.actions
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,16 @@ JsonObject {
|
||||
property string logo: ""
|
||||
property string wallpaperPath: Quickshell.env("HOME") + "/Pictures/Wallpapers"
|
||||
property bool wallust: false
|
||||
property Apps apps: Apps {}
|
||||
property Idle idle: Idle {}
|
||||
|
||||
component Apps: JsonObject {
|
||||
property list<string> terminal: ["foot"]
|
||||
property list<string> audio: ["pavucontrol"]
|
||||
property list<string> playback: ["mpv"]
|
||||
property list<string> explorer: ["thunar"]
|
||||
}
|
||||
|
||||
component Idle: JsonObject {
|
||||
property list<var> timeouts: [
|
||||
{
|
||||
|
||||
+78
-1
@@ -3,5 +3,82 @@ import Quickshell.Io
|
||||
JsonObject {
|
||||
property int maxAppsShown: 10
|
||||
property int maxWallpapers: 7
|
||||
property string wallpaperPrefix: ">"
|
||||
property string actionPrefix: ">"
|
||||
property string specialPrefix: "@"
|
||||
property Sizes sizes: Sizes {}
|
||||
property UseFuzzy useFuzzy: UseFuzzy {}
|
||||
|
||||
component UseFuzzy: JsonObject {
|
||||
property bool apps: false
|
||||
property bool actions: false
|
||||
property bool schemes: false
|
||||
property bool variants: false
|
||||
property bool wallpapers: false
|
||||
}
|
||||
|
||||
component Sizes: JsonObject {
|
||||
property int itemWidth: 600
|
||||
property int itemHeight: 50
|
||||
property int wallpaperWidth: 280
|
||||
property int wallpaperHeight: 200
|
||||
}
|
||||
|
||||
property list<var> actions: [
|
||||
{
|
||||
name: "Calculator",
|
||||
icon: "calculate",
|
||||
description: "Do simple math equations (powered by Qalc)",
|
||||
command: ["autocomplete", "calc"],
|
||||
enabled: true,
|
||||
dangerous: false
|
||||
},
|
||||
{
|
||||
name: "Wallpaper",
|
||||
icon: "image",
|
||||
description: "Change the current wallpaper",
|
||||
command: ["autocomplete", "wallpaper"],
|
||||
enabled: true,
|
||||
dangerous: false
|
||||
},
|
||||
{
|
||||
name: "Shutdown",
|
||||
icon: "power_settings_new",
|
||||
description: "Shutdown the system",
|
||||
command: ["systemctl", "poweroff"],
|
||||
enabled: true,
|
||||
dangerous: true
|
||||
},
|
||||
{
|
||||
name: "Reboot",
|
||||
icon: "cached",
|
||||
description: "Reboot the system",
|
||||
command: ["systemctl", "reboot"],
|
||||
enabled: true,
|
||||
dangerous: true
|
||||
},
|
||||
{
|
||||
name: "Logout",
|
||||
icon: "exit_to_app",
|
||||
description: "Log out of the current session",
|
||||
command: ["loginctl", "terminate-user", ""],
|
||||
enabled: true,
|
||||
dangerous: true
|
||||
},
|
||||
{
|
||||
name: "Lock",
|
||||
icon: "lock",
|
||||
description: "Lock the current session",
|
||||
command: ["loginctl", "lock-session"],
|
||||
enabled: true,
|
||||
dangerous: false
|
||||
},
|
||||
{
|
||||
name: "Sleep",
|
||||
icon: "bedtime",
|
||||
description: "Suspend then hibernate",
|
||||
command: ["systemctl", "suspend-then-hibernate"],
|
||||
enabled: true,
|
||||
dangerous: false
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Modules.Notifications.Sidebar as Sidebar
|
||||
import qs.Modules.Notifications.Sidebar.Utils as Utils
|
||||
import qs.Modules.Dashboard as Dashboard
|
||||
import qs.Modules.Osd as Osd
|
||||
import qs.Modules.Launcher as Launcher
|
||||
|
||||
Shape {
|
||||
id: root
|
||||
@@ -45,6 +46,13 @@ Shape {
|
||||
startY: 0
|
||||
}
|
||||
|
||||
Launcher.Background {
|
||||
wrapper: root.panels.launcher
|
||||
|
||||
startX: ( root.width - wrapper.width ) / 2 - rounding
|
||||
startY: root.height
|
||||
}
|
||||
|
||||
Dashboard.Background {
|
||||
wrapper: root.panels.dashboard
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import qs.Modules.Notifications.Sidebar.Utils as Utils
|
||||
import qs.Modules.Dashboard as Dashboard
|
||||
import qs.Modules.Osd as Osd
|
||||
import qs.Components.Toast as Toasts
|
||||
import qs.Modules.Launcher as Launcher
|
||||
import qs.Config
|
||||
|
||||
Item {
|
||||
@@ -24,6 +25,7 @@ Item {
|
||||
readonly property alias dashboard: dashboard
|
||||
readonly property alias osd: osd
|
||||
readonly property alias toasts: toasts
|
||||
readonly property alias launcher: launcher
|
||||
|
||||
anchors.fill: parent
|
||||
// anchors.margins: 8
|
||||
@@ -75,6 +77,17 @@ Item {
|
||||
anchors.right: parent.right
|
||||
}
|
||||
|
||||
Launcher.Wrapper {
|
||||
id: launcher
|
||||
|
||||
screen: root.screen
|
||||
visibilities: root.visibilities
|
||||
panels: root
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
|
||||
Utils.Wrapper {
|
||||
id: utilities
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import ZShell.Models
|
||||
import qs.Config
|
||||
import qs.Modules
|
||||
import qs.Helpers
|
||||
import qs.Paths
|
||||
|
||||
Searcher {
|
||||
id: root
|
||||
|
||||
property bool showPreview: false
|
||||
readonly property string current: showPreview ? previewPath : actualCurrent
|
||||
property string previewPath
|
||||
property string actualCurrent: WallpaperPath.currentWallpaperPath
|
||||
|
||||
function setWallpaper(path: string): void {
|
||||
actualCurrent = path;
|
||||
WallpaperPath.currentWallpaperPath = path;
|
||||
Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/LockScreenBg.py")} --input_image=${root.actualCurrent} --output_path=${Paths.state}/lockscreen_bg.png`]);
|
||||
}
|
||||
|
||||
function preview(path: string): void {
|
||||
previewPath = path;
|
||||
showPreview = true;
|
||||
}
|
||||
|
||||
function stopPreview(): void {
|
||||
showPreview = false;
|
||||
Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/SchemeColorGen.py")} --path=${root.actualCurrent} --thumbnail=${Paths.cache}/imagecache/thumbnail.jpg --output=${Paths.state}/scheme.json --scheme=${Config.colors.schemeType}`]);
|
||||
}
|
||||
|
||||
list: wallpapers.entries
|
||||
key: "relativePath"
|
||||
useFuzzy: true
|
||||
extraOpts: useFuzzy ? ({}) : ({
|
||||
forward: false
|
||||
})
|
||||
|
||||
FileSystemModel {
|
||||
id: wallpapers
|
||||
|
||||
recursive: true
|
||||
path: Config.general.wallpaperPath
|
||||
filter: FileSystemModel.Images
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
import qs
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property DesktopEntry modelData
|
||||
|
||||
implicitHeight: 48
|
||||
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: event => onClicked(event)
|
||||
function onClicked(): void {
|
||||
Search.launch(root.modelData);
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 8
|
||||
anchors.rightMargin: 8
|
||||
anchors.margins: 4
|
||||
|
||||
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: 8
|
||||
anchors.verticalCenter: icon.verticalCenter
|
||||
|
||||
implicitWidth: parent.width - icon.width
|
||||
implicitHeight: name.implicitHeight + comment.implicitHeight
|
||||
|
||||
Text {
|
||||
id: name
|
||||
|
||||
text: root.modelData?.name || qsTr("Unknown Application")
|
||||
font.pointSize: 12
|
||||
color: mouseArea.containsMouse ? "#ffffff" : "#cccccc"
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
id: comment
|
||||
|
||||
text: ( root.modelData?.comment || root.modelData?.genericName || root.modelData?.name ) ?? ""
|
||||
font.pointSize: 10
|
||||
color: mouseArea.containsMouse ? "#dddddd" : "#888888"
|
||||
|
||||
elide: Text.ElideRight
|
||||
width: root.width - icon.width - 4 * 2
|
||||
|
||||
anchors.top: name.bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Config
|
||||
import qs.Daemons
|
||||
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
values: {
|
||||
const map = new Map();
|
||||
for ( const n of NotifServer.notClosed )
|
||||
map.set( n.appName, null );
|
||||
for ( const n of NotifServer.list )
|
||||
map.set( n.appName, null );
|
||||
return [ ...map.keys() ];
|
||||
}
|
||||
onValuesChanged: {
|
||||
root.flagChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: groupColumn
|
||||
required property string modelData
|
||||
property list<var> notifications: NotifServer.list.filter( n => n.appName === modelData )
|
||||
width: parent.width
|
||||
spacing: 10
|
||||
|
||||
property bool shouldShow: false
|
||||
property bool isExpanded: false
|
||||
property bool collapseAnimRunning: false
|
||||
property color textColor: DynamicColors.palette.m3onSurface
|
||||
|
||||
function closeAll(): void {
|
||||
for ( const n of NotifServer.notClosed.filter( n => n.appName === modelData ))
|
||||
n.close();
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
add: Transition {
|
||||
id: addTrans
|
||||
SequentialAnimation {
|
||||
PauseAnimation {
|
||||
duration: ( addTrans.ViewTransition.index - addTrans.ViewTransition.targetIndexes[ 0 ]) * 30
|
||||
}
|
||||
ParallelAnimation {
|
||||
NumberAnimation {
|
||||
properties: "y";
|
||||
from: addTrans.ViewTransition.destination.y - (height / 2);
|
||||
to: addTrans.ViewTransition.destination.y;
|
||||
duration: 100;
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
properties: "opacity";
|
||||
from: 0;
|
||||
to: 1;
|
||||
duration: 100;
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
properties: "scale";
|
||||
from: 0.7;
|
||||
to: 1.0;
|
||||
duration: 100
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: addTrans.ViewTransition.targetIndexes.length * 30 + 100
|
||||
running: groupColumn.isExpanded
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
groupColumn.shouldShow = true;
|
||||
console.log("ran timer");
|
||||
}
|
||||
}
|
||||
|
||||
move: Transition {
|
||||
id: moveTrans
|
||||
NumberAnimation {
|
||||
properties: "y";
|
||||
duration: 100;
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
properties: "opacity, scale";
|
||||
to: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
width: parent.width
|
||||
height: 30
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.leftMargin: 5
|
||||
text: groupColumn.modelData
|
||||
color: groupColumn.textColor
|
||||
font.pointSize: 14
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: collapseRect
|
||||
|
||||
property color notifyBgColor: DynamicColors.palette.m3primary
|
||||
property color notifyColor: DynamicColors.palette.m3onPrimary
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 30
|
||||
color: !groupColumn.isExpanded ? collapseRect.notifyBgColor : ( collapseArea.containsMouse ? "#15FFFFFF" : "transparent" )
|
||||
radius: groupColumn.isExpanded ? 4 : height / 2
|
||||
visible: true
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: groupColumn.isExpanded ? "\ue944" : groupColumn.notifications.length
|
||||
font.family: groupColumn.isExpanded ? "Material Symbols Rounded" : "Rubik"
|
||||
font.pointSize: 18
|
||||
color: groupColumn.isExpanded ? groupColumn.textColor : collapseRect.notifyColor
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: collapseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
groupColumn.collapseAnimRunning = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NotifGroupRepeater { id: groupRepeater }
|
||||
}
|
||||
}
|
||||
@@ -1,538 +0,0 @@
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Components
|
||||
import qs.Config
|
||||
import qs.Helpers
|
||||
import qs.Effects
|
||||
import qs.Paths
|
||||
|
||||
Scope {
|
||||
id: root
|
||||
|
||||
PanelWindow {
|
||||
id: launcherWindow
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
color: "transparent"
|
||||
visible: false
|
||||
|
||||
WlrLayershell.namespace: "ZShell-Launcher"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||
|
||||
onVisibleChanged: {
|
||||
if ( !visible ) {
|
||||
searchInput.text = "";
|
||||
appListLoader.item.currentIndex = 0;
|
||||
appListLoader.item.positionViewAtBeginning();
|
||||
}
|
||||
}
|
||||
|
||||
CustomShortcut {
|
||||
name: "toggle-launcher"
|
||||
onPressed: {
|
||||
if ( !launcherWindow.visible ) {
|
||||
if ( !openAnim.running ) {
|
||||
openAnim.start();
|
||||
}
|
||||
} else if ( launcherWindow.visible ) {
|
||||
if ( !closeAnim.running ) {
|
||||
closeAnim.start();
|
||||
}
|
||||
}
|
||||
searchInput.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
ShadowRect {
|
||||
id: effects
|
||||
anchors {
|
||||
top: appListRect.top
|
||||
bottom: backgroundRect.bottom
|
||||
left: appListRect.left
|
||||
right: appListRect.right
|
||||
}
|
||||
radius: 8
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: backgroundRect
|
||||
|
||||
property color backgroundColor: DynamicColors.tPalette.m3surface
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
implicitHeight: mainLayout.childrenRect.height + 20
|
||||
implicitWidth: appListRect.implicitWidth
|
||||
x: Math.round(( parent.width - width ) / 2 )
|
||||
color: backgroundColor
|
||||
opacity: 1
|
||||
|
||||
ParallelAnimation {
|
||||
id: openAnim
|
||||
Anim {
|
||||
target: appListRect
|
||||
duration: MaterialEasing.expressiveDefaultSpatialTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveDefaultSpatial
|
||||
property: "implicitHeight"
|
||||
from: 40
|
||||
to: appListContainer.implicitHeight + 20
|
||||
}
|
||||
Anim {
|
||||
target: appListRect
|
||||
duration: 50
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
Anim {
|
||||
target: backgroundRect
|
||||
duration: 50
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
Anim {
|
||||
target: effects
|
||||
duration: 50
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
onStarted: {
|
||||
launcherWindow.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: closeAnim
|
||||
Anim {
|
||||
target: appListRect
|
||||
duration: MaterialEasing.expressiveDefaultSpatialTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveDefaultSpatial
|
||||
property: "implicitHeight"
|
||||
from: appListContainer.implicitHeight
|
||||
to: 0
|
||||
}
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: 120 }
|
||||
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
target: backgroundRect
|
||||
duration: 50
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
}
|
||||
Anim {
|
||||
target: appListRect
|
||||
duration: 50
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
}
|
||||
Anim {
|
||||
target: effects
|
||||
duration: 50
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
onStopped: {
|
||||
launcherWindow.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: mainLayout
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
spacing: 5
|
||||
clip: true
|
||||
|
||||
CustomTextField {
|
||||
id: searchInput
|
||||
implicitHeight: 30
|
||||
implicitWidth: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: appListRect
|
||||
x: Math.round(( parent.width - width ) / 2 )
|
||||
implicitWidth: appListContainer.implicitWidth + 20
|
||||
implicitHeight: appListContainer.implicitHeight + 20
|
||||
anchors.bottom: backgroundRect.top
|
||||
color: backgroundRect.color
|
||||
topRightRadius: 8
|
||||
topLeftRadius: 8
|
||||
clip: true
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveFastSpatialTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveDefaultSpatial
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitWidth {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveFastSpatialTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveDefaultSpatial
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.centerIn: parent
|
||||
id: appListContainer
|
||||
visible: true
|
||||
clip: true
|
||||
property var showWallpapers: searchInput.text.startsWith(">")
|
||||
state: showWallpapers ? "wallpaperpicker" : "apps"
|
||||
states: [
|
||||
State {
|
||||
name: "apps"
|
||||
PropertyChanges {
|
||||
appListLoader.active: true
|
||||
appListContainer.implicitHeight: appListLoader.implicitHeight
|
||||
appListContainer.implicitWidth: 600
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "wallpaperpicker"
|
||||
PropertyChanges {
|
||||
wallpaperPickerLoader.active: true
|
||||
appListContainer.implicitHeight: wallpaperPickerLoader.implicitHeight
|
||||
appListContainer.implicitWidth: wallpaperPickerLoader.implicitWidth
|
||||
}
|
||||
}
|
||||
]
|
||||
Loader {
|
||||
id: wallpaperPickerLoader
|
||||
active: false
|
||||
anchors.fill: parent
|
||||
sourceComponent: PathView {
|
||||
id: wallpaperPickerView
|
||||
anchors.fill: parent
|
||||
model: ScriptModel {
|
||||
id: wallpaperModel
|
||||
readonly property string search: searchInput.text.split(" ").slice(1).join(" ")
|
||||
|
||||
values: SearchWallpapers.query( search )
|
||||
onValuesChanged: wallpaperPickerView.currentIndex = SearchWallpapers.list.findIndex( w => w.path === WallpaperPath.currentWallpaperPath )
|
||||
}
|
||||
|
||||
readonly property int itemWidth: 288 + 10
|
||||
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 margins = 10;
|
||||
const maxWidth = screen.width - margins * 2;
|
||||
|
||||
if ( maxWidth <= 0 )
|
||||
return 0;
|
||||
|
||||
|
||||
const maxItemsOnScreen = Math.floor( maxWidth / itemWidth );
|
||||
const visible = Math.min( maxItemsOnScreen, Config.launcher.maxWallpapers, wallpaperModel.values.length );
|
||||
|
||||
if ( visible === 2 )
|
||||
return 1;
|
||||
if ( visible > 1 && visible % 2 === 0 )
|
||||
return visible - 1;
|
||||
return visible;
|
||||
}
|
||||
|
||||
Component.onCompleted: currentIndex = SearchWallpapers.list.findIndex( w => w.path === WallpaperPath.currentWallpaperPath )
|
||||
Component.onDestruction: SearchWallpapers.stopPreview()
|
||||
|
||||
onCurrentItemChanged: {
|
||||
if ( currentItem )
|
||||
SearchWallpapers.preview( currentItem.modelData.path );
|
||||
Quickshell.execDetached(["python3", Quickshell.shellPath("scripts/SchemeColorGen.py"), `--path=${currentItem.modelData.path}`, `--thumbnail=${Paths.cache}/imagecache/thumbnail.jpg`, `--output=${Paths.state}/scheme.json`, `--scheme=${Config.colors.schemeType}`]);
|
||||
}
|
||||
|
||||
cacheItemCount: 5
|
||||
snapMode: PathView.SnapToItem
|
||||
preferredHighlightBegin: 0.5
|
||||
preferredHighlightEnd: 0.5
|
||||
highlightRangeMode: PathView.StrictlyEnforceRange
|
||||
|
||||
pathItemCount: numItems
|
||||
implicitHeight: 212
|
||||
implicitWidth: Math.min( numItems, count ) * itemWidth
|
||||
|
||||
path: Path {
|
||||
startY: wallpaperPickerView.height / 2
|
||||
|
||||
PathAttribute {
|
||||
name: "z"
|
||||
value: 0
|
||||
}
|
||||
PathLine {
|
||||
x: wallpaperPickerView.width / 2
|
||||
relativeY: 0
|
||||
}
|
||||
PathAttribute {
|
||||
name: "z"
|
||||
value: 1
|
||||
}
|
||||
PathLine {
|
||||
x: wallpaperPickerView.width
|
||||
relativeY: 0
|
||||
}
|
||||
}
|
||||
|
||||
focus: true
|
||||
|
||||
delegate: WallpaperItem { }
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: appListLoader
|
||||
active: false
|
||||
anchors.fill: parent
|
||||
sourceComponent: ListView {
|
||||
id: appListView
|
||||
|
||||
property color highlightColor: DynamicColors.tPalette.m3onSurface
|
||||
|
||||
anchors.fill: parent
|
||||
model: ScriptModel {
|
||||
id: appModel
|
||||
|
||||
onValuesChanged: {
|
||||
appListView.currentIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
verticalLayoutDirection: ListView.BottomToTop
|
||||
implicitHeight: Math.min( count, Config.launcher.maxAppsShown ) * 48
|
||||
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: appListView.height
|
||||
highlightFollowsCurrentItem: false
|
||||
highlightRangeMode: ListView.ApplyRange
|
||||
focus: true
|
||||
highlight: Rectangle {
|
||||
radius: 4
|
||||
color: appListView.highlightColor
|
||||
opacity: 0.20
|
||||
|
||||
y: appListView.currentItem?.y
|
||||
implicitWidth: appListView.width
|
||||
implicitHeight: appListView.currentItem?.implicitHeight ?? 0
|
||||
|
||||
Behavior on y {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property list<var> search: Search.search( searchInput.text )
|
||||
|
||||
state: {
|
||||
const text = searchInput.text
|
||||
if ( search.length === 0 ) {
|
||||
return "noresults"
|
||||
} else {
|
||||
return "apps"
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "apps"
|
||||
PropertyChanges {
|
||||
appModel.values: Search.search(searchInput.text)
|
||||
appListView.delegate: appItem
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "noresults"
|
||||
PropertyChanges {
|
||||
appModel.values: [1]
|
||||
appListView.delegate: noResultsItem
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Component {
|
||||
id: appItem
|
||||
AppItem {
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: noResultsItem
|
||||
Item {
|
||||
width: appListView.width
|
||||
height: 48
|
||||
Text {
|
||||
id: icon
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
property real fill: 0
|
||||
text: "\ue000"
|
||||
color: "#cccccc"
|
||||
renderType: Text.NativeRendering
|
||||
font.pointSize: 28
|
||||
font.family: "Material Symbols Outlined"
|
||||
font.variableAxes: ({
|
||||
FILL: fill.toFixed(1),
|
||||
GRAD: -25,
|
||||
opsz: fontInfo.pixelSize,
|
||||
wght: fontInfo.weight
|
||||
})
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: icon.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "No results found"
|
||||
color: "#cccccc"
|
||||
renderType: Text.NativeRendering
|
||||
|
||||
font.pointSize: 12
|
||||
font.family: "Rubik"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: wallpaperItem
|
||||
WallpaperItem { }
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
SequentialAnimation {
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
target: appListView
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
duration: 200
|
||||
easing.bezierCurve: MaterialEasing.standardAccel
|
||||
}
|
||||
Anim {
|
||||
target: appListView
|
||||
property: "scale"
|
||||
from: 1
|
||||
to: 0.9
|
||||
duration: 200
|
||||
easing.bezierCurve: MaterialEasing.standardAccel
|
||||
}
|
||||
}
|
||||
PropertyAction {
|
||||
targets: [model, appListView]
|
||||
properties: "values,delegate"
|
||||
}
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
target: appListView
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: 200
|
||||
easing.bezierCurve: MaterialEasing.standardDecel
|
||||
}
|
||||
Anim {
|
||||
target: appListView
|
||||
property: "scale"
|
||||
from: 0.9
|
||||
to: 1
|
||||
duration: 200
|
||||
easing.bezierCurve: MaterialEasing.standardDecel
|
||||
}
|
||||
}
|
||||
PropertyAction {
|
||||
targets: [appListView.add, appListView.remove]
|
||||
property: "enabled"
|
||||
value: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add: Transition {
|
||||
enabled: !appListView.state
|
||||
Anim {
|
||||
properties: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
|
||||
Anim {
|
||||
properties: "scale"
|
||||
from: 0.95
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
remove: Transition {
|
||||
enabled: !appListView.state
|
||||
Anim {
|
||||
properties: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
}
|
||||
|
||||
Anim {
|
||||
properties: "scale"
|
||||
from: 1
|
||||
to: 0.95
|
||||
}
|
||||
}
|
||||
|
||||
move: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
addDisplaced: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
duration: 200
|
||||
}
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
displaced: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.Modules.Launcher.Services
|
||||
import qs.Modules.Launcher.Items
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
import qs.Modules as Modules
|
||||
|
||||
CustomListView {
|
||||
id: root
|
||||
|
||||
required property CustomTextField search
|
||||
required property PersistentProperties visibilities
|
||||
|
||||
model: ScriptModel {
|
||||
id: model
|
||||
|
||||
onValuesChanged: root.currentIndex = 0
|
||||
}
|
||||
|
||||
verticalLayoutDirection: ListView.BottomToTop
|
||||
spacing: Appearance.spacing.small
|
||||
orientation: Qt.Vertical
|
||||
implicitHeight: (Config.launcher.sizes.itemHeight + spacing) * Math.min(Config.launcher.maxAppsShown, count) - spacing
|
||||
|
||||
preferredHighlightBegin: 0
|
||||
preferredHighlightEnd: height
|
||||
highlightRangeMode: ListView.ApplyRange
|
||||
|
||||
highlightFollowsCurrentItem: false
|
||||
highlight: CustomRect {
|
||||
radius: 8
|
||||
color: DynamicColors.palette.m3onSurface
|
||||
opacity: 0.08
|
||||
|
||||
y: root.currentItem?.y ?? 0
|
||||
implicitWidth: root.width
|
||||
implicitHeight: root.currentItem?.implicitHeight ?? 0
|
||||
|
||||
Behavior on y {
|
||||
Modules.Anim {
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
transitions: Transition {
|
||||
SequentialAnimation {
|
||||
ParallelAnimation {
|
||||
Modules.Anim {
|
||||
target: root
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
|
||||
}
|
||||
Modules.Anim {
|
||||
target: root
|
||||
property: "scale"
|
||||
from: 1
|
||||
to: 0.9
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
|
||||
}
|
||||
}
|
||||
PropertyAction {
|
||||
targets: [model, root]
|
||||
properties: "values,delegate"
|
||||
}
|
||||
ParallelAnimation {
|
||||
Modules.Anim {
|
||||
target: root
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
|
||||
}
|
||||
Modules.Anim {
|
||||
target: root
|
||||
property: "scale"
|
||||
from: 0.9
|
||||
to: 1
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
|
||||
}
|
||||
}
|
||||
PropertyAction {
|
||||
targets: [root.add, root.remove]
|
||||
property: "enabled"
|
||||
value: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomScrollBar.vertical: CustomScrollBar {
|
||||
flickable: root
|
||||
}
|
||||
|
||||
add: Transition {
|
||||
enabled: !root.state
|
||||
|
||||
Modules.Anim {
|
||||
properties: "opacity,scale"
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
remove: Transition {
|
||||
enabled: !root.state
|
||||
|
||||
Modules.Anim {
|
||||
properties: "opacity,scale"
|
||||
from: 1
|
||||
to: 0
|
||||
}
|
||||
}
|
||||
|
||||
move: Transition {
|
||||
Modules.Anim {
|
||||
property: "y"
|
||||
}
|
||||
Modules.Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
addDisplaced: Transition {
|
||||
Modules.Anim {
|
||||
property: "y"
|
||||
duration: Appearance.anim.durations.small
|
||||
}
|
||||
Modules.Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
displaced: Transition {
|
||||
Modules.Anim {
|
||||
property: "y"
|
||||
}
|
||||
Modules.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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
import qs.Modules as Modules
|
||||
|
||||
ShapePath {
|
||||
id: root
|
||||
|
||||
required property Wrapper wrapper
|
||||
readonly property real rounding: Config.barConfig.rounding
|
||||
readonly property bool flatten: wrapper.height < rounding * 2
|
||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||
|
||||
strokeWidth: -1
|
||||
fillColor: DynamicColors.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 {
|
||||
Modules.CAnim {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.Modules.Launcher.Services
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
import qs.Modules as Modules
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property PersistentProperties visibilities
|
||||
required property var panels
|
||||
required property real maxHeight
|
||||
|
||||
readonly property int padding: Appearance.padding.small
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
id: searchWrapper
|
||||
|
||||
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
|
||||
radius: 8
|
||||
|
||||
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 + 10
|
||||
|
||||
text: "search"
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
}
|
||||
|
||||
CustomTextField {
|
||||
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 (DynamicColors.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?.incrementCurrentIndex()
|
||||
Keys.onDownPressed: list.currentList?.decrementCurrentIndex()
|
||||
|
||||
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 + 10
|
||||
|
||||
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: DynamicColors.palette.m3onSurfaceVariant
|
||||
|
||||
MouseArea {
|
||||
id: mouse
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: search.text ? Qt.PointingHandCursor : undefined
|
||||
|
||||
onClicked: search.text = ""
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
Modules.Anim {
|
||||
duration: Appearance.anim.durations.small
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Modules.Anim {
|
||||
duration: Appearance.anim.durations.small
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.Paths
|
||||
import qs.Modules
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var content
|
||||
required property PersistentProperties visibilities
|
||||
required property var panels
|
||||
required property real maxHeight
|
||||
required property CustomTextField 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: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: Appearance.font.size.extraLarge
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
CustomText {
|
||||
text: root.state === "wallpapers" ? qsTr("No wallpapers found") : qsTr("No results")
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: Appearance.font.size.larger
|
||||
font.weight: 500
|
||||
}
|
||||
|
||||
CustomText {
|
||||
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: DynamicColors.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.small
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitHeight {
|
||||
enabled: root.visibilities.launcher
|
||||
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import QtQuick
|
||||
import qs.Modules.Launcher.Services
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
|
||||
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
|
||||
|
||||
CustomText {
|
||||
id: name
|
||||
|
||||
text: root.modelData?.name ?? ""
|
||||
font.pointSize: Appearance.font.size.normal
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: desc
|
||||
|
||||
text: root.modelData?.desc ?? ""
|
||||
font.pointSize: Appearance.font.size.small
|
||||
color: DynamicColors.palette.m3outline
|
||||
|
||||
elide: Text.ElideRight
|
||||
width: root.width - icon.width - Appearance.rounding.normal * 2
|
||||
|
||||
anchors.top: name.bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
import qs.Modules.Launcher.Services
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
import qs.Modules
|
||||
|
||||
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
|
||||
implicitHeight: name.implicitHeight + comment.implicitHeight
|
||||
|
||||
CustomText {
|
||||
id: name
|
||||
|
||||
text: root.modelData?.name ?? ""
|
||||
font.pointSize: Appearance.font.size.normal
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: comment
|
||||
|
||||
text: (root.modelData?.comment || root.modelData?.genericName || root.modelData?.name) ?? ""
|
||||
font.pointSize: Appearance.font.size.small
|
||||
color: DynamicColors.palette.m3outline
|
||||
|
||||
elide: Text.ElideRight
|
||||
width: root.width - icon.width - Appearance.rounding.normal * 2
|
||||
|
||||
anchors.top: name.bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import ZShell
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Components
|
||||
import qs.Modules
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: result
|
||||
|
||||
color: {
|
||||
if (text.includes("error: ") || text.includes("warning: "))
|
||||
return DynamicColors.palette.m3error;
|
||||
if (!root.math)
|
||||
return DynamicColors.palette.m3onSurfaceVariant;
|
||||
return DynamicColors.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
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
color: DynamicColors.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: DynamicColors.palette.m3onTertiary
|
||||
|
||||
function onClicked(): void {
|
||||
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.terminal, "fish", "-C", `exec qalc -i '${root.math}'`]);
|
||||
root.list.visibilities.launcher = false;
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: label
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: icon.left
|
||||
anchors.rightMargin: Appearance.spacing.small
|
||||
|
||||
text: qsTr("Open in calculator")
|
||||
color: DynamicColors.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: DynamicColors.palette.m3onTertiary
|
||||
font.pointSize: Appearance.font.size.large
|
||||
}
|
||||
|
||||
Behavior on implicitWidth {
|
||||
Anim {
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import ZShell.Models
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
import qs.Modules
|
||||
|
||||
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 {}
|
||||
}
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
id: image
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: Appearance.padding.large
|
||||
color: DynamicColors.tPalette.m3surfaceContainer
|
||||
radius: Appearance.rounding.normal
|
||||
|
||||
implicitWidth: Config.launcher.sizes.wallpaperWidth
|
||||
implicitHeight: implicitWidth / 16 * 9
|
||||
|
||||
MaterialIcon {
|
||||
anchors.centerIn: parent
|
||||
text: "image"
|
||||
color: DynamicColors.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
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
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,51 @@
|
||||
pragma Singleton
|
||||
|
||||
import qs.Modules.Launcher
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
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))
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,26 +2,31 @@ pragma Singleton
|
||||
|
||||
import ZShell
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Config
|
||||
import qs.Helpers
|
||||
import qs.Paths
|
||||
|
||||
Searcher {
|
||||
id: root
|
||||
|
||||
readonly property string home: Quickshell.env("HOME")
|
||||
|
||||
function launch(entry: DesktopEntry): void {
|
||||
appDb.incrementFrequency(entry.id);
|
||||
|
||||
console.log( "Search command:", entry.command );
|
||||
|
||||
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 || Quickshell.env("HOME")
|
||||
workingDirectory: entry.workingDirectory
|
||||
});
|
||||
}
|
||||
|
||||
function search(search: string): list<var> {
|
||||
const prefix = ">";
|
||||
const prefix = Config.launcher.specialPrefix;
|
||||
|
||||
if (search.startsWith(`${prefix}i `)) {
|
||||
keys = ["id", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
@@ -62,12 +67,12 @@ Searcher {
|
||||
}
|
||||
|
||||
list: appDb.apps
|
||||
useFuzzy: true
|
||||
useFuzzy: Config.launcher.useFuzzy.apps
|
||||
|
||||
AppDb {
|
||||
id: appDb
|
||||
|
||||
path: `${root.home}/.local/share/z-cast-qt/apps.sqlite`
|
||||
path: `${Paths.state}/apps.sqlite`
|
||||
entries: DesktopEntries.applications.values
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
import qs.Modules.Launcher.Items
|
||||
|
||||
PathView {
|
||||
id: root
|
||||
|
||||
required property CustomTextField 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 = panels.bar.implicitWidth;
|
||||
let outerMargins = 0;
|
||||
if (panels.popouts.hasCurrent && panels.popouts.currentCenter + panels.popouts.nonAnimHeight / 2 > screen.height - content.implicitHeight)
|
||||
outerMargins = panels.popouts.nonAnimWidth;
|
||||
if ((visibilities.utilities || visibilities.sidebar) && panels.utilities.implicitWidth > outerMargins)
|
||||
outerMargins = panels.utilities.implicitWidth;
|
||||
const maxWidth = screen.width - Config.barConfig.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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.Components
|
||||
import qs.Config
|
||||
import qs.Modules as Modules
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property ShellScreen screen
|
||||
required property PersistentProperties visibilities
|
||||
required property var panels
|
||||
|
||||
readonly property bool shouldBeActive: visibilities.launcher
|
||||
property int contentHeight
|
||||
|
||||
readonly property real maxHeight: {
|
||||
let max = screen.height - 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
|
||||
|
||||
Modules.Anim {
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
to: root.contentHeight
|
||||
duration: Appearance.anim.durations.small
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
|
||||
}
|
||||
ScriptAction {
|
||||
script: root.implicitHeight = Qt.binding(() => content.implicitHeight)
|
||||
}
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: hideAnim
|
||||
|
||||
ScriptAction {
|
||||
script: root.implicitHeight = root.implicitHeight
|
||||
}
|
||||
Modules.Anim {
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
to: 0
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
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.maxAppsShown)
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
|
||||
interval: Appearance.anim.durations.small
|
||||
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,25 @@
|
||||
import ZShell
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
|
||||
Scope {
|
||||
id: root
|
||||
|
||||
property bool launcherInterrupted
|
||||
readonly property bool hasFullscreen: Hypr.focusedWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen === 2) ?? false
|
||||
|
||||
CustomShortcut {
|
||||
name: "toggle-launcher"
|
||||
description: "Toggle launcher"
|
||||
onPressed: root.launcherInterrupted = false
|
||||
onReleased: {
|
||||
if (!root.launcherInterrupted && !root.hasFullscreen) {
|
||||
const visibilities = Visibilities.getForActive();
|
||||
visibilities.launcher = !visibilities.launcher;
|
||||
}
|
||||
root.launcherInterrupted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import QtQuick.Layouts
|
||||
import QtQuick
|
||||
import qs.Components
|
||||
import qs.Config
|
||||
import qs.Daemons
|
||||
import qs.Helpers
|
||||
import qs.Effects
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
color: "transparent"
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
right: true
|
||||
left: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
WlrLayershell.namespace: "ZShell-Notifs"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
|
||||
mask: Region { regions: root.notifRegions }
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
property list<Region> notifRegions: []
|
||||
required property bool centerShown
|
||||
property color textColor: Config.useDynamicColors ? DynamicColors.palette.m3onSurface : "white"
|
||||
property color backgroundColor: Config.useDynamicColors ? DynamicColors.tPalette.m3surface : Config.baseBgColor
|
||||
// visible: Hyprland.monitorFor(screen).focused
|
||||
|
||||
ListView {
|
||||
id: notifListView
|
||||
model: ScriptModel {
|
||||
values: NotifServer.list.filter( n => n.popup )
|
||||
onValuesChanged: {
|
||||
if ( values.length === 0 )
|
||||
root.notifRegions = [];
|
||||
}
|
||||
}
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
x: root.centerShown ? root.screen.width - width - 420 : root.screen.width - width - 20
|
||||
z: 0
|
||||
anchors.topMargin: 54
|
||||
width: 400
|
||||
spacing: 10
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation {
|
||||
property: "y"
|
||||
duration: 100
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
|
||||
remove: Transition {
|
||||
id: hideTransition
|
||||
ParallelAnimation {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
duration: 200
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
property: "x"
|
||||
to: hideTransition.ViewTransition.destination.x + 200
|
||||
duration: 200
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add: Transition {
|
||||
id: showTransition
|
||||
ParallelAnimation {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: 200
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
property: "x"
|
||||
from: showTransition.ViewTransition.destination.x + 200
|
||||
to: showTransition.ViewTransition.destination.x
|
||||
duration: 200
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component NotifRegion: Region { }
|
||||
|
||||
Component {
|
||||
id: notifRegion
|
||||
NotifRegion {}
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: rootItem
|
||||
implicitWidth: 400
|
||||
implicitHeight: contentLayout.childrenRect.height + 16
|
||||
required property NotifServer.Notif modelData
|
||||
|
||||
ShadowRect {
|
||||
anchors.fill: backgroundRect
|
||||
radius: backgroundRect.radius
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
id: backgroundRect
|
||||
implicitWidth: 400
|
||||
implicitHeight: contentLayout.childrenRect.height + 16
|
||||
color: root.backgroundColor
|
||||
border.width: Config.useDynamicColors ? 0 : 1
|
||||
border.color: "#555555"
|
||||
radius: 8
|
||||
|
||||
CustomRect {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
color: DynamicColors.palette.m3primary
|
||||
|
||||
implicitHeight: 4
|
||||
implicitWidth: ( rootItem.modelData.timer.remainingTime / rootItem.modelData.timer.totalTime ) * parent.width
|
||||
|
||||
Behavior on implicitWidth {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.notifRegions.push( notifRegion.createObject(root, { item: backgroundRect }));
|
||||
}
|
||||
|
||||
Column {
|
||||
id: contentLayout
|
||||
z: 0
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.margins: 10
|
||||
spacing: 8
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
IconImage {
|
||||
source: rootItem.modelData.image === "" ? Qt.resolvedUrl(rootItem.modelData.appIcon) : Qt.resolvedUrl(rootItem.modelData.image)
|
||||
Layout.preferredWidth: 48
|
||||
Layout.preferredHeight: 48
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignLeft
|
||||
// visible: rootItem.modelData.image !== ""
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: 0
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
|
||||
Text {
|
||||
text: rootItem.modelData.appName
|
||||
color: root.textColor
|
||||
font.bold: true
|
||||
font.pointSize: 14
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.NoWrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Text {
|
||||
text: rootItem.modelData.summary
|
||||
color: root.textColor
|
||||
font.pointSize: 12
|
||||
font.bold: true
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: rootItem.modelData.body
|
||||
color: root.textColor
|
||||
font.pointSize: 14
|
||||
textFormat: Text.MarkdownText
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.WordWrap
|
||||
maximumLineCount: 4
|
||||
width: parent.width
|
||||
linkColor: Config.accentColor.accents.primaryAlt
|
||||
|
||||
onLinkActivated: link => {
|
||||
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: 6
|
||||
anchors.topMargin: 6
|
||||
width: 18
|
||||
height: 18
|
||||
color: closeArea.containsMouse ? "#FF6077" : "transparent"
|
||||
radius: 9
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
color: closeArea.containsMouse ? "white" : "#888888"
|
||||
font.pointSize: 12
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
rootItem.modelData.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ElapsedTimer {
|
||||
id: timer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import qs.Config
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string source: SearchWallpapers.current
|
||||
property string source: Wallpapers.current
|
||||
property Image current: one
|
||||
|
||||
anchors.fill: parent
|
||||
@@ -50,7 +50,7 @@ Item {
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: 0
|
||||
scale: SearchWallpapers.showPreview ? 1 : 0.8
|
||||
scale: Wallpapers.showPreview ? 1 : 0.8
|
||||
asynchronous: true
|
||||
onStatusChanged: {
|
||||
if (status === Image.Ready) {
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
import ZShell.Models
|
||||
|
||||
Item {
|
||||
id: root
|
||||
required property FileSystemEntry modelData
|
||||
implicitWidth: 288
|
||||
implicitHeight: 162
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ClippingRectangle {
|
||||
anchors.fill: parent
|
||||
radius: 8
|
||||
color: "#10FFFFFF"
|
||||
Image {
|
||||
id: thumbnailImage
|
||||
|
||||
asynchronous: true
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
source: root.modelData.path
|
||||
sourceSize.width: 960
|
||||
sourceSize.height: 540
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Hyprland
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
import qs.Components
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property string currentTitle: Hypr.activeName
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: Math.max( titleText1.implicitWidth, titleText2.implicitWidth ) + 10
|
||||
clip: true
|
||||
|
||||
property bool showFirst: true
|
||||
property color textColor: Config.useDynamicColors ? DynamicColors.palette.m3primary : "white"
|
||||
|
||||
// Component.onCompleted: {
|
||||
// Hyprland.rawEvent.connect(( event ) => {
|
||||
// if (event.name === "activewindow") {
|
||||
// InitialTitle.getInitialTitle( function( initialTitle ) {
|
||||
// root.currentTitle = initialTitle
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
onCurrentTitleChanged: {
|
||||
if (showFirst) {
|
||||
titleText2.text = currentTitle
|
||||
showFirst = false
|
||||
} else {
|
||||
titleText1.text = currentTitle
|
||||
showFirst = true
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: titleText1
|
||||
anchors.fill: parent
|
||||
anchors.margins: 5
|
||||
text: root.currentTitle
|
||||
color: root.textColor
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: 16
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
opacity: root.showFirst ? 1 : 0
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: titleText2
|
||||
anchors.fill: parent
|
||||
anchors.margins: 5
|
||||
color: root.textColor
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: 16
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
opacity: root.showFirst ? 0 : 1
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user