feat: fullscreen notification & toasts overlay (#1276)
* reworked fullscreen mode as transforming shell * controlcenter configuring of toasts & notifs * fix animation on fs switch * border rounding & shadow animation * change controlcenter notifications layout * stay on WlrLayer.Overlay, use Anim * ci: update action versions * qmlformat * format take two * third time's the charm * fix: special workspace fullscreen * fix: bar width border.thickness on non-persistent behaviour * merge fix * stop layout shift on close * last few conventions sorted * linting * maximized state to fullscreen --------- Co-authored-by: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>
This commit is contained in:
parent
b5f761666d
commit
c588794b20
24 changed files with 582 additions and 35 deletions
|
|
@ -55,6 +55,7 @@ Elevation {
|
||||||
function onClicked(): void {
|
function onClicked(): void {
|
||||||
root.itemSelected(item.modelData);
|
root.itemSelected(item.modelData);
|
||||||
root.active = item.modelData;
|
root.active = item.modelData;
|
||||||
|
item.modelData.clicked();
|
||||||
root.expanded = false;
|
root.expanded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -267,11 +267,13 @@ Singleton {
|
||||||
function serializeNotifs(): var {
|
function serializeNotifs(): var {
|
||||||
return {
|
return {
|
||||||
expire: notifs.expire,
|
expire: notifs.expire,
|
||||||
|
fullscreen: notifs.fullscreen,
|
||||||
defaultExpireTimeout: notifs.defaultExpireTimeout,
|
defaultExpireTimeout: notifs.defaultExpireTimeout,
|
||||||
clearThreshold: notifs.clearThreshold,
|
clearThreshold: notifs.clearThreshold,
|
||||||
expandThreshold: notifs.expandThreshold,
|
expandThreshold: notifs.expandThreshold,
|
||||||
actionOnClick: notifs.actionOnClick,
|
actionOnClick: notifs.actionOnClick,
|
||||||
groupPreviewNum: notifs.groupPreviewNum
|
groupPreviewNum: notifs.groupPreviewNum,
|
||||||
|
openExpanded: notifs.openExpanded
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -323,6 +325,7 @@ Singleton {
|
||||||
maxToasts: utilities.maxToasts,
|
maxToasts: utilities.maxToasts,
|
||||||
toasts: {
|
toasts: {
|
||||||
configLoaded: utilities.toasts.configLoaded,
|
configLoaded: utilities.toasts.configLoaded,
|
||||||
|
fullscreen: utilities.toasts.fullscreen,
|
||||||
chargingChanged: utilities.toasts.chargingChanged,
|
chargingChanged: utilities.toasts.chargingChanged,
|
||||||
gameModeChanged: utilities.toasts.gameModeChanged,
|
gameModeChanged: utilities.toasts.gameModeChanged,
|
||||||
dndChanged: utilities.toasts.dndChanged,
|
dndChanged: utilities.toasts.dndChanged,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import Quickshell.Io
|
||||||
|
|
||||||
JsonObject {
|
JsonObject {
|
||||||
property bool expire: true
|
property bool expire: true
|
||||||
|
property string fullscreen: "on"
|
||||||
property int defaultExpireTimeout: 5000
|
property int defaultExpireTimeout: 5000
|
||||||
property real clearThreshold: 0.3
|
property real clearThreshold: 0.3
|
||||||
property int expandThreshold: 20
|
property int expandThreshold: 20
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ JsonObject {
|
||||||
|
|
||||||
component Toasts: JsonObject {
|
component Toasts: JsonObject {
|
||||||
property bool configLoaded: true
|
property bool configLoaded: true
|
||||||
|
property string fullscreen: "off"
|
||||||
property bool chargingChanged: true
|
property bool chargingChanged: true
|
||||||
property bool gameModeChanged: true
|
property bool gameModeChanged: true
|
||||||
property bool dndChanged: true
|
property bool dndChanged: true
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ Scope {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool launcherInterrupted
|
property bool launcherInterrupted
|
||||||
readonly property bool hasFullscreen: Hypr.focusedWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen === 2) ?? false
|
readonly property bool hasFullscreen: Hypr.focusedWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1) ?? false
|
||||||
|
|
||||||
// qmllint disable unresolved-type
|
// qmllint disable unresolved-type
|
||||||
CustomShortcut {
|
CustomShortcut {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ ColumnLayout {
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
required property DrawerVisibilities visibilities
|
required property DrawerVisibilities visibilities
|
||||||
required property BarPopouts.Wrapper popouts
|
required property BarPopouts.Wrapper popouts
|
||||||
|
required property bool fullscreen
|
||||||
readonly property int vPadding: Appearance.padding.large
|
readonly property int vPadding: Appearance.padding.large
|
||||||
|
|
||||||
function closeTray(): void {
|
function closeTray(): void {
|
||||||
|
|
@ -128,6 +129,7 @@ ColumnLayout {
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
sourceComponent: Workspaces {
|
sourceComponent: Workspaces {
|
||||||
screen: root.screen
|
screen: root.screen
|
||||||
|
fullscreen: root.fullscreen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -135,6 +137,7 @@ ColumnLayout {
|
||||||
roleValue: "activeWindow"
|
roleValue: "activeWindow"
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
visible: !root.fullscreen
|
||||||
sourceComponent: ActiveWindow {
|
sourceComponent: ActiveWindow {
|
||||||
bar: root
|
bar: root
|
||||||
monitor: Brightness.getMonitorForScreen(root.screen)
|
monitor: Brightness.getMonitorForScreen(root.screen)
|
||||||
|
|
@ -144,18 +147,21 @@ ColumnLayout {
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: "tray"
|
roleValue: "tray"
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
|
visible: !root.fullscreen
|
||||||
sourceComponent: Tray {}
|
sourceComponent: Tray {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: "clock"
|
roleValue: "clock"
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
|
visible: !root.fullscreen
|
||||||
sourceComponent: Clock {}
|
sourceComponent: Clock {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: "statusIcons"
|
roleValue: "statusIcons"
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
|
visible: !root.fullscreen
|
||||||
sourceComponent: StatusIcons {}
|
sourceComponent: StatusIcons {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,13 @@ Item {
|
||||||
required property DrawerVisibilities visibilities
|
required property DrawerVisibilities visibilities
|
||||||
required property BarPopouts.Wrapper popouts
|
required property BarPopouts.Wrapper popouts
|
||||||
required property bool disabled
|
required property bool disabled
|
||||||
|
required property bool fullscreen
|
||||||
|
|
||||||
readonly property int clampedWidth: Math.max(Config.border.minThickness, implicitWidth)
|
readonly property int clampedWidth: Math.max(Config.border.minThickness, implicitWidth)
|
||||||
readonly property int padding: Math.max(Appearance.padding.smaller, Config.border.thickness)
|
readonly property int padding: Math.max(Appearance.padding.smaller, Config.border.thickness)
|
||||||
readonly property int contentWidth: Config.bar.sizes.innerWidth + padding * 2
|
readonly property int contentWidth: Config.bar.sizes.innerWidth + padding * 2
|
||||||
readonly property int exclusiveZone: !disabled && (Config.bar.persistent || visibilities.bar) ? contentWidth : Config.border.thickness
|
readonly property int exclusiveZone: !disabled && (Config.bar.persistent || visibilities.bar) ? contentWidth : Config.border.thickness
|
||||||
readonly property bool shouldBeVisible: !disabled && (Config.bar.persistent || visibilities.bar || isHovered)
|
readonly property bool shouldBeVisible: !fullscreen && !disabled && (Config.bar.persistent || visibilities.bar || isHovered)
|
||||||
property bool isHovered
|
property bool isHovered
|
||||||
|
|
||||||
function closeTray(): void {
|
function closeTray(): void {
|
||||||
|
|
@ -33,8 +34,9 @@ Item {
|
||||||
(content.item as Bar)?.handleWheel(y, angleDelta);
|
(content.item as Bar)?.handleWheel(y, angleDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
visible: width > Config.border.thickness
|
clip: true
|
||||||
implicitWidth: Config.border.thickness
|
visible: width > 0
|
||||||
|
implicitWidth: fullscreen ? 0 : Config.border.thickness
|
||||||
|
|
||||||
states: State {
|
states: State {
|
||||||
name: "visible"
|
name: "visible"
|
||||||
|
|
@ -83,6 +85,7 @@ Item {
|
||||||
screen: root.screen
|
screen: root.screen
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
popouts: root.popouts // qmllint disable incompatible-type
|
popouts: root.popouts // qmllint disable incompatible-type
|
||||||
|
fullscreen: root.fullscreen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ StyledRect {
|
||||||
required property int activeWsId
|
required property int activeWsId
|
||||||
required property Repeater workspaces
|
required property Repeater workspaces
|
||||||
required property Item mask
|
required property Item mask
|
||||||
|
required property bool fullscreen
|
||||||
|
|
||||||
readonly property int currentWsIdx: {
|
readonly property int currentWsIdx: {
|
||||||
let i = activeWsId - 1;
|
let i = activeWsId - 1;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ StyledClippingRect {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
|
required property bool fullscreen
|
||||||
|
|
||||||
readonly property bool onSpecial: (Config.bar.workspaces.perMonitorWorkspaces ? Hypr.monitorFor(screen) : Hypr.focusedMonitor)?.lastIpcObject.specialWorkspace?.name !== ""
|
readonly property bool onSpecial: (Config.bar.workspaces.perMonitorWorkspaces ? Hypr.monitorFor(screen) : Hypr.focusedMonitor)?.lastIpcObject.specialWorkspace?.name !== ""
|
||||||
readonly property int activeWsId: Config.bar.workspaces.perMonitorWorkspaces ? (Hypr.monitorFor(screen).activeWorkspace?.id ?? 1) : Hypr.activeWsId
|
readonly property int activeWsId: Config.bar.workspaces.perMonitorWorkspaces ? (Hypr.monitorFor(screen).activeWorkspace?.id ?? 1) : Hypr.activeWsId
|
||||||
|
|
@ -36,6 +37,7 @@ StyledClippingRect {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
scale: root.onSpecial ? 0.8 : 1
|
scale: root.onSpecial ? 0.8 : 1
|
||||||
opacity: root.onSpecial ? 0.5 : 1
|
opacity: root.onSpecial ? 0.5 : 1
|
||||||
|
visible: !root.fullscreen
|
||||||
|
|
||||||
layer.enabled: root.blur > 0
|
layer.enabled: root.blur > 0
|
||||||
layer.effect: MultiEffect {
|
layer.effect: MultiEffect {
|
||||||
|
|
@ -86,6 +88,7 @@ StyledClippingRect {
|
||||||
activeWsId: root.activeWsId
|
activeWsId: root.activeWsId
|
||||||
workspaces: workspaces
|
workspaces: workspaces
|
||||||
mask: layout
|
mask: layout
|
||||||
|
fullscreen: root.fullscreen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,12 @@ QtObject {
|
||||||
readonly property string icon: "task_alt"
|
readonly property string icon: "task_alt"
|
||||||
readonly property string component: "taskbar/TaskbarPane.qml"
|
readonly property string component: "taskbar/TaskbarPane.qml"
|
||||||
},
|
},
|
||||||
|
QtObject {
|
||||||
|
readonly property string id: "notifications"
|
||||||
|
readonly property string label: "notifications"
|
||||||
|
readonly property string icon: "notifications"
|
||||||
|
readonly property string component: "notifications/NotificationsPane.qml"
|
||||||
|
},
|
||||||
QtObject {
|
QtObject {
|
||||||
readonly property string id: "launcher"
|
readonly property string id: "launcher"
|
||||||
readonly property string label: "launcher"
|
readonly property string label: "launcher"
|
||||||
|
|
@ -60,7 +66,7 @@ QtObject {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getByIndex(index: int): QtObject {
|
function getByIndex(index: int): var {
|
||||||
if (index >= 0 && index < panes.length) {
|
if (index >= 0 && index < panes.length) {
|
||||||
return panes[index];
|
return panes[index];
|
||||||
}
|
}
|
||||||
|
|
@ -76,12 +82,12 @@ QtObject {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getByLabel(label: string): QtObject {
|
function getByLabel(label: string): var {
|
||||||
const index = getIndexByLabel(label);
|
const index = getIndexByLabel(label);
|
||||||
return getByIndex(index);
|
return getByIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getById(id: string): QtObject {
|
function getById(id: string): var {
|
||||||
for (let i = 0; i < panes.length; i++) {
|
for (let i = 0; i < panes.length; i++) {
|
||||||
if (panes[i].id === id) {
|
if (panes[i].id === id) {
|
||||||
return panes[i];
|
return panes[i];
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import "network"
|
||||||
import "audio"
|
import "audio"
|
||||||
import "appearance"
|
import "appearance"
|
||||||
import "taskbar"
|
import "taskbar"
|
||||||
|
import "notifications"
|
||||||
import "launcher"
|
import "launcher"
|
||||||
import "dashboard"
|
import "dashboard"
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
|
||||||
427
modules/controlcenter/notifications/NotificationsPane.qml
Normal file
427
modules/controlcenter/notifications/NotificationsPane.qml
Normal file
|
|
@ -0,0 +1,427 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import ".."
|
||||||
|
import "../components"
|
||||||
|
import qs.components
|
||||||
|
import qs.components.controls
|
||||||
|
import qs.components.effects
|
||||||
|
import qs.components.containers
|
||||||
|
import qs.services
|
||||||
|
import qs.config
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Session session
|
||||||
|
|
||||||
|
property bool notificationsExpire: Config.notifs.expire ?? true
|
||||||
|
property string notificationsFullscreen: Config.notifs.fullscreen ?? "on"
|
||||||
|
property bool notificationsOpenExpanded: Config.notifs.openExpanded ?? false
|
||||||
|
property int notificationsDefaultExpireTimeout: Config.notifs.defaultExpireTimeout ?? 5000
|
||||||
|
property int notificationsGroupPreviewNum: Config.notifs.groupPreviewNum ?? 3
|
||||||
|
|
||||||
|
property int maxToasts: Config.utilities.maxToasts ?? 4
|
||||||
|
property string toastsFullscreen: Config.utilities.toasts.fullscreen ?? "off"
|
||||||
|
property bool chargingChanged: Config.utilities.toasts.chargingChanged ?? true
|
||||||
|
property bool gameModeChanged: Config.utilities.toasts.gameModeChanged ?? true
|
||||||
|
property bool dndChanged: Config.utilities.toasts.dndChanged ?? true
|
||||||
|
property bool audioOutputChanged: Config.utilities.toasts.audioOutputChanged ?? true
|
||||||
|
property bool audioInputChanged: Config.utilities.toasts.audioInputChanged ?? true
|
||||||
|
property bool capsLockChanged: Config.utilities.toasts.capsLockChanged ?? true
|
||||||
|
property bool numLockChanged: Config.utilities.toasts.numLockChanged ?? true
|
||||||
|
property bool kbLayoutChanged: Config.utilities.toasts.kbLayoutChanged ?? true
|
||||||
|
property bool vpnChanged: Config.utilities.toasts.vpnChanged ?? true
|
||||||
|
property bool nowPlaying: Config.utilities.toasts.nowPlaying ?? false
|
||||||
|
|
||||||
|
function saveConfig(): void {
|
||||||
|
Config.notifs.expire = root.notificationsExpire;
|
||||||
|
Config.notifs.fullscreen = root.notificationsFullscreen;
|
||||||
|
Config.notifs.openExpanded = root.notificationsOpenExpanded;
|
||||||
|
Config.notifs.defaultExpireTimeout = root.notificationsDefaultExpireTimeout;
|
||||||
|
Config.notifs.groupPreviewNum = root.notificationsGroupPreviewNum;
|
||||||
|
|
||||||
|
Config.utilities.maxToasts = root.maxToasts;
|
||||||
|
Config.utilities.toasts.fullscreen = root.toastsFullscreen;
|
||||||
|
Config.utilities.toasts.chargingChanged = root.chargingChanged;
|
||||||
|
Config.utilities.toasts.gameModeChanged = root.gameModeChanged;
|
||||||
|
Config.utilities.toasts.dndChanged = root.dndChanged;
|
||||||
|
Config.utilities.toasts.audioOutputChanged = root.audioOutputChanged;
|
||||||
|
Config.utilities.toasts.audioInputChanged = root.audioInputChanged;
|
||||||
|
Config.utilities.toasts.capsLockChanged = root.capsLockChanged;
|
||||||
|
Config.utilities.toasts.numLockChanged = root.numLockChanged;
|
||||||
|
Config.utilities.toasts.kbLayoutChanged = root.kbLayoutChanged;
|
||||||
|
Config.utilities.toasts.vpnChanged = root.vpnChanged;
|
||||||
|
Config.utilities.toasts.nowPlaying = root.nowPlaying;
|
||||||
|
|
||||||
|
Config.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
ClippingRectangle {
|
||||||
|
id: notificationsClippingRect
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.leftMargin: 0
|
||||||
|
anchors.rightMargin: Appearance.padding.normal
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
radius: notificationsBorder.innerRadius
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: notificationsLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Appearance.padding.large + Appearance.padding.normal
|
||||||
|
anchors.leftMargin: Appearance.padding.large
|
||||||
|
anchors.rightMargin: Appearance.padding.large
|
||||||
|
|
||||||
|
sourceComponent: notificationsContentComponent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerBorder {
|
||||||
|
id: notificationsBorder
|
||||||
|
|
||||||
|
leftThickness: 0
|
||||||
|
rightThickness: Appearance.padding.normal
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: notificationsContentComponent
|
||||||
|
|
||||||
|
StyledFlickable {
|
||||||
|
id: notificationsFlickable
|
||||||
|
|
||||||
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
contentHeight: notificationsLayout.height
|
||||||
|
|
||||||
|
StyledScrollBar.vertical: StyledScrollBar {
|
||||||
|
flickable: notificationsFlickable
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: notificationsLayout
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.maximumWidth: 500
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
SectionContainer {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
alignTop: true
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: qsTr("Notifications")
|
||||||
|
font.pointSize: Appearance.font.size.normal
|
||||||
|
}
|
||||||
|
|
||||||
|
SplitButtonRow {
|
||||||
|
id: notificationsFullscreenSelector
|
||||||
|
|
||||||
|
function syncActiveItem(): void {
|
||||||
|
active = root.notificationsFullscreen === "off" ? notificationsFullscreenOffItem : notificationsFullscreenOnItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
label: qsTr("Show in fullscreen")
|
||||||
|
menuItems: [notificationsFullscreenOffItem, notificationsFullscreenOnItem]
|
||||||
|
|
||||||
|
Component.onCompleted: syncActiveItem()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onNotificationsFullscreenChanged(): void {
|
||||||
|
notificationsFullscreenSelector.syncActiveItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
target: root
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
id: notificationsFullscreenOffItem
|
||||||
|
|
||||||
|
text: qsTr("Off")
|
||||||
|
icon: "notifications_off"
|
||||||
|
activeText: qsTr("Off")
|
||||||
|
onClicked: {
|
||||||
|
root.notificationsFullscreen = "off";
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
id: notificationsFullscreenOnItem
|
||||||
|
|
||||||
|
text: qsTr("On")
|
||||||
|
icon: "notifications"
|
||||||
|
activeText: qsTr("On")
|
||||||
|
onClicked: {
|
||||||
|
root.notificationsFullscreen = "on";
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
label: qsTr("Expire automatically")
|
||||||
|
checked: root.notificationsExpire
|
||||||
|
onToggled: checked => {
|
||||||
|
root.notificationsExpire = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
label: qsTr("Open expanded")
|
||||||
|
checked: root.notificationsOpenExpanded
|
||||||
|
onToggled: checked => {
|
||||||
|
root.notificationsOpenExpanded = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinBoxRow {
|
||||||
|
label: qsTr("Default timeout")
|
||||||
|
value: root.notificationsDefaultExpireTimeout
|
||||||
|
min: 1000
|
||||||
|
max: 60000
|
||||||
|
step: 500
|
||||||
|
onValueModified: value => {
|
||||||
|
root.notificationsDefaultExpireTimeout = value;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinBoxRow {
|
||||||
|
label: qsTr("Group preview count")
|
||||||
|
value: root.notificationsGroupPreviewNum
|
||||||
|
min: 1
|
||||||
|
max: 10
|
||||||
|
step: 1
|
||||||
|
onValueModified: value => {
|
||||||
|
root.notificationsGroupPreviewNum = value;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
SectionContainer {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
alignTop: true
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: qsTr("Toast settings")
|
||||||
|
font.pointSize: Appearance.font.size.normal
|
||||||
|
}
|
||||||
|
|
||||||
|
SplitButtonRow {
|
||||||
|
id: toastFullscreenSelector
|
||||||
|
|
||||||
|
function syncActiveItem(): void {
|
||||||
|
if (root.toastsFullscreen === "all") {
|
||||||
|
active = toastFullscreenAllItem;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.toastsFullscreen === "important") {
|
||||||
|
active = toastFullscreenImportantItem;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
active = toastFullscreenOffItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
z: expanded ? 100 : 0
|
||||||
|
label: qsTr("Show in fullscreen")
|
||||||
|
menuItems: [toastFullscreenOffItem, toastFullscreenImportantItem, toastFullscreenAllItem]
|
||||||
|
|
||||||
|
Component.onCompleted: syncActiveItem()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onToastsFullscreenChanged(): void {
|
||||||
|
toastFullscreenSelector.syncActiveItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
target: root
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
id: toastFullscreenOffItem
|
||||||
|
|
||||||
|
text: qsTr("Off")
|
||||||
|
icon: "notifications_off"
|
||||||
|
activeText: qsTr("Off")
|
||||||
|
onClicked: {
|
||||||
|
root.toastsFullscreen = "off";
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
id: toastFullscreenImportantItem
|
||||||
|
|
||||||
|
text: qsTr("Important")
|
||||||
|
icon: "priority_high"
|
||||||
|
activeText: qsTr("Important")
|
||||||
|
onClicked: {
|
||||||
|
root.toastsFullscreen = "important";
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
id: toastFullscreenAllItem
|
||||||
|
|
||||||
|
text: qsTr("On")
|
||||||
|
icon: "notifications"
|
||||||
|
activeText: qsTr("On")
|
||||||
|
onClicked: {
|
||||||
|
root.toastsFullscreen = "all";
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinBoxRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("Visible toasts")
|
||||||
|
value: root.maxToasts
|
||||||
|
min: 1
|
||||||
|
max: 10
|
||||||
|
step: 1
|
||||||
|
onValueModified: value => {
|
||||||
|
root.maxToasts = value;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
columns: 2
|
||||||
|
columnSpacing: Appearance.spacing.normal
|
||||||
|
rowSpacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("Charging changes")
|
||||||
|
checked: root.chargingChanged
|
||||||
|
onToggled: checked => {
|
||||||
|
root.chargingChanged = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("Game mode changes")
|
||||||
|
checked: root.gameModeChanged
|
||||||
|
onToggled: checked => {
|
||||||
|
root.gameModeChanged = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("Do not disturb")
|
||||||
|
checked: root.dndChanged
|
||||||
|
onToggled: checked => {
|
||||||
|
root.dndChanged = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("Audio output changes")
|
||||||
|
checked: root.audioOutputChanged
|
||||||
|
onToggled: checked => {
|
||||||
|
root.audioOutputChanged = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("Audio input changes")
|
||||||
|
checked: root.audioInputChanged
|
||||||
|
onToggled: checked => {
|
||||||
|
root.audioInputChanged = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("Caps lock changes")
|
||||||
|
checked: root.capsLockChanged
|
||||||
|
onToggled: checked => {
|
||||||
|
root.capsLockChanged = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("Num lock changes")
|
||||||
|
checked: root.numLockChanged
|
||||||
|
onToggled: checked => {
|
||||||
|
root.numLockChanged = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("Keyboard layout changes")
|
||||||
|
checked: root.kbLayoutChanged
|
||||||
|
onToggled: checked => {
|
||||||
|
root.kbLayoutChanged = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("VPN changes")
|
||||||
|
checked: root.vpnChanged
|
||||||
|
onToggled: checked => {
|
||||||
|
root.vpnChanged = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: qsTr("Now playing")
|
||||||
|
checked: root.nowPlaying
|
||||||
|
onToggled: checked => {
|
||||||
|
root.nowPlaying = checked;
|
||||||
|
root.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,14 +15,17 @@ Shape {
|
||||||
|
|
||||||
required property Panels panels
|
required property Panels panels
|
||||||
required property Item bar
|
required property Item bar
|
||||||
|
required property real borderThickness
|
||||||
|
required property real borderRounding
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Config.border.thickness
|
anchors.margins: root.borderThickness
|
||||||
anchors.leftMargin: bar.implicitWidth
|
anchors.leftMargin: bar.implicitWidth
|
||||||
preferredRendererType: Shape.CurveRenderer
|
preferredRendererType: Shape.CurveRenderer
|
||||||
|
|
||||||
Osd.Background {
|
Osd.Background {
|
||||||
wrapper: root.panels.osd // qmllint disable incompatible-type
|
wrapper: root.panels.osd // qmllint disable incompatible-type
|
||||||
|
rounding: Config.border.rounding
|
||||||
|
|
||||||
startX: root.width - root.panels.session.width - root.panels.sidebar.width
|
startX: root.width - root.panels.session.width - root.panels.sidebar.width
|
||||||
startY: (root.height - wrapper.height) / 2 - rounding
|
startY: (root.height - wrapper.height) / 2 - rounding
|
||||||
|
|
@ -31,6 +34,7 @@ Shape {
|
||||||
Notifications.Background {
|
Notifications.Background {
|
||||||
wrapper: root.panels.notifications // qmllint disable incompatible-type
|
wrapper: root.panels.notifications // qmllint disable incompatible-type
|
||||||
sidebar: sidebar
|
sidebar: sidebar
|
||||||
|
rounding: Config.border.rounding
|
||||||
|
|
||||||
startX: root.width
|
startX: root.width
|
||||||
startY: 0
|
startY: 0
|
||||||
|
|
@ -68,6 +72,7 @@ Shape {
|
||||||
Utilities.Background {
|
Utilities.Background {
|
||||||
wrapper: root.panels.utilities // qmllint disable incompatible-type
|
wrapper: root.panels.utilities // qmllint disable incompatible-type
|
||||||
sidebar: sidebar
|
sidebar: sidebar
|
||||||
|
rounding: root.borderRounding
|
||||||
|
|
||||||
startX: root.width
|
startX: root.width
|
||||||
startY: root.height
|
startY: root.height
|
||||||
|
|
@ -78,6 +83,7 @@ Shape {
|
||||||
|
|
||||||
wrapper: root.panels.sidebar // qmllint disable incompatible-type
|
wrapper: root.panels.sidebar // qmllint disable incompatible-type
|
||||||
panels: root.panels
|
panels: root.panels
|
||||||
|
rounding: root.borderRounding
|
||||||
|
|
||||||
startX: root.width
|
startX: root.width
|
||||||
startY: root.panels.notifications.height
|
startY: root.panels.notifications.height
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,13 @@ import QtQuick
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import qs.components
|
import qs.components
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Item bar
|
required property Item bar
|
||||||
|
required property real borderThickness
|
||||||
|
required property real borderRounding
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
|
@ -36,9 +37,9 @@ Item {
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Config.border.thickness
|
anchors.margins: root.borderThickness
|
||||||
anchors.leftMargin: root.bar.implicitWidth
|
anchors.leftMargin: root.bar.implicitWidth
|
||||||
radius: Config.border.rounding
|
radius: root.borderRounding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,18 +25,34 @@ Variants {
|
||||||
Exclusions {
|
Exclusions {
|
||||||
screen: scope.modelData
|
screen: scope.modelData
|
||||||
bar: bar
|
bar: bar
|
||||||
|
borderThickness: Config.border.thickness
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledWindow {
|
StyledWindow {
|
||||||
id: win
|
id: win
|
||||||
|
|
||||||
readonly property bool hasFullscreen: Hypr.monitorFor(screen)?.activeWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen === 2) ?? false
|
readonly property var monitor: Hypr.monitorFor(screen)
|
||||||
|
readonly property bool hasSpecialWorkspace: (monitor?.lastIpcObject?.specialWorkspace?.name.length ?? 0) > 0
|
||||||
|
readonly property bool hasFullscreen: {
|
||||||
|
if (hasSpecialWorkspace) {
|
||||||
|
const specialName = monitor?.lastIpcObject?.specialWorkspace?.name;
|
||||||
|
if (!specialName)
|
||||||
|
return false;
|
||||||
|
const specialWs = Hypr.workspaces.values.find(ws => ws.name === specialName);
|
||||||
|
return specialWs?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1) ?? false;
|
||||||
|
}
|
||||||
|
return monitor?.activeWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1) ?? false;
|
||||||
|
}
|
||||||
|
property real borderThickness: hasFullscreen ? 0 : Config.border.thickness
|
||||||
|
readonly property real borderLayoutThickness: hasFullscreen ? 0 : Config.border.thickness
|
||||||
|
property real borderRounding: hasFullscreen ? 0 : Config.border.rounding
|
||||||
|
property real shadowOpacity: hasFullscreen ? 0 : 0.7
|
||||||
readonly property int dragMaskPadding: {
|
readonly property int dragMaskPadding: {
|
||||||
if (focusGrab.active || panels.popouts.isDetached)
|
if (focusGrab.active || panels.popouts.isDetached)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const mon = Hypr.monitorFor(screen);
|
const mon = Hypr.monitorFor(screen);
|
||||||
if (mon?.lastIpcObject.specialWorkspace?.name || mon?.activeWorkspace?.lastIpcObject.windows > 0)
|
if (mon?.lastIpcObject.specialWorkspace?.name || mon?.activeWorkspace.lastIpcObject.windows > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const thresholds = [];
|
const thresholds = [];
|
||||||
|
|
@ -55,6 +71,7 @@ Variants {
|
||||||
screen: scope.modelData
|
screen: scope.modelData
|
||||||
name: "drawers"
|
name: "drawers"
|
||||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.session || panels.dashboard.needsKeyboard ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.session || panels.dashboard.needsKeyboard ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
||||||
|
|
||||||
mask: Region {
|
mask: Region {
|
||||||
|
|
@ -72,6 +89,30 @@ Variants {
|
||||||
anchors.left: true
|
anchors.left: true
|
||||||
anchors.right: true
|
anchors.right: true
|
||||||
|
|
||||||
|
Behavior on borderThickness {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on borderRounding {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on shadowOpacity {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Variants {
|
Variants {
|
||||||
id: regions
|
id: regions
|
||||||
|
|
||||||
|
|
@ -81,7 +122,7 @@ Variants {
|
||||||
required property Item modelData
|
required property Item modelData
|
||||||
|
|
||||||
x: modelData.x + bar.implicitWidth
|
x: modelData.x + bar.implicitWidth
|
||||||
y: modelData.y + Config.border.thickness
|
y: modelData.y + win.borderLayoutThickness
|
||||||
width: modelData.width
|
width: modelData.width
|
||||||
height: modelData.height
|
height: modelData.height
|
||||||
intersection: Intersection.Subtract
|
intersection: Intersection.Subtract
|
||||||
|
|
@ -120,16 +161,20 @@ Variants {
|
||||||
layer.effect: MultiEffect {
|
layer.effect: MultiEffect {
|
||||||
shadowEnabled: true
|
shadowEnabled: true
|
||||||
blurMax: 15
|
blurMax: 15
|
||||||
shadowColor: Qt.alpha(Colours.palette.m3shadow, 0.7)
|
shadowColor: Qt.alpha(Colours.palette.m3shadow, Math.max(0, win.shadowOpacity))
|
||||||
}
|
}
|
||||||
|
|
||||||
Border {
|
Border {
|
||||||
bar: bar
|
bar: bar
|
||||||
|
borderThickness: win.borderThickness
|
||||||
|
borderRounding: win.borderRounding
|
||||||
}
|
}
|
||||||
|
|
||||||
Backgrounds {
|
Backgrounds {
|
||||||
panels: panels
|
panels: panels
|
||||||
bar: bar
|
bar: bar
|
||||||
|
borderThickness: win.borderThickness
|
||||||
|
borderRounding: win.borderRounding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,6 +190,8 @@ Variants {
|
||||||
visibilities: visibilities
|
visibilities: visibilities
|
||||||
panels: panels
|
panels: panels
|
||||||
bar: bar
|
bar: bar
|
||||||
|
borderThickness: win.borderLayoutThickness
|
||||||
|
fullscreen: win.hasFullscreen
|
||||||
|
|
||||||
Panels {
|
Panels {
|
||||||
id: panels
|
id: panels
|
||||||
|
|
@ -152,6 +199,7 @@ Variants {
|
||||||
screen: scope.modelData
|
screen: scope.modelData
|
||||||
visibilities: visibilities
|
visibilities: visibilities
|
||||||
bar: bar
|
bar: bar
|
||||||
|
borderThickness: win.borderLayoutThickness
|
||||||
}
|
}
|
||||||
|
|
||||||
BarWrapper {
|
BarWrapper {
|
||||||
|
|
@ -165,6 +213,7 @@ Variants {
|
||||||
popouts: panels.popouts
|
popouts: panels.popouts
|
||||||
|
|
||||||
disabled: scope.barDisabled
|
disabled: scope.barDisabled
|
||||||
|
fullscreen: win.hasFullscreen
|
||||||
|
|
||||||
Component.onCompleted: Visibilities.bars.set(scope.modelData, this)
|
Component.onCompleted: Visibilities.bars.set(scope.modelData, this)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.components.containers
|
import qs.components.containers
|
||||||
import qs.config
|
|
||||||
import qs.modules.bar as Bar
|
import qs.modules.bar as Bar
|
||||||
|
|
||||||
Scope {
|
Scope {
|
||||||
|
|
@ -11,6 +10,7 @@ Scope {
|
||||||
|
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
required property Bar.BarWrapper bar
|
required property Bar.BarWrapper bar
|
||||||
|
required property real borderThickness
|
||||||
|
|
||||||
ExclusionZone {
|
ExclusionZone {
|
||||||
anchors.left: true
|
anchors.left: true
|
||||||
|
|
@ -32,7 +32,7 @@ Scope {
|
||||||
component ExclusionZone: StyledWindow {
|
component ExclusionZone: StyledWindow {
|
||||||
screen: root.screen
|
screen: root.screen
|
||||||
name: "border-exclusion"
|
name: "border-exclusion"
|
||||||
exclusiveZone: Config.border.thickness
|
exclusiveZone: root.borderThickness
|
||||||
mask: Region {}
|
mask: Region {}
|
||||||
implicitWidth: 1
|
implicitWidth: 1
|
||||||
implicitHeight: 1
|
implicitHeight: 1
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ CustomMouseArea {
|
||||||
required property DrawerVisibilities visibilities
|
required property DrawerVisibilities visibilities
|
||||||
required property Panels panels
|
required property Panels panels
|
||||||
required property Bar.BarWrapper bar
|
required property Bar.BarWrapper bar
|
||||||
|
required property real borderThickness
|
||||||
|
required property bool fullscreen
|
||||||
|
|
||||||
property point dragStart
|
property point dragStart
|
||||||
property bool dashboardShortcutActive
|
property bool dashboardShortcutActive
|
||||||
|
|
@ -22,7 +24,7 @@ CustomMouseArea {
|
||||||
property bool utilitiesShortcutActive
|
property bool utilitiesShortcutActive
|
||||||
|
|
||||||
function withinPanelHeight(panel: Item, x: real, y: real): bool {
|
function withinPanelHeight(panel: Item, x: real, y: real): bool {
|
||||||
const panelY = Config.border.thickness + panel.y;
|
const panelY = root.borderThickness + panel.y;
|
||||||
return y >= panelY - Config.border.rounding && y <= panelY + panel.height + Config.border.rounding;
|
return y >= panelY - Config.border.rounding && y <= panelY + panel.height + Config.border.rounding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,13 +50,16 @@ CustomMouseArea {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWheel(event: WheelEvent): void {
|
function onWheel(event: WheelEvent): void {
|
||||||
|
if (fullscreen)
|
||||||
|
return;
|
||||||
if (event.x < bar.implicitWidth) {
|
if (event.x < bar.implicitWidth) {
|
||||||
bar.handleWheel(event.y, event.angleDelta);
|
bar.handleWheel(event.y, event.angleDelta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
acceptedButtons: fullscreen ? Qt.NoButton : Qt.AllButtons
|
||||||
|
hoverEnabled: !fullscreen
|
||||||
|
|
||||||
onPressed: event => dragStart = Qt.point(event.x, event.y)
|
onPressed: event => dragStart = Qt.point(event.x, event.y)
|
||||||
onContainsMouseChanged: {
|
onContainsMouseChanged: {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ Item {
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
required property DrawerVisibilities visibilities
|
required property DrawerVisibilities visibilities
|
||||||
required property Bar.BarWrapper bar
|
required property Bar.BarWrapper bar
|
||||||
|
required property real borderThickness
|
||||||
|
|
||||||
readonly property alias osd: osd
|
readonly property alias osd: osd
|
||||||
readonly property alias notifications: notifications
|
readonly property alias notifications: notifications
|
||||||
|
|
@ -31,9 +32,17 @@ Item {
|
||||||
readonly property alias sidebar: sidebar
|
readonly property alias sidebar: sidebar
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Config.border.thickness
|
anchors.margins: root.borderThickness
|
||||||
anchors.leftMargin: bar.implicitWidth
|
anchors.leftMargin: bar.implicitWidth
|
||||||
|
|
||||||
|
Behavior on anchors.margins {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on anchors.leftMargin {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
Osd.Wrapper {
|
Osd.Wrapper {
|
||||||
id: osd
|
id: osd
|
||||||
|
|
||||||
|
|
@ -100,7 +109,7 @@ Item {
|
||||||
if (isDetached)
|
if (isDetached)
|
||||||
return (root.height - nonAnimHeight) / 2;
|
return (root.height - nonAnimHeight) / 2;
|
||||||
|
|
||||||
const off = currentCenter - Config.border.thickness - nonAnimHeight / 2;
|
const off = currentCenter - root.borderThickness - nonAnimHeight / 2;
|
||||||
const diff = root.height - Math.floor(off + nonAnimHeight);
|
const diff = root.height - Math.floor(off + nonAnimHeight);
|
||||||
if (diff < 0)
|
if (diff < 0)
|
||||||
return off + diff;
|
return off + diff;
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,13 @@ import QtQuick
|
||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
import qs.components
|
import qs.components
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
|
||||||
|
|
||||||
ShapePath {
|
ShapePath {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Wrapper wrapper
|
required property Wrapper wrapper
|
||||||
required property var sidebar
|
required property var sidebar
|
||||||
readonly property real rounding: Config.border.rounding
|
required property real rounding
|
||||||
readonly property bool flatten: wrapper.height < rounding * 2
|
readonly property bool flatten: wrapper.height < rounding * 2
|
||||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||||
|
|
||||||
|
|
@ -31,14 +30,14 @@ ShapePath {
|
||||||
relativeY: root.wrapper.height - root.roundingY * 2
|
relativeY: root.wrapper.height - root.roundingY * 2
|
||||||
}
|
}
|
||||||
PathArc {
|
PathArc {
|
||||||
relativeX: root.sidebar.notifsRoundingX
|
relativeX: root.rounding
|
||||||
relativeY: root.roundingY
|
relativeY: root.roundingY
|
||||||
radiusX: root.sidebar.notifsRoundingX
|
radiusX: root.rounding
|
||||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||||
direction: PathArc.Counterclockwise
|
direction: PathArc.Counterclockwise
|
||||||
}
|
}
|
||||||
PathLine {
|
PathLine {
|
||||||
relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding - root.sidebar.notifsRoundingX : root.wrapper.width
|
relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding * 2 : root.wrapper.width
|
||||||
relativeY: 0
|
relativeY: 0
|
||||||
}
|
}
|
||||||
PathArc {
|
PathArc {
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,12 @@ import QtQuick
|
||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
import qs.components
|
import qs.components
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
|
||||||
|
|
||||||
ShapePath {
|
ShapePath {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Wrapper wrapper
|
required property Wrapper wrapper
|
||||||
readonly property real rounding: Config.border.rounding
|
required property real rounding
|
||||||
readonly property bool flatten: wrapper.width < rounding * 2
|
readonly property bool flatten: wrapper.width < rounding * 2
|
||||||
readonly property real roundingX: flatten ? wrapper.width / 2 : rounding
|
readonly property real roundingX: flatten ? wrapper.width / 2 : rounding
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,13 @@ import QtQuick
|
||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
import qs.components
|
import qs.components
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
|
||||||
|
|
||||||
ShapePath {
|
ShapePath {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Wrapper wrapper
|
required property Wrapper wrapper
|
||||||
required property var panels
|
required property var panels
|
||||||
|
required property real rounding
|
||||||
readonly property real rounding: Config.border.rounding
|
|
||||||
|
|
||||||
readonly property real notifsWidthDiff: panels.notifications.width - wrapper.width
|
readonly property real notifsWidthDiff: panels.notifications.width - wrapper.width
|
||||||
readonly property real notifsRoundingX: panels.notifications.height > 0 && notifsWidthDiff < rounding * 2 ? notifsWidthDiff / 2 : rounding
|
readonly property real notifsRoundingX: panels.notifications.height > 0 && notifsWidthDiff < rounding * 2 ? notifsWidthDiff / 2 : rounding
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,13 @@ import QtQuick
|
||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
import qs.components
|
import qs.components
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
|
||||||
|
|
||||||
ShapePath {
|
ShapePath {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Wrapper wrapper
|
required property Wrapper wrapper
|
||||||
required property var sidebar
|
required property var sidebar
|
||||||
readonly property real rounding: Config.border.rounding
|
required property real rounding
|
||||||
readonly property bool flatten: wrapper.height < rounding * 2
|
readonly property bool flatten: wrapper.height < rounding * 2
|
||||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Caelestia
|
import Caelestia
|
||||||
import qs.components
|
import qs.components
|
||||||
|
import qs.services
|
||||||
import qs.config
|
import qs.config
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|
@ -12,6 +13,16 @@ Item {
|
||||||
readonly property int spacing: Appearance.spacing.small
|
readonly property int spacing: Appearance.spacing.small
|
||||||
property bool flag
|
property bool flag
|
||||||
|
|
||||||
|
function shouldShowToast(toast: Toast): bool {
|
||||||
|
if (!Notifs.hasFullscreen())
|
||||||
|
return true;
|
||||||
|
if (Config.utilities.toasts.fullscreen === "all")
|
||||||
|
return true;
|
||||||
|
if (Config.utilities.toasts.fullscreen === "important")
|
||||||
|
return toast.type === Toast.Warning || toast.type === Toast.Error;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
implicitWidth: Config.utilities.sizes.toastWidth - Appearance.padding.normal * 2
|
implicitWidth: Config.utilities.sizes.toastWidth - Appearance.padding.normal * 2
|
||||||
implicitHeight: {
|
implicitHeight: {
|
||||||
let h = -spacing;
|
let h = -spacing;
|
||||||
|
|
@ -31,6 +42,8 @@ Item {
|
||||||
const toasts = [];
|
const toasts = [];
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (const toast of Toaster.toasts) {
|
for (const toast of Toaster.toasts) {
|
||||||
|
if (!root.shouldShowToast(toast))
|
||||||
|
continue;
|
||||||
toasts.push(toast);
|
toasts.push(toast);
|
||||||
if (!toast.closed) {
|
if (!toast.closed) {
|
||||||
count++;
|
count++;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,22 @@ Singleton {
|
||||||
|
|
||||||
property bool loaded
|
property bool loaded
|
||||||
|
|
||||||
|
function hasFullscreen(): bool {
|
||||||
|
for (const monitor of Hypr.monitors.values) {
|
||||||
|
if (monitor?.activeWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldShowPopup(): bool {
|
||||||
|
if (props.dnd || [...Visibilities.screens.values()].some(v => v.sidebar))
|
||||||
|
return false;
|
||||||
|
if (Config.notifs.fullscreen === "off" && hasFullscreen())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
onDndChanged: {
|
onDndChanged: {
|
||||||
if (!Config.utilities.toasts.dndChanged)
|
if (!Config.utilities.toasts.dndChanged)
|
||||||
return;
|
return;
|
||||||
|
|
@ -79,7 +95,7 @@ Singleton {
|
||||||
notif.tracked = true;
|
notif.tracked = true;
|
||||||
|
|
||||||
const comp = notifComp.createObject(root, {
|
const comp = notifComp.createObject(root, {
|
||||||
popup: !props.dnd && ![...Visibilities.screens.values()].some(v => v.sidebar),
|
popup: root.shouldShowPopup(),
|
||||||
notification: notif
|
notification: notif
|
||||||
});
|
});
|
||||||
root.list = [comp, ...root.list];
|
root.list = [comp, ...root.list];
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue