508 lines
19 KiB
QML
508 lines
19 KiB
QML
import QtQuick
|
|
import QtQuick.Layouts
|
|
import QtQuick.Controls
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import Quickshell.Hyprland
|
|
import Quickshell.Services.SystemTray
|
|
import "../theme"
|
|
import ".."
|
|
|
|
PanelWindow {
|
|
id: menuBarWindow
|
|
property var modelData
|
|
screen: modelData
|
|
|
|
anchors {
|
|
top: true
|
|
left: true
|
|
right: true
|
|
}
|
|
|
|
// Set implicitHeight to accommodate bar + open popups without clipping
|
|
implicitHeight: (GlobalState.appleMenuVisible || GlobalState.activeDropdownMenu !== "" ||
|
|
GlobalState.volumePopupVisible || GlobalState.wifiPopupVisible ||
|
|
GlobalState.batteryPopupVisible || GlobalState.calendarPopupVisible) ? 420 : Theme.menuBarHeight
|
|
|
|
color: "transparent"
|
|
WlrLayershell.layer: WlrLayer.Top
|
|
WlrLayershell.namespace: "quickshell-menubar"
|
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
|
|
|
// Set exclusive zone only for the 26px bar
|
|
exclusiveZone: Theme.menuBarHeight
|
|
|
|
// Background Bar (26px)
|
|
Rectangle {
|
|
id: barRect
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
height: Theme.menuBarHeight
|
|
color: Theme.menuBarBg
|
|
border.color: Theme.menuBarBorder
|
|
border.width: 0
|
|
|
|
// Bottom hairline border
|
|
Rectangle {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
height: 1
|
|
color: Theme.menuBarBorder
|
|
}
|
|
|
|
RowLayout {
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 12
|
|
anchors.rightMargin: 12
|
|
spacing: 0
|
|
|
|
// =================================================================
|
|
// LEFT SIDE: Apple Menu + App Title + Standard Menus
|
|
// =================================================================
|
|
RowLayout {
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
|
spacing: 2
|
|
|
|
// Apple Logo Button
|
|
Rectangle {
|
|
id: appleBtn
|
|
width: 28
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: (GlobalState.appleMenuVisible || appleMouse.containsMouse)
|
|
? Qt.rgba(1.0, 1.0, 1.0, 0.18) : "transparent"
|
|
|
|
Image {
|
|
anchors.centerIn: parent
|
|
width: 14
|
|
height: 14
|
|
source: "../assets/apple.svg"
|
|
sourceSize: Qt.size(14, 14)
|
|
}
|
|
|
|
MouseArea {
|
|
id: appleMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
const wasOpen = GlobalState.appleMenuVisible;
|
|
GlobalState.closeAllPopups();
|
|
GlobalState.appleMenuVisible = !wasOpen;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Active App Title (Bold)
|
|
Rectangle {
|
|
id: appTitleBtn
|
|
implicitWidth: appTitleText.implicitWidth + 16
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: titleMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
|
|
|
Text {
|
|
id: appTitleText
|
|
anchors.centerIn: parent
|
|
text: GlobalState.activeWindowClass || "Finder"
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeMenuBar
|
|
font.weight: Font.Bold
|
|
color: Theme.textPrimary
|
|
}
|
|
|
|
MouseArea {
|
|
id: titleMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
const wasOpen = (GlobalState.activeDropdownMenu === "File");
|
|
GlobalState.closeAllPopups();
|
|
GlobalState.activeDropdownMenu = wasOpen ? "" : "File";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Standard Menus: File, Edit, View, Window, Help
|
|
Repeater {
|
|
model: ["File", "Edit", "View", "Window", "Help"]
|
|
delegate: Rectangle {
|
|
id: menuBtn
|
|
implicitWidth: menuText.implicitWidth + 14
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: (GlobalState.activeDropdownMenu === modelData || menuMouse.containsMouse)
|
|
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
|
|
|
Text {
|
|
id: menuText
|
|
anchors.centerIn: parent
|
|
text: modelData
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeMenuBar
|
|
font.weight: Font.Normal
|
|
color: Theme.textPrimary
|
|
}
|
|
|
|
MouseArea {
|
|
id: menuMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onEntered: {
|
|
// If a menu is already open, hovering switches to this one
|
|
if (GlobalState.activeDropdownMenu !== "") {
|
|
GlobalState.activeDropdownMenu = modelData;
|
|
}
|
|
}
|
|
onClicked: {
|
|
const wasOpen = (GlobalState.activeDropdownMenu === modelData);
|
|
GlobalState.closeAllPopups();
|
|
GlobalState.activeDropdownMenu = wasOpen ? "" : modelData;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Spacer
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
// =================================================================
|
|
// RIGHT SIDE: Tray + Media + Volume + Wifi + Battery + Spotlight + Control Center + Clock
|
|
// =================================================================
|
|
RowLayout {
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
|
spacing: 4
|
|
|
|
// System Tray Icons
|
|
Repeater {
|
|
model: SystemTray.items
|
|
delegate: Rectangle {
|
|
required property SystemTrayItem modelData
|
|
width: 22
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: trayMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
|
|
|
Image {
|
|
anchors.centerIn: parent
|
|
width: 15
|
|
height: 15
|
|
source: modelData.icon || ""
|
|
sourceSize: Qt.size(15, 15)
|
|
}
|
|
|
|
MouseArea {
|
|
id: trayMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: modelData.activate()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Media Indicator (visible if playing)
|
|
Rectangle {
|
|
visible: GlobalState.mediaPlaying
|
|
implicitWidth: mediaRow.implicitWidth + 12
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: mediaMouse.containsMouse ? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
|
|
|
RowLayout {
|
|
id: mediaRow
|
|
anchors.centerIn: parent
|
|
spacing: 4
|
|
Image {
|
|
width: 13
|
|
height: 13
|
|
source: "../assets/music.svg"
|
|
sourceSize: Qt.size(13, 13)
|
|
}
|
|
Text {
|
|
text: GlobalState.mediaTitle ? `${GlobalState.mediaTitle.substring(0, 18)}...` : "Playing"
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.textSecondary
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: mediaMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: GlobalState.mediaPlayPause()
|
|
}
|
|
}
|
|
|
|
// Volume Item
|
|
Rectangle {
|
|
id: volBtn
|
|
width: 26
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: (GlobalState.volumePopupVisible || volMouse.containsMouse)
|
|
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
|
|
|
Image {
|
|
anchors.centerIn: parent
|
|
width: 14
|
|
height: 14
|
|
source: "../assets/volume.svg"
|
|
sourceSize: Qt.size(14, 14)
|
|
}
|
|
|
|
MouseArea {
|
|
id: volMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
const wasOpen = GlobalState.volumePopupVisible;
|
|
GlobalState.closeAllPopups();
|
|
GlobalState.volumePopupVisible = !wasOpen;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wi-Fi Item
|
|
Rectangle {
|
|
id: wifiBtn
|
|
width: 26
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: (GlobalState.wifiPopupVisible || wifiMouse.containsMouse)
|
|
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
|
|
|
Image {
|
|
anchors.centerIn: parent
|
|
width: 14
|
|
height: 14
|
|
source: "../assets/wifi.svg"
|
|
sourceSize: Qt.size(14, 14)
|
|
}
|
|
|
|
MouseArea {
|
|
id: wifiMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
const wasOpen = GlobalState.wifiPopupVisible;
|
|
GlobalState.closeAllPopups();
|
|
GlobalState.wifiPopupVisible = !wasOpen;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Battery Item
|
|
Rectangle {
|
|
id: batBtn
|
|
implicitWidth: batRow.implicitWidth + 8
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: (GlobalState.batteryPopupVisible || batMouse.containsMouse)
|
|
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
|
|
|
RowLayout {
|
|
id: batRow
|
|
anchors.centerIn: parent
|
|
spacing: 4
|
|
|
|
Text {
|
|
visible: GlobalState.batteryPresent
|
|
text: `${GlobalState.batteryPercent}%`
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.textPrimary
|
|
}
|
|
|
|
Image {
|
|
width: 18
|
|
height: 12
|
|
source: "../assets/battery.svg"
|
|
sourceSize: Qt.size(18, 12)
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: batMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
const wasOpen = GlobalState.batteryPopupVisible;
|
|
GlobalState.closeAllPopups();
|
|
GlobalState.batteryPopupVisible = !wasOpen;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Spotlight Search Button
|
|
Rectangle {
|
|
id: spotBtn
|
|
width: 26
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: (GlobalState.spotlightVisible || spotMouse.containsMouse)
|
|
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
|
|
|
Image {
|
|
anchors.centerIn: parent
|
|
width: 14
|
|
height: 14
|
|
source: "../assets/spotlight.svg"
|
|
sourceSize: Qt.size(14, 14)
|
|
}
|
|
|
|
MouseArea {
|
|
id: spotMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: GlobalState.toggleSpotlight()
|
|
}
|
|
}
|
|
|
|
// Control Center / Notification Center Toggle Button
|
|
Rectangle {
|
|
id: ccBtn
|
|
width: 26
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: (GlobalState.controlCenterVisible || ccMouse.containsMouse)
|
|
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
|
|
|
Image {
|
|
anchors.centerIn: parent
|
|
width: 14
|
|
height: 14
|
|
source: "../assets/controlcenter.svg"
|
|
sourceSize: Qt.size(14, 14)
|
|
}
|
|
|
|
MouseArea {
|
|
id: ccMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: GlobalState.toggleControlCenter()
|
|
}
|
|
}
|
|
|
|
// Date & Time (Clock)
|
|
Rectangle {
|
|
id: clockBtn
|
|
implicitWidth: clockRow.implicitWidth + 10
|
|
height: 20
|
|
radius: Theme.radiusSmall
|
|
color: (GlobalState.calendarPopupVisible || clockMouse.containsMouse)
|
|
? Qt.rgba(1.0, 1.0, 1.0, 0.15) : "transparent"
|
|
|
|
RowLayout {
|
|
id: clockRow
|
|
anchors.centerIn: parent
|
|
spacing: 6
|
|
|
|
Text {
|
|
text: GlobalState.dateString
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeMenuBar
|
|
color: Theme.textSecondary
|
|
}
|
|
|
|
Text {
|
|
text: GlobalState.timeString
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeMenuBar
|
|
font.weight: Font.Medium
|
|
color: Theme.textPrimary
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: clockMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
const wasOpen = GlobalState.calendarPopupVisible;
|
|
GlobalState.closeAllPopups();
|
|
GlobalState.calendarPopupVisible = !wasOpen;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// DROPDOWNS & POPUPS
|
|
// =========================================================================
|
|
|
|
// 1. Apple Menu Dropdown
|
|
AppleMenu {
|
|
id: appleDropdown
|
|
visible: GlobalState.appleMenuVisible
|
|
x: 8
|
|
y: Theme.menuBarHeight + 2
|
|
}
|
|
|
|
// 2. Application Menus Dropdown (File, Edit, View, Window, Help)
|
|
AppMenuDropdown {
|
|
id: appMenuDropdown
|
|
visible: GlobalState.activeDropdownMenu !== ""
|
|
menuName: GlobalState.activeDropdownMenu
|
|
x: 60
|
|
y: Theme.menuBarHeight + 2
|
|
}
|
|
|
|
// 3. Volume Popup
|
|
VolumePopup {
|
|
id: volumeDropdown
|
|
visible: GlobalState.volumePopupVisible
|
|
anchors.top: barRect.bottom
|
|
anchors.topMargin: 2
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 190
|
|
}
|
|
|
|
// 4. Wi-Fi Popup
|
|
WifiPopup {
|
|
id: wifiDropdown
|
|
visible: GlobalState.wifiPopupVisible
|
|
anchors.top: barRect.bottom
|
|
anchors.topMargin: 2
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 160
|
|
}
|
|
|
|
// 5. Battery Popup
|
|
BatteryPopup {
|
|
id: batteryDropdown
|
|
visible: GlobalState.batteryPopupVisible
|
|
anchors.top: barRect.bottom
|
|
anchors.topMargin: 2
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 110
|
|
}
|
|
|
|
// 6. Calendar Popup
|
|
CalendarPopup {
|
|
id: calDropdown
|
|
visible: GlobalState.calendarPopupVisible
|
|
anchors.top: barRect.bottom
|
|
anchors.topMargin: 2
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 10
|
|
}
|
|
}
|