Merge branch 'weather-bar-feat' of https://github.com/tekeoglan/dots-hyprland into weather-bar-feat

This commit is contained in:
Hasan A. Tekeoğlu
2025-07-01 04:49:29 +03:00
70 changed files with 1466 additions and 656 deletions
+121 -49
View File
@@ -16,13 +16,12 @@ import Quickshell.Services.UPower
Scope {
id: bar
readonly property int barHeight: Appearance.sizes.barHeight
readonly property int osdHideMouseMoveThreshold: 20
property bool showBarBackground: ConfigOptions.bar.showBackground
property bool showBarBackground: Config.options.bar.showBackground
component VerticalBarSeparator: Rectangle {
Layout.topMargin: barHeight / 3
Layout.bottomMargin: barHeight / 3
Layout.topMargin: Appearance.sizes.baseBarHeight / 3
Layout.bottomMargin: Appearance.sizes.baseBarHeight / 3
Layout.fillHeight: true
implicitWidth: 1
color: Appearance.colors.colOutlineVariant
@@ -32,7 +31,7 @@ Scope {
// For each monitor
model: {
const screens = Quickshell.screens;
const list = ConfigOptions.bar.screenList;
const list = Config.options.bar.screenList;
if (!list || list.length === 0)
return screens;
return screens.filter(screen => list.includes(screen.name));
@@ -40,43 +39,78 @@ Scope {
PanelWindow { // Bar window
id: barRoot
required property ShellScreen modelData
screen: modelData
property ShellScreen modelData
property var brightnessMonitor: Brightness.getMonitorForScreen(modelData)
property real useShortenedForm: (Appearance.sizes.barHellaShortenScreenWidthThreshold >= screen.width) ? 2 : (Appearance.sizes.barShortenScreenWidthThreshold >= screen.width) ? 1 : 0
readonly property int centerSideModuleWidth: (useShortenedForm == 2) ? Appearance.sizes.barCenterSideModuleWidthHellaShortened : (useShortenedForm == 1) ? Appearance.sizes.barCenterSideModuleWidthShortened : Appearance.sizes.barCenterSideModuleWidth
WlrLayershell.namespace: "quickshell:bar"
implicitHeight: barHeight + Appearance.rounding.screenRounding
exclusiveZone: showBarBackground ? barHeight : (barHeight - 4)
implicitHeight: Appearance.sizes.barHeight + Appearance.rounding.screenRounding
exclusiveZone: Appearance.sizes.baseBarHeight + (Config.options.bar.cornerStyle === 1 ? Appearance.sizes.hyprlandGapsOut : 0)
mask: Region {
item: barContent
}
color: "transparent"
anchors {
top: !ConfigOptions.bar.bottom
bottom: ConfigOptions.bar.bottom
top: !Config.options.bar.bottom
bottom: Config.options.bar.bottom
left: true
right: true
}
Rectangle { // Bar background
Item { // Bar content region
id: barContent
anchors {
right: parent.right
left: parent.left
top: !ConfigOptions.bar.bottom ? parent.top : undefined
bottom: ConfigOptions.bar.bottom ? parent.bottom : undefined
top: parent.top
bottom: undefined
}
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
height: barHeight
implicitHeight: Appearance.sizes.barHeight
height: Appearance.sizes.barHeight
states: State {
name: "bottom"
when: Config.options.bar.bottom
AnchorChanges {
target: barContent
anchors {
right: parent.right
left: parent.left
top: undefined
bottom: parent.bottom
}
}
}
// Background shadow
Loader {
active: showBarBackground && Config.options.bar.cornerStyle === 1
anchors.fill: barBackground
sourceComponent: StyledRectangularShadow {
anchors.fill: undefined // The loader's anchors act on this, and this should not have any anchor
target: barBackground
}
}
// Background
Rectangle {
id: barBackground
anchors {
fill: parent
margins: Config.options.bar.cornerStyle === 1 ? (Appearance.sizes.hyprlandGapsOut) : 0 // idk why but +1 is needed
}
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
radius: Config.options.bar.cornerStyle === 1 ? Appearance.rounding.windowRounding : 0
}
MouseArea { // Left side | scroll to change brightness
id: barLeftSideMouseArea
anchors.left: parent.left
implicitHeight: barHeight
implicitHeight: Appearance.sizes.baseBarHeight
height: Appearance.sizes.barHeight
width: (barRoot.width - middleSection.width) / 2
property bool hovered: false
property real lastScrollX: 0
@@ -169,7 +203,8 @@ Scope {
anchors.centerIn: parent
width: 19.5
height: 19.5
source: ConfigOptions.bar.topLeftIcon == 'distro' ? SystemInfo.distroIcon : "spark-symbolic"
source: Config.options.bar.topLeftIcon == 'distro' ?
SystemInfo.distroIcon : "spark-symbolic"
}
ColorOverlay {
@@ -193,7 +228,7 @@ Scope {
RowLayout { // Middle section
id: middleSection
anchors.centerIn: parent
spacing: ConfigOptions?.bar.borderless ? 4 : 8
spacing: Config.options?.bar.borderless ? 4 : 8
BarGroup {
id: leftCenterGroup
@@ -211,9 +246,7 @@ Scope {
}
}
VerticalBarSeparator {
visible: ConfigOptions?.bar.borderless
}
VerticalBarSeparator {visible: Config.options?.bar.borderless}
BarGroup {
id: middleCenterGroup
@@ -238,9 +271,7 @@ Scope {
}
}
VerticalBarSeparator {
visible: ConfigOptions?.bar.borderless
}
VerticalBarSeparator {visible: Config.options?.bar.borderless}
MouseArea {
id: rightCenterGroup
@@ -258,13 +289,13 @@ Scope {
anchors.fill: parent
ClockWidget {
showDate: (ConfigOptions.bar.verbose && barRoot.useShortenedForm < 2)
showDate: (Config.options.bar.verbose && barRoot.useShortenedForm < 2)
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
}
UtilButtons {
visible: (ConfigOptions.bar.verbose && barRoot.useShortenedForm === 0)
visible: (Config.options.bar.verbose && barRoot.useShortenedForm === 0)
Layout.alignment: Qt.AlignVCenter
}
@@ -296,8 +327,9 @@ Scope {
id: barRightSideMouseArea
anchors.right: parent.right
implicitHeight: barHeight
width: (barRoot.width - (barLeftSideMouseArea.width + middleSection.width + weatherLoader.width))
implicitHeight: Appearance.sizes.baseBarHeight
height: Appearance.sizes.barHeight
width: (barRoot.width - middleSection.width) / 2
property bool hovered: false
property real lastScrollX: 0
@@ -370,10 +402,14 @@ Scope {
RippleButton { // Right sidebar button
id: rightSidebarButton
Layout.margins: 4
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.rightMargin: Appearance.rounding.screenRounding
Layout.fillHeight: true
Layout.fillWidth: false
implicitWidth: indicatorsRowLayout.implicitWidth + 10 * 2
implicitHeight: indicatorsRowLayout.implicitHeight + 5 * 2
buttonRadius: Appearance.rounding.full
colBackground: barRightSideMouseArea.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1)
colBackgroundHover: Appearance.colors.colLayer1Hover
@@ -463,32 +499,68 @@ Scope {
}
// Round decorators
Item {
Loader {
id: roundDecorators
anchors {
left: parent.left
right: parent.right
// top: barContent.bottom
top: ConfigOptions.bar.bottom ? undefined : barContent.bottom
bottom: ConfigOptions.bar.bottom ? barContent.top : undefined
}
y: Appearance.sizes.barHeight
width: parent.width
height: Appearance.rounding.screenRounding
visible: showBarBackground
active: showBarBackground && Config.options.bar.cornerStyle === 0 // Hug
RoundCorner {
anchors.top: parent.top
anchors.left: parent.left
size: Appearance.rounding.screenRounding
corner: ConfigOptions.bar.bottom ? cornerEnum.bottomLeft : cornerEnum.topLeft
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
opacity: 1.0 - Appearance.transparency
states: State {
name: "bottom"
when: Config.options.bar.bottom
PropertyChanges {
roundDecorators.y: 0
}
}
RoundCorner {
anchors.top: parent.top
anchors.right: parent.right
size: Appearance.rounding.screenRounding
corner: ConfigOptions.bar.bottom ? cornerEnum.bottomRight : cornerEnum.topRight
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
opacity: 1.0 - Appearance.transparency
sourceComponent: Item {
implicitHeight: Appearance.rounding.screenRounding
RoundCorner {
id: leftCorner
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
}
size: Appearance.rounding.screenRounding
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
opacity: 1.0 - Appearance.transparency
corner: RoundCorner.CornerEnum.TopLeft
states: State {
name: "bottom"
when: Config.options.bar.bottom
PropertyChanges {
leftCorner.corner: RoundCorner.CornerEnum.BottomLeft
}
}
}
RoundCorner {
id: rightCorner
anchors {
right: parent.right
top: !Config.options.bar.bottom ? parent.top : undefined
bottom: Config.options.bar.bottom ? parent.bottom : undefined
}
size: Appearance.rounding.screenRounding
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
opacity: 1.0 - Appearance.transparency
corner: RoundCorner.CornerEnum.TopRight
states: State {
name: "bottom"
when: Config.options.bar.bottom
PropertyChanges {
rightCorner.corner: RoundCorner.CornerEnum.BottomRight
}
}
}
}
}
}
+3 -2
View File
@@ -7,7 +7,8 @@ import QtQuick.Layouts
Item {
id: root
property real padding: 5
implicitHeight: 40
implicitHeight: Appearance.sizes.baseBarHeight
height: Appearance.sizes.barHeight
implicitWidth: rowLayout.implicitWidth + padding * 2
default property alias items: rowLayout.children
@@ -18,7 +19,7 @@ Item {
topMargin: 4
bottomMargin: 4
}
color: ConfigOptions?.bar.borderless ? "transparent" : Appearance.colors.colLayer1
color: Config.options?.bar.borderless ? "transparent" : Appearance.colors.colLayer1
radius: Appearance.rounding.small
}
@@ -9,12 +9,12 @@ import Quickshell.Services.UPower
Item {
id: root
property bool borderless: ConfigOptions.bar.borderless
property bool borderless: Config.options.bar.borderless
readonly property var chargeState: Battery.chargeState
readonly property bool isCharging: Battery.isCharging
readonly property bool isPluggedIn: Battery.isPluggedIn
readonly property real percentage: Battery.percentage
readonly property bool isLow: percentage <= ConfigOptions.battery.low / 100
readonly property bool isLow: percentage <= Config.options.battery.low / 100
readonly property color batteryLowBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3error : Appearance.m3colors.m3errorContainer
readonly property color batteryLowOnBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3errorContainer : Appearance.m3colors.m3error
@@ -6,8 +6,8 @@ import QtQuick.Layouts
Item {
id: root
property bool borderless: ConfigOptions.bar.borderless
property bool showDate: ConfigOptions.bar.verbose
property bool borderless: Config.options.bar.borderless
property bool showDate: Config.options.bar.verbose
implicitWidth: rowLayout.implicitWidth
implicitHeight: 32
+2 -2
View File
@@ -11,13 +11,13 @@ import Quickshell.Hyprland
Item {
id: root
property bool borderless: ConfigOptions.bar.borderless
property bool borderless: Config.options.bar.borderless
readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property string cleanedTitle: StringUtils.cleanMusicTitle(activePlayer?.trackTitle) || qsTr("No media")
Layout.fillHeight: true
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
implicitHeight: 40
implicitHeight: Appearance.sizes.barHeight
Timer {
running: activePlayer?.playbackState == MprisPlaybackState.Playing
+3 -3
View File
@@ -9,7 +9,7 @@ import Quickshell.Services.Mpris
Item {
id: root
property bool borderless: ConfigOptions.bar.borderless
property bool borderless: Config.options.bar.borderless
property bool alwaysShowAllResources: false
implicitWidth: rowLayout.implicitWidth + rowLayout.anchors.leftMargin + rowLayout.anchors.rightMargin
implicitHeight: 32
@@ -30,7 +30,7 @@ Item {
Resource {
iconName: "swap_horiz"
percentage: ResourceUsage.swapUsedPercentage
shown: (ConfigOptions.bar.resources.alwaysShowSwap && percentage > 0) ||
shown: (Config.options.bar.resources.alwaysShowSwap && percentage > 0) ||
(MprisController.activePlayer?.trackTitle == null) ||
root.alwaysShowAllResources
Layout.leftMargin: shown ? 4 : 0
@@ -39,7 +39,7 @@ Item {
Resource {
iconName: "settings_slow_motion"
percentage: ResourceUsage.cpuUsage
shown: ConfigOptions.bar.resources.alwaysShowCpu ||
shown: Config.options.bar.resources.alwaysShowCpu ||
!(MprisController.activePlayer?.trackTitle?.length > 0) ||
root.alwaysShowAllResources
Layout.leftMargin: shown ? 4 : 0
@@ -43,7 +43,7 @@ MouseArea {
IconImage {
id: trayIcon
visible: !ConfigOptions.bar.tray.monochromeIcons
visible: !Config.options.bar.tray.monochromeIcons
source: root.item.icon
anchors.centerIn: parent
width: parent.width
@@ -51,7 +51,7 @@ MouseArea {
}
Loader {
active: ConfigOptions.bar.tray.monochromeIcons
active: Config.options.bar.tray.monochromeIcons
anchors.fill: trayIcon
sourceComponent: Item {
Desaturate {
+11 -11
View File
@@ -9,7 +9,7 @@ import Quickshell.Services.Pipewire
Item {
id: root
property bool borderless: ConfigOptions.bar.borderless
property bool borderless: Config.options.bar.borderless
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
implicitHeight: rowLayout.implicitHeight
@@ -20,8 +20,8 @@ Item {
anchors.centerIn: parent
Loader {
active: ConfigOptions.bar.utilButtons.showScreenSnip
visible: ConfigOptions.bar.utilButtons.showScreenSnip
active: Config.options.bar.utilButtons.showScreenSnip
visible: Config.options.bar.utilButtons.showScreenSnip
sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter
onClicked: Hyprland.dispatch("exec hyprshot --freeze --clipboard-only --mode region --silent")
@@ -36,8 +36,8 @@ Item {
}
Loader {
active: ConfigOptions.bar.utilButtons.showColorPicker
visible: ConfigOptions.bar.utilButtons.showColorPicker
active: Config.options.bar.utilButtons.showColorPicker
visible: Config.options.bar.utilButtons.showColorPicker
sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter
onClicked: Hyprland.dispatch("exec hyprpicker -a")
@@ -52,8 +52,8 @@ Item {
}
Loader {
active: ConfigOptions.bar.utilButtons.showKeyboardToggle
visible: ConfigOptions.bar.utilButtons.showKeyboardToggle
active: Config.options.bar.utilButtons.showKeyboardToggle
visible: Config.options.bar.utilButtons.showKeyboardToggle
sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter
onClicked: Hyprland.dispatch("global quickshell:oskToggle")
@@ -68,8 +68,8 @@ Item {
}
Loader {
active: ConfigOptions.bar.utilButtons.showMicToggle
visible: ConfigOptions.bar.utilButtons.showMicToggle
active: Config.options.bar.utilButtons.showMicToggle
visible: Config.options.bar.utilButtons.showMicToggle
sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter
onClicked: Hyprland.dispatch("exec wpctl set-mute @DEFAULT_SOURCE@ toggle")
@@ -84,8 +84,8 @@ Item {
}
Loader {
active: ConfigOptions.bar.utilButtons.showDarkModeToggle
visible: ConfigOptions.bar.utilButtons.showDarkModeToggle
active: Config.options.bar.utilButtons.showDarkModeToggle
visible: Config.options.bar.utilButtons.showDarkModeToggle
sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter
onClicked: event => {
+20 -20
View File
@@ -15,11 +15,11 @@ import Qt5Compat.GraphicalEffects
Item {
required property var bar
property bool borderless: ConfigOptions.bar.borderless
property bool borderless: Config.options.bar.borderless
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / ConfigOptions.bar.workspaces.shown)
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / Config.options.bar.workspaces.shown)
property list<bool> workspaceOccupied: []
property int widgetPadding: 4
property int workspaceButtonWidth: 26
@@ -27,12 +27,12 @@ Item {
property real workspaceIconSizeShrinked: workspaceButtonWidth * 0.55
property real workspaceIconOpacityShrinked: 1
property real workspaceIconMarginShrinked: -4
property int workspaceIndexInGroup: (monitor.activeWorkspace?.id - 1) % ConfigOptions.bar.workspaces.shown
property int workspaceIndexInGroup: (monitor.activeWorkspace?.id - 1) % Config.options.bar.workspaces.shown
// Function to update workspaceOccupied
function updateWorkspaceOccupied() {
workspaceOccupied = Array.from({ length: ConfigOptions.bar.workspaces.shown }, (_, i) => {
return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * ConfigOptions.bar.workspaces.shown + i + 1);
workspaceOccupied = Array.from({ length: Config.options.bar.workspaces.shown }, (_, i) => {
return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * Config.options.bar.workspaces.shown + i + 1);
})
}
@@ -48,7 +48,7 @@ Item {
}
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
implicitHeight: 40
implicitHeight: Appearance.sizes.barHeight
// Scroll to switch workspaces
WheelHandler {
@@ -78,10 +78,10 @@ Item {
spacing: 0
anchors.fill: parent
implicitHeight: 40
implicitHeight: Appearance.sizes.barHeight
Repeater {
model: ConfigOptions.bar.workspaces.shown
model: Config.options.bar.workspaces.shown
Rectangle {
z: 1
@@ -157,14 +157,14 @@ Item {
spacing: 0
anchors.fill: parent
implicitHeight: 40
implicitHeight: Appearance.sizes.barHeight
Repeater {
model: ConfigOptions.bar.workspaces.shown
model: Config.options.bar.workspaces.shown
Button {
id: button
property int workspaceValue: workspaceGroup * ConfigOptions.bar.workspaces.shown + index + 1
property int workspaceValue: workspaceGroup * Config.options.bar.workspaces.shown + index + 1
Layout.fillHeight: true
onPressed: Hyprland.dispatch(`workspace ${workspaceValue}`)
width: workspaceButtonWidth
@@ -185,8 +185,8 @@ Item {
StyledText { // Workspace number text
opacity: GlobalStates.workspaceShowNumbers
|| ((ConfigOptions?.bar.workspaces.alwaysShowNumbers && (!ConfigOptions?.bar.workspaces.showAppIcons || !workspaceButtonBackground.biggestWindow || GlobalStates.workspaceShowNumbers))
|| (GlobalStates.workspaceShowNumbers && !ConfigOptions?.bar.workspaces.showAppIcons)
|| ((Config.options?.bar.workspaces.alwaysShowNumbers && (!Config.options?.bar.workspaces.showAppIcons || !workspaceButtonBackground.biggestWindow || GlobalStates.workspaceShowNumbers))
|| (GlobalStates.workspaceShowNumbers && !Config.options?.bar.workspaces.showAppIcons)
) ? 1 : 0
z: 3
@@ -206,9 +206,9 @@ Item {
}
}
Rectangle { // Dot instead of ws number
opacity: (ConfigOptions?.bar.workspaces.alwaysShowNumbers
opacity: (Config.options?.bar.workspaces.alwaysShowNumbers
|| GlobalStates.workspaceShowNumbers
|| (ConfigOptions?.bar.workspaces.showAppIcons && workspaceButtonBackground.biggestWindow)
|| (Config.options?.bar.workspaces.showAppIcons && workspaceButtonBackground.biggestWindow)
) ? 0 : 1
visible: opacity > 0
anchors.centerIn: parent
@@ -228,21 +228,21 @@ Item {
anchors.centerIn: parent
width: workspaceButtonWidth
height: workspaceButtonWidth
opacity: !ConfigOptions?.bar.workspaces.showAppIcons ? 0 :
(workspaceButtonBackground.biggestWindow && !GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ?
opacity: !Config.options?.bar.workspaces.showAppIcons ? 0 :
(workspaceButtonBackground.biggestWindow && !GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ?
1 : workspaceButtonBackground.biggestWindow ? workspaceIconOpacityShrinked : 0
visible: opacity > 0
IconImage {
id: mainAppIcon
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.bottomMargin: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ?
anchors.bottomMargin: (!GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ?
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
anchors.rightMargin: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ?
anchors.rightMargin: (!GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ?
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
source: workspaceButtonBackground.mainAppIconSource
implicitSize: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ? workspaceIconSize : workspaceIconSizeShrinked
implicitSize: (!GlobalStates.workspaceShowNumbers && Config.options?.bar.workspaces.showAppIcons) ? workspaceIconSize : workspaceIconSizeShrinked
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)