Files
quickdots/widgets/sidebar/Sidebar.qml

214 lines
6.0 KiB
QML

import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
import "../../config" as Cfg
import "sysinfo"
import "mpris"
import "weather"
PanelWindow {
id: root
required property var modelData
screen: modelData
color: "transparent"
visible: false
anchors { top: true; bottom: true; left: true; right: true }
WlrLayershell.layer: WlrLayer.Top
WlrLayershell.namespace: "main-shell-sidebar"
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: _open ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
Region { id: noMask }
mask: _open ? null : noMask
readonly property var t: Cfg.Config.theme
readonly property bool isTop: Cfg.Config.barPosition === "top"
readonly property int barEdgePad: Cfg.Config.frameVariant === "bar" ? (isTop ? Cfg.Config.frameBarPadTop : Cfg.Config.frameBarPadBottom) : 0
readonly property int frameTop: isTop ? Cfg.Config.barHeight + barEdgePad : Cfg.Config.margin
readonly property int frameBot: isTop ? Cfg.Config.margin : Cfg.Config.barHeight + barEdgePad
readonly property int inset: Cfg.Config.margin + Cfg.Config.frameBorderWidth + 8
readonly property int sbWidth: 260
readonly property bool isLeft: Cfg.Config.sideBarPosition === "left"
readonly property int slideDist: root.sbWidth + 20
readonly property int slideFrom: isLeft ? -slideDist : slideDist
readonly property int panelX: isLeft ? root.inset : (width - root.sbWidth - root.inset)
property bool _open: false
readonly property bool isOpen: _open
GlobalShortcut {
name: "sidebar"
onPressed: root.toggle()
}
function open() {
var fm = Hyprland.focusedMonitor
if (!fm || fm.name !== screen.name) return
visible = true
_open = true
enterAnim.stop()
exitAnim.stop()
hideTimer.stop()
enterAnim.start()
}
function close() {
_open = false
enterAnim.stop()
exitAnim.start()
}
function toggle() {
if (!_open) {
var fm = Hyprland.focusedMonitor
if (!fm || fm.name !== screen.name) return
}
_open ? close() : open()
}
Timer {
id: hideTimer
interval: 280
onTriggered: visible = false
}
Connections {
target: root
function onActiveChanged() {
if (!root.active && root._open) root.close()
}
}
MouseArea {
anchors.fill: parent
onClicked: root.close()
}
Rectangle {
id: sidebarPanel
transform: Translate { id: panelSlide; x: root.slideFrom }
x: root.panelX
y: root.frameTop + Cfg.Config.frameBorderWidth
width: root.sbWidth
height: parent.height - root.frameTop - root.frameBot - Cfg.Config.frameBorderWidth * 2
radius: Cfg.Config.popupRadius
color: "transparent"
opacity: 0
clip: true
Item {
id: widgetArea
anchors {
fill: parent
topMargin: 10
bottomMargin: 10
leftMargin: 10
rightMargin: 10
}
Flickable {
id: flick
anchors.fill: parent
contentWidth: width
contentHeight: widgetCol.implicitHeight
boundsBehavior: Flickable.StopAtBounds
clip: true
flickDeceleration: 2000
ScrollBar.vertical: ScrollBar {
policy: ScrollBar.AsNeeded
width: 4
contentItem: Rectangle {
radius: 2
color: Qt.alpha(root.t.accent, 0.3)
}
}
Column {
id: widgetCol
anchors { left: parent.left; right: parent.right }
spacing: 10
Loader {
active: Cfg.Config.sideBarSysInfo
sourceComponent: sysInfoComp
anchors { left: parent.left; right: parent.right }
}
Loader {
active: Cfg.Config.sideBarMpris
sourceComponent: mprisComp
anchors { left: parent.left; right: parent.right }
}
Loader {
active: Cfg.Config.sideBarWeather
sourceComponent: weatherComp
anchors { left: parent.left; right: parent.right }
}
}
}
}
}
Component {
id: sysInfoComp
WidgetCard {
SysInfo {
anchors { left: parent.left; right: parent.right }
}
}
}
Component {
id: mprisComp
WidgetCard {
MprisWidget {
anchors { left: parent.left; right: parent.right }
}
}
}
Component {
id: weatherComp
WidgetCard {
WeatherWidget {
anchors { left: parent.left; right: parent.right }
}
}
}
ParallelAnimation {
id: enterAnim
NumberAnimation {
target: panelSlide; property: "x"
to: 0; duration: 320; easing.type: Easing.OutCubic
}
NumberAnimation {
target: sidebarPanel; property: "opacity"
to: 1; duration: 280; easing.type: Easing.OutCubic
}
}
ParallelAnimation {
id: exitAnim
onStopped: hideTimer.restart()
NumberAnimation {
target: panelSlide; property: "x"
to: root.slideFrom; duration: 250; easing.type: Easing.InCubic
}
NumberAnimation {
target: sidebarPanel; property: "opacity"
to: 0; duration: 200; easing.type: Easing.InBack
}
}
}