Files
NixOS-Configs/home/hypr/quickshell/components/MenuBar.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
}
}