chore: fix bar linter warnings

This commit is contained in:
2 * r + 2 * t 2026-03-21 16:04:57 +11:00
parent 022d509f99
commit 20c7482b2b
17 changed files with 230 additions and 220 deletions

View file

@ -1,8 +1,9 @@
import Quickshell.Io
import qs.config
JsonObject {
property int thickness: Appearance.padding.normal
property int rounding: Appearance.rounding.large
property int thickness: Config.appearance.padding.normal
property int rounding: Config.appearance.rounding.large
readonly property int minThickness: 2
readonly property int clampedThickness: Math.max(minThickness, thickness)

View file

@ -23,9 +23,9 @@ ColumnLayout {
return;
for (let i = 0; i < repeater.count; i++) {
const item = repeater.itemAt(i);
if (item?.enabled && item.id === "tray") {
item.item.expanded = false;
const loader = repeater.itemAt(i) as WrappedLoader;
if (loader?.enabled && loader.id === "tray") {
(loader.item as Tray).expanded = false;
}
}
}
@ -43,11 +43,9 @@ ColumnLayout {
const id = ch.id;
const top = ch.y;
const item = ch.item;
const itemHeight = item.implicitHeight;
if (id === "statusIcons" && Config.bar.popouts.statusIcons) {
const items = item.items;
const items = (ch.item as StatusIcons).items;
const icon = items.childAt(items.width / 2, mapToItem(items, 0, y).y);
if (icon) {
popouts.currentName = icon.name;
@ -55,9 +53,10 @@ ColumnLayout {
popouts.hasCurrent = true;
}
} else if (id === "tray" && Config.bar.popouts.tray) {
if (!Config.bar.tray.compact || (item.expanded && !item.expandIcon.contains(mapToItem(item.expandIcon, item.implicitWidth / 2, y)))) {
const index = Math.floor(((y - top - item.padding * 2 + item.spacing) / item.layout.implicitHeight) * item.items.count);
const trayItem = item.items.itemAt(index);
const tray = ch.item as Tray;
if (!Config.bar.tray.compact || (tray.expanded && !tray.expandIcon.contains(mapToItem(tray.expandIcon, tray.implicitWidth / 2, y)))) {
const index = Math.floor(((y - top - tray.padding * 2 + tray.spacing) / tray.layout.implicitHeight) * tray.items.count);
const trayItem = tray.items.itemAt(index);
if (trayItem) {
popouts.currentName = `traymenu${index}`;
popouts.currentCenter = Qt.binding(() => trayItem.mapToItem(root, 0, trayItem.implicitHeight / 2).y);
@ -67,11 +66,11 @@ ColumnLayout {
}
} else {
popouts.hasCurrent = false;
item.expanded = true;
tray.expanded = true;
}
} else if (id === "activeWindow" && Config.bar.popouts.activeWindow && Config.bar.activeWindow.showOnHover) {
popouts.currentName = id.toLowerCase();
popouts.currentCenter = item.mapToItem(root, 0, itemHeight / 2).y;
popouts.currentCenter = (ch.item as Item).mapToItem(root, 0, (ch.item as Item).implicitHeight / 2).y ?? 0;
popouts.hasCurrent = true;
}
}

View file

@ -2,7 +2,7 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.config
import "popouts" as BarPopouts
import qs.modules.bar.popouts as BarPopouts
import Quickshell
import QtQuick
@ -22,15 +22,15 @@ Item {
property bool isHovered
function closeTray(): void {
content.item?.closeTray();
(content.item as Bar)?.closeTray();
}
function checkPopout(y: real): void {
content.item?.checkPopout(y);
(content.item as Bar)?.checkPopout(y);
}
function handleWheel(y: real, angleDelta: point): void {
content.item?.handleWheel(y, angleDelta);
(content.item as Bar)?.handleWheel(y, angleDelta);
}
visible: width > Config.border.thickness

View file

@ -20,13 +20,12 @@ StyledRect {
property real leading: workspaces.count > 0 ? workspaces.itemAt(currentWsIdx)?.y ?? 0 : 0
property real trailing: workspaces.count > 0 ? workspaces.itemAt(currentWsIdx)?.y ?? 0 : 0
property real currentSize: workspaces.count > 0 ? workspaces.itemAt(currentWsIdx)?.size ?? 0 : 0
property real currentSize: workspaces.count > 0 ? (workspaces.itemAt(currentWsIdx) as Workspace)?.size ?? 0 : 0
property real offset: Math.min(leading, trailing)
property real size: {
const s = Math.abs(leading - trailing) + currentSize;
if (Config.bar.workspaces.activeTrail && lastWs > currentWsIdx) {
const ws = workspaces.itemAt(lastWs);
// console.log(ws, lastWs);
const ws = workspaces.itemAt(lastWs) as Workspace;
return ws ? Math.min(ws.y + ws.size - offset, s) : 0;
}
return s;

View file

@ -15,7 +15,7 @@ Item {
required property ShellScreen screen
readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen)
readonly property string activeSpecial: (Config.bar.workspaces.perMonitorWorkspaces ? monitor : Hypr.focusedMonitor)?.lastIpcObject?.specialWorkspace?.name ?? ""
readonly property string activeSpecial: (Config.bar.workspaces.perMonitorWorkspaces ? monitor : Hypr.focusedMonitor)?.lastIpcObject.specialWorkspace?.name ?? ""
layer.enabled: true
layer.effect: OpacityMask {
@ -105,151 +105,14 @@ Item {
highlightFollowsCurrentItem: false
highlight: Item {
y: view.currentItem?.y ?? 0
implicitHeight: view.currentItem?.size ?? 0
implicitHeight: (view.currentItem as SpecialWsDelegate)?.size ?? 0
Behavior on y {
Anim {}
}
}
delegate: ColumnLayout {
id: ws
required property HyprlandWorkspace modelData
readonly property int size: label.Layout.preferredHeight + (hasWindows ? windows.implicitHeight + Appearance.padding.small : 0)
property int wsId
property string icon
property bool hasWindows
anchors.left: view.contentItem.left
anchors.right: view.contentItem.right
spacing: 0
Component.onCompleted: {
wsId = modelData.id;
icon = Icons.getSpecialWsIcon(modelData.name);
hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && modelData.lastIpcObject.windows > 0;
}
// Hacky thing cause modelData gets destroyed before the remove anim finishes
Connections {
function onIdChanged(): void {
if (ws.modelData)
ws.wsId = ws.modelData.id;
}
function onNameChanged(): void {
if (ws.modelData)
ws.icon = Icons.getSpecialWsIcon(ws.modelData.name);
}
function onLastIpcObjectChanged(): void {
if (ws.modelData)
ws.hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && ws.modelData.lastIpcObject.windows > 0;
}
target: ws.modelData
}
Connections {
function onShowWindowsOnSpecialWorkspacesChanged(): void {
if (ws.modelData)
ws.hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && ws.modelData.lastIpcObject.windows > 0;
}
target: Config.bar.workspaces
}
Loader {
id: label
asynchronous: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.preferredHeight: Config.bar.sizes.innerWidth - Appearance.padding.small * 2
sourceComponent: ws.icon.length === 1 ? letterComp : iconComp
Component {
id: iconComp
MaterialIcon {
fill: 1
text: ws.icon
verticalAlignment: Qt.AlignVCenter
}
}
Component {
id: letterComp
StyledText {
text: ws.icon
verticalAlignment: Qt.AlignVCenter
}
}
}
Loader {
id: windows
asynchronous: true
Layout.alignment: Qt.AlignHCenter
Layout.fillHeight: true
Layout.preferredHeight: implicitHeight
visible: active
active: ws.hasWindows
sourceComponent: Column {
spacing: 0
add: Transition {
Anim {
properties: "scale"
from: 0
to: 1
easing.bezierCurve: Appearance.anim.curves.standardDecel
}
}
move: Transition {
Anim {
properties: "scale"
to: 1
easing.bezierCurve: Appearance.anim.curves.standardDecel
}
Anim {
properties: "x,y"
}
}
Repeater {
model: ScriptModel {
values: {
const windows = Hypr.toplevels.values.filter(c => c.workspace?.id === ws.wsId);
const maxIcons = Config.bar.workspaces.maxWindowIcons;
return maxIcons > 0 ? windows.slice(0, maxIcons) : windows;
}
}
MaterialIcon {
required property var modelData
grade: 0
text: Icons.getAppCategoryIcon(modelData.lastIpcObject.class, "terminal")
color: Colours.palette.m3onSurfaceVariant
}
}
}
Behavior on Layout.preferredHeight {
Anim {}
}
}
}
delegate: SpecialWsDelegate {}
add: Transition {
Anim {
@ -296,6 +159,145 @@ Item {
}
}
component SpecialWsDelegate: ColumnLayout {
id: ws
required property HyprlandWorkspace modelData
readonly property int size: label.Layout.preferredHeight + (hasWindows ? windows.implicitHeight + Appearance.padding.small : 0)
property int wsId
property string icon
property bool hasWindows
anchors.left: view.contentItem.left
anchors.right: view.contentItem.right
spacing: 0
Component.onCompleted: {
wsId = modelData.id;
icon = Icons.getSpecialWsIcon(modelData.name);
hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && modelData.lastIpcObject.windows > 0;
}
// Hacky thing cause modelData gets destroyed before the remove anim finishes
Connections {
function onIdChanged(): void {
if (ws.modelData)
ws.wsId = ws.modelData.id;
}
function onNameChanged(): void {
if (ws.modelData)
ws.icon = Icons.getSpecialWsIcon(ws.modelData.name);
}
function onLastIpcObjectChanged(): void {
if (ws.modelData)
ws.hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && ws.modelData.lastIpcObject.windows > 0;
}
target: ws.modelData
}
Connections {
function onShowWindowsOnSpecialWorkspacesChanged(): void {
if (ws.modelData)
ws.hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && ws.modelData.lastIpcObject.windows > 0;
}
target: Config.bar.workspaces
}
Loader {
id: label
asynchronous: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.preferredHeight: Config.bar.sizes.innerWidth - Appearance.padding.small * 2
sourceComponent: ws.icon.length === 1 ? letterComp : iconComp
Component {
id: iconComp
MaterialIcon {
fill: 1
text: ws.icon
verticalAlignment: Qt.AlignVCenter
}
}
Component {
id: letterComp
StyledText {
text: ws.icon
verticalAlignment: Qt.AlignVCenter
}
}
}
Loader {
id: windows
asynchronous: true
Layout.alignment: Qt.AlignHCenter
Layout.fillHeight: true
Layout.preferredHeight: implicitHeight
visible: active
active: ws.hasWindows
sourceComponent: Column {
spacing: 0
add: Transition {
Anim {
properties: "scale"
from: 0
to: 1
easing.bezierCurve: Appearance.anim.curves.standardDecel
}
}
move: Transition {
Anim {
properties: "scale"
to: 1
easing.bezierCurve: Appearance.anim.curves.standardDecel
}
Anim {
properties: "x,y"
}
}
Repeater {
model: ScriptModel {
values: {
const windows = Hypr.toplevels.values.filter(c => c.workspace?.id === ws.wsId);
const maxIcons = Config.bar.workspaces.maxWindowIcons;
return maxIcons > 0 ? windows.slice(0, maxIcons) : windows;
}
}
MaterialIcon {
required property var modelData
grade: 0
text: Icons.getAppCategoryIcon(modelData.lastIpcObject.class, "terminal")
color: Colours.palette.m3onSurfaceVariant
}
}
}
Behavior on Layout.preferredHeight {
Anim {}
}
}
}
Loader {
asynchronous: true
active: Config.bar.workspaces.activeIndicator
@ -309,7 +311,7 @@ Item {
anchors.right: parent.right
y: (view.currentItem?.y ?? 0) - view.contentY
implicitHeight: view.currentItem?.size ?? 0
implicitHeight: (view.currentItem as SpecialWsDelegate)?.size ?? 0
color: Colours.palette.m3tertiary
radius: Appearance.rounding.full
@ -358,7 +360,7 @@ Item {
if (Math.abs(event.y - startY) > drag.threshold)
return;
const ws = view.itemAt(event.x, event.y);
const ws = view.itemAt(event.x, event.y) as SpecialWsDelegate;
if (ws?.modelData)
Hypr.dispatch(`togglespecialworkspace ${ws.modelData.name.slice(8)}`);
else

View file

@ -13,7 +13,7 @@ StyledClippingRect {
required property ShellScreen screen
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 var occupied: {
@ -92,7 +92,7 @@ StyledClippingRect {
MouseArea {
anchors.fill: layout
onClicked: event => {
const ws = layout.childAt(event.x, event.y).ws;
const ws = (layout.childAt(event.x, event.y) as Workspace)?.ws;
if (Hypr.activeWsId !== ws)
Hypr.dispatch(`workspace ${ws}`);
else

View file

@ -10,7 +10,7 @@ import QtQuick.Layouts
Item {
id: root
required property Item wrapper
required property PopoutState popouts
implicitWidth: Hypr.activeToplevel ? child.implicitWidth : -Appearance.padding.large * 2
implicitHeight: child.implicitHeight
@ -66,7 +66,7 @@ Item {
StateLayer {
function onClicked(): void {
root.wrapper.detach("winfo");
root.popouts.detachRequested("winfo");
}
radius: Appearance.rounding.normal

View file

@ -12,7 +12,7 @@ import QtQuick.Controls
Item {
id: root
required property var wrapper
required property PopoutState popouts
implicitWidth: layout.implicitWidth + Appearance.padding.normal * 2
implicitHeight: layout.implicitHeight + Appearance.padding.normal * 2
@ -112,7 +112,7 @@ Item {
text: qsTr("Open settings")
icon: "settings"
onClicked: root.wrapper.detach("audio")
onClicked: root.popouts.detachRequested("audio")
}
}
}

View file

@ -42,7 +42,7 @@ Column {
active: PowerProfiles.degradationReason !== PerformanceDegradationReason.None
height: active ? (item?.implicitHeight ?? 0) : 0
height: active ? ((item as Item)?.implicitHeight ?? 0) : 0
sourceComponent: StyledRect {
implicitWidth: child.implicitWidth + Appearance.padding.normal * 2

View file

@ -13,7 +13,7 @@ import QtQuick.Layouts
ColumnLayout {
id: root
required property Item wrapper
required property PopoutState popouts
spacing: Appearance.spacing.small
@ -173,7 +173,7 @@ ColumnLayout {
text: qsTr("Open settings")
icon: "settings"
onClicked: root.wrapper.detach("bluetooth")
onClicked: root.popouts.detachRequested("bluetooth")
}
component Toggle: RowLayout {

View file

@ -11,7 +11,7 @@ import "./kblayout"
Item {
id: root
required property Item wrapper
required property PopoutState popouts
readonly property Popout currentPopout: content.children.find(c => c.shouldBeActive) ?? null
readonly property Item current: currentPopout?.item ?? null
@ -29,7 +29,7 @@ Item {
Popout {
name: "activewindow"
sourceComponent: ActiveWindow {
wrapper: root.wrapper
popouts: root.popouts
}
}
@ -38,7 +38,7 @@ Item {
name: "network"
sourceComponent: Network {
wrapper: root.wrapper
popouts: root.popouts
view: "wireless"
}
}
@ -46,7 +46,7 @@ Item {
Popout {
name: "ethernet"
sourceComponent: Network {
wrapper: root.wrapper
popouts: root.popouts
view: "ethernet"
}
}
@ -58,39 +58,39 @@ Item {
sourceComponent: WirelessPassword {
id: passwordComponent
wrapper: root.wrapper
network: networkPopout.item?.passwordNetwork ?? null
popouts: root.popouts
network: (networkPopout.item as Network)?.passwordNetwork ?? null
}
Connections {
function onCurrentNameChanged() {
// Update network immediately when password popout becomes active
if (root.wrapper.currentName === "wirelesspassword") {
if (root.popouts.currentName === "wirelesspassword") {
// Set network immediately if available
if (networkPopout.item && networkPopout.item.passwordNetwork) {
if ((networkPopout.item as Network)?.passwordNetwork) {
if (passwordPopout.item) {
passwordPopout.item.network = networkPopout.item.passwordNetwork;
(passwordPopout.item as WirelessPassword).network = (networkPopout.item as Network).passwordNetwork;
}
}
// Also try after a short delay in case networkPopout.item wasn't ready
Qt.callLater(() => {
if (passwordPopout.item && networkPopout.item && networkPopout.item.passwordNetwork) {
passwordPopout.item.network = networkPopout.item.passwordNetwork;
if (passwordPopout.item && (networkPopout.item as Network)?.passwordNetwork) {
(passwordPopout.item as WirelessPassword).network = (networkPopout.item as Network).passwordNetwork;
}
}, 100);
}
}
target: root.wrapper
target: root.popouts
}
Connections {
function onItemChanged() {
// When network popout loads, update password popout if it's active
if (root.wrapper.currentName === "wirelesspassword" && passwordPopout.item) {
if (root.popouts.currentName === "wirelesspassword" && passwordPopout.item) {
Qt.callLater(() => {
if (networkPopout.item && networkPopout.item.passwordNetwork) {
passwordPopout.item.network = networkPopout.item.passwordNetwork;
if ((networkPopout.item as Network)?.passwordNetwork) {
(passwordPopout.item as WirelessPassword).network = (networkPopout.item as Network).passwordNetwork;
}
});
}
@ -103,7 +103,7 @@ Item {
Popout {
name: "bluetooth"
sourceComponent: Bluetooth {
wrapper: root.wrapper
popouts: root.popouts
}
}
@ -115,15 +115,13 @@ Item {
Popout {
name: "audio"
sourceComponent: Audio {
wrapper: root.wrapper
popouts: root.popouts
}
}
Popout {
name: "kblayout"
sourceComponent: KbLayout {
wrapper: root.wrapper
}
sourceComponent: KbLayout {}
}
Popout {
@ -147,21 +145,21 @@ Item {
Connections {
function onHasCurrentChanged(): void {
if (root.wrapper.hasCurrent && trayMenu.shouldBeActive) {
if (root.popouts.hasCurrent && trayMenu.shouldBeActive) {
trayMenu.sourceComponent = null;
trayMenu.sourceComponent = trayMenuComp;
}
}
target: root.wrapper
target: root.popouts
}
Component {
id: trayMenuComp
TrayMenu {
popouts: root.wrapper
trayItem: trayMenu.modelData.menu
popouts: root.popouts
trayItem: trayMenu.modelData.menu // qmllint disable unresolved-type
}
}
}
@ -172,7 +170,7 @@ Item {
id: popout
required property string name
readonly property bool shouldBeActive: root.wrapper.currentName === name
readonly property bool shouldBeActive: root.popouts.currentName === name
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right

View file

@ -12,7 +12,7 @@ import QtQuick.Layouts
ColumnLayout {
id: root
required property Item wrapper
required property PopoutState popouts
property string connectingToSsid: ""
property string view: "wireless" // "wireless" or "ethernet"
@ -132,7 +132,7 @@ ColumnLayout {
// Password is required - show password dialog
root.passwordNetwork = network;
root.showPasswordDialog = true;
root.wrapper.currentName = "wirelesspassword";
root.popouts.currentName = "wirelesspassword";
});
// Clear connecting state if connection succeeds immediately (saved profile)
@ -341,8 +341,8 @@ ColumnLayout {
if (root.showPasswordDialog && root.passwordNetwork && Nmcli.active.ssid === root.passwordNetwork.ssid) {
root.showPasswordDialog = false;
root.passwordNetwork = null;
if (root.wrapper.currentName === "wirelesspassword") {
root.wrapper.currentName = "network";
if (root.popouts.currentName === "wirelesspassword") {
root.popouts.currentName = "network";
}
}
}
@ -359,13 +359,13 @@ ColumnLayout {
Connections {
function onCurrentNameChanged(): void {
// Clear password network when leaving password dialog
if (root.wrapper.currentName !== "wirelesspassword" && root.showPasswordDialog) {
if (root.popouts.currentName !== "wirelesspassword" && root.showPasswordDialog) {
root.showPasswordDialog = false;
root.passwordNetwork = null;
}
}
target: root.wrapper
target: root.popouts
}
component Toggle: RowLayout {

View file

@ -0,0 +1,8 @@
import QtQuick
QtObject {
property string currentName
property bool hasCurrent
signal detachRequested(mode: string)
}

View file

@ -11,7 +11,7 @@ import QtQuick.Controls
StackView {
id: root
required property Item popouts
required property PopoutState popouts
required property QsMenuHandle trayItem
implicitWidth: currentItem?.implicitWidth ?? 0

View file

@ -12,11 +12,11 @@ import QtQuick.Layouts
ColumnLayout {
id: root
required property Item wrapper
required property PopoutState popouts
property var network: null
property bool isClosing: false
readonly property bool shouldBeVisible: root.wrapper.currentName === "wirelesspassword"
readonly property bool shouldBeVisible: root.popouts.currentName === "wirelesspassword"
function checkConnectionStatus(): void {
if (!root.shouldBeVisible || !connectButton.connecting) {
@ -64,8 +64,8 @@ ColumnLayout {
connectionMonitor.stop();
// Return to network popout
if (root.wrapper.currentName === "wirelesspassword") {
root.wrapper.currentName = "network";
if (root.popouts.currentName === "wirelesspassword") {
root.popouts.currentName = "network";
}
}
@ -94,7 +94,7 @@ ColumnLayout {
Connections {
function onCurrentNameChanged() {
if (root.wrapper.currentName === "wirelesspassword") {
if (root.popouts.currentName === "wirelesspassword") {
// Update network when popout becomes active
Qt.callLater(() => {
// Try to get network from parent Content's networkPopout
@ -112,7 +112,7 @@ ColumnLayout {
}
}
target: root.wrapper
target: root.popouts
}
Timer {
@ -578,8 +578,8 @@ ColumnLayout {
connectButton.connecting = false;
connectButton.text = qsTr("Connect");
// Return to network popout on successful connection
if (root.wrapper.currentName === "wirelesspassword") {
root.wrapper.currentName = "network";
if (root.popouts.currentName === "wirelesspassword") {
root.popouts.currentName = "network";
}
closeDialog();
}

View file

@ -17,11 +17,12 @@ Item {
readonly property real nonAnimWidth: x > 0 || hasCurrent ? children.find(c => c.shouldBeActive)?.implicitWidth ?? content.implicitWidth : 0
readonly property real nonAnimHeight: children.find(c => c.shouldBeActive)?.implicitHeight ?? content.implicitHeight
readonly property Item current: content.item?.current ?? null
readonly property Item current: (content.item as Content)?.current ?? null
property string currentName
property alias currentName: popoutState.currentName
property real currentCenter
property bool hasCurrent
property alias hasCurrent: popoutState.hasCurrent
readonly property PopoutState state: popoutState
property string detachedMode
property string queuedMode
@ -59,7 +60,7 @@ Item {
Keys.onEscapePressed: {
// Forward escape to password popout if active, otherwise close
if (currentName === "wirelesspassword" && content.item) {
const passwordPopout = content.item.children.find(c => c.name === "wirelesspassword");
const passwordPopout = (content.item as Content)?.children.find(c => c.name === "wirelesspassword");
if (passwordPopout && passwordPopout.item) {
passwordPopout.item.closeDialog();
return;
@ -75,6 +76,12 @@ Item {
}
}
PopoutState {
id: popoutState
onDetachRequested: mode => root.detach(mode)
}
HyprlandFocusGrab {
active: root.isDetached
windows: [QsWindow.window]
@ -105,7 +112,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
sourceComponent: Content {
wrapper: root
popouts: popoutState
}
}

View file

@ -7,13 +7,9 @@ import qs.components
import qs.services
import qs.config
import "."
ColumnLayout {
id: root
required property Item wrapper
function refresh() {
kb.refresh();
}