controlcenter: add floating mode

Closes #363
This commit is contained in:
2 * r + 2 * t 2025-08-07 15:38:17 +10:00
parent 5bcface15a
commit d9ffc13825
8 changed files with 187 additions and 24 deletions

View file

@ -1,4 +1,5 @@
import qs.components.misc import qs.components.misc
import qs.modules.controlcenter
import qs.services import qs.services
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
@ -8,6 +9,12 @@ Scope {
property bool launcherInterrupted property bool launcherInterrupted
CustomShortcut {
name: "controlCenter"
description: "Open control center"
onPressed: WindowFactory.create()
}
CustomShortcut { CustomShortcut {
name: "showall" name: "showall"
description: "Toggle launcher, dashboard and osd" description: "Toggle launcher, dashboard and osd"
@ -62,4 +69,12 @@ Scope {
return Object.keys(visibilities).filter(k => typeof visibilities[k] === "boolean").join("\n"); return Object.keys(visibilities).filter(k => typeof visibilities[k] === "boolean").join("\n");
} }
} }
IpcHandler {
target: "controlCenter"
function open(): void {
WindowFactory.create();
}
}
} }

View file

@ -101,6 +101,10 @@ Item {
sourceComponent: ControlCenter { sourceComponent: ControlCenter {
screen: root.screen screen: root.screen
active: root.queuedMode active: root.queuedMode
function close(): void {
root.close();
}
} }
} }

View file

@ -12,9 +12,19 @@ Item {
id: root id: root
required property ShellScreen screen required property ShellScreen screen
property bool floating
readonly property int rounding: floating ? 0 : Appearance.rounding.normal
property alias active: session.active property alias active: session.active
property alias navExpanded: session.navExpanded
readonly property Session session: Session { readonly property Session session: Session {
id: session id: session
root: root
}
function close(): void {
} }
implicitWidth: implicitHeight * Config.controlCenter.sizes.ratio implicitWidth: implicitHeight * Config.controlCenter.sizes.ratio
@ -28,8 +38,8 @@ Item {
StyledRect { StyledRect {
Layout.fillHeight: true Layout.fillHeight: true
topLeftRadius: Appearance.rounding.normal topLeftRadius: root.rounding
bottomLeftRadius: Appearance.rounding.normal bottomLeftRadius: root.rounding
implicitWidth: navRail.implicitWidth implicitWidth: navRail.implicitWidth
color: Colours.palette.m3surfaceContainer color: Colours.palette.m3surfaceContainer
@ -47,6 +57,7 @@ Item {
NavRail { NavRail {
id: navRail id: navRail
screen: root.screen
session: root.session session: root.session
} }
} }
@ -55,6 +66,8 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
topRightRadius: root.rounding
bottomRightRadius: root.rounding
session: root.session session: root.session
} }
} }

View file

@ -3,14 +3,15 @@ pragma ComponentBehavior: Bound
import qs.components import qs.components
import qs.services import qs.services
import qs.config import qs.config
import Quickshell
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
Item { Item {
id: root id: root
required property ShellScreen screen
required property Session session required property Session session
property bool expanded
implicitWidth: layout.implicitWidth + Appearance.padding.large * 4 implicitWidth: layout.implicitWidth + Appearance.padding.large * 4
implicitHeight: layout.implicitHeight + Appearance.padding.large * 2 implicitHeight: layout.implicitHeight + Appearance.padding.large * 2
@ -23,7 +24,7 @@ Item {
states: State { states: State {
name: "expanded" name: "expanded"
when: root.expanded when: root.session.navExpanded
PropertyChanges { PropertyChanges {
layout.spacing: Appearance.spacing.small layout.spacing: Appearance.spacing.small
@ -32,14 +33,6 @@ Item {
menuIcon.rotation: 180 menuIcon.rotation: 180
menuIconExpanded.rotation: 0 menuIconExpanded.rotation: 0
} }
AnchorChanges {
target: menuIcon
anchors.horizontalCenter: undefined
}
AnchorChanges {
target: menuIconExpanded
anchors.horizontalCenter: undefined
}
} }
transitions: Transition { transitions: Transition {
@ -49,23 +42,27 @@ Item {
} }
Item { Item {
id: menuBtn
Layout.topMargin: Appearance.spacing.large
Layout.fillWidth: true Layout.fillWidth: true
Layout.bottomMargin: Appearance.spacing.large * 2 implicitHeight: menuIcon.implicitHeight + Appearance.padding.normal * 2
implicitHeight: Math.max(menuIcon.implicitHeight, menuIconExpanded.implicitHeight) + Appearance.padding.normal * 2
StateLayer { StateLayer {
radius: Appearance.rounding.small radius: Appearance.rounding.small
function onClicked(): void { function onClicked(): void {
root.expanded = !root.expanded; root.session.navExpanded = !root.session.navExpanded;
} }
} }
MaterialIcon { MaterialIcon {
id: menuIcon id: menuIcon
anchors.horizontalCenter: parent.horizontalCenter anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Appearance.padding.large
text: "menu" text: "menu"
font.pointSize: Appearance.font.size.large font.pointSize: Appearance.font.size.large
} }
@ -73,15 +70,86 @@ Item {
MaterialIcon { MaterialIcon {
id: menuIconExpanded id: menuIconExpanded
anchors.horizontalCenter: parent.horizontalCenter anchors.fill: menuIcon
anchors.verticalCenter: parent.verticalCenter
text: "menu_open" text: "menu_open"
font.pointSize: Appearance.font.size.large font.pointSize: menuIcon.font.pointSize
opacity: 0 opacity: 0
rotation: -180 rotation: -180
} }
} }
StyledRect {
id: normalWinBtn
readonly property int nonAnimWidth: normalWinIcon.implicitWidth + (root.session.navExpanded ? normalWinLabel.anchors.leftMargin + normalWinLabel.implicitWidth : 0) + normalWinIcon.anchors.leftMargin * 2
Layout.bottomMargin: Appearance.spacing.large * 2
implicitWidth: nonAnimWidth
implicitHeight: root.session.navExpanded ? normalWinIcon.implicitHeight + Appearance.padding.normal * 2 : nonAnimWidth
color: Colours.palette.m3primaryContainer
radius: Appearance.rounding.small
StateLayer {
id: normalWinState
color: Colours.palette.m3onPrimaryContainer
function onClicked(): void {
root.session.root.close();
WindowFactory.create(null, {
screen: root.screen,
active: root.session.active,
navExpanded: root.session.navExpanded
});
}
}
MaterialIcon {
id: normalWinIcon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Appearance.padding.large
text: "select_window"
font.pointSize: Appearance.font.size.large
fill: 1
}
StyledText {
id: normalWinLabel
anchors.left: normalWinIcon.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Appearance.spacing.normal
text: qsTr("Open in window")
opacity: root.session.navExpanded ? 1 : 0
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.small
}
}
}
Behavior on implicitWidth {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
Behavior on implicitHeight {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
}
NavItem { NavItem {
icon: "network_manage" icon: "network_manage"
label: "network" label: "network"
@ -110,7 +178,7 @@ Item {
states: State { states: State {
name: "expanded" name: "expanded"
when: root.expanded when: root.session.navExpanded
PropertyChanges { PropertyChanges {
expandedLabel.opacity: 1 expandedLabel.opacity: 1

View file

@ -14,8 +14,6 @@ ClippingRectangle {
required property Session session required property Session session
topRightRadius: Appearance.rounding.normal
bottomRightRadius: Appearance.rounding.normal
color: "transparent" color: "transparent"
ColumnLayout { ColumnLayout {

View file

@ -4,8 +4,10 @@ import QtQuick
QtObject { QtObject {
readonly property list<string> panes: ["network", "bluetooth", "audio"] readonly property list<string> panes: ["network", "bluetooth", "audio"]
property string active required property var root
property int activeIndex property string active: panes[0]
property int activeIndex: 0
property bool navExpanded: false
readonly property Bt bt: Bt {} readonly property Bt bt: Bt {}

View file

@ -0,0 +1,62 @@
pragma Singleton
import qs.services
import qs.config
import Quickshell
import QtQuick
Singleton {
id: root
function create(parent: Item, props: var): void {
controlCenter.createObject(parent ?? dummy, props);
}
QtObject {
id: dummy
}
Component {
id: controlCenter
FloatingWindow {
id: win
property alias active: cc.active
property alias navExpanded: cc.navExpanded
color: Colours.palette.m3surface
onVisibleChanged: {
if (!visible)
destroy();
}
minimumSize.width: 1000
minimumSize.height: 600
implicitWidth: cc.implicitWidth
implicitHeight: cc.implicitHeight
ControlCenter {
id: cc
anchors.fill: parent
screen: win.screen
floating: true
function close(): void {
win.visible = false;
}
}
Behavior on color {
ColorAnimation {
duration: Appearance.anim.durations.normal
easing.type: Easing.BezierSpline
easing.bezierCurve: Appearance.anim.curves.standard
}
}
}
}
}

View file

@ -19,6 +19,7 @@ RowLayout {
Item { Item {
Layout.preferredWidth: Math.floor(parent.width * 0.4) Layout.preferredWidth: Math.floor(parent.width * 0.4)
Layout.minimumWidth: 420
Layout.fillHeight: true Layout.fillHeight: true
DeviceList { DeviceList {