/* SPDX-FileCopyrightText: 2020 Marco Martin SPDX-FileCopyrightText: 2023 ivan tkachenko SPDX-License-Identifier: LGPL-2.0-or-later */ import QtQuick import QtQuick.Controls as QQC2 import org.kde.kirigami as Kirigami /** * This component is intended to be used as root item for * KCMs with arbitrary content. Unlike SimpleKCM this does NOT * provide a scrollable view, The developer will have to manage * their own scrollviews. * Most of the times SimpleKCM should be used instead * @code * import QtQuick * import QtQuick.Controls as QQC2 * import QtQuick.Layouts * import org.kde.kcmutils as KCMUtils * * KCMUtils.AbstractKCM { * RowLayout { * QQC2.ScrollView { } * QQC2.ScrollView { } * } * footer: QQC2.ToolBar { } * } * @endcode * @inherits org.kde.kirigami.Page * @since 6.0 */ Kirigami.Page { id: root readonly property int margins: 6 // Layout_ChildMarginWidth from Breeze /** * framedView: bool * Whether to use this component as the base of a "framed" KCM with an * inner scrollview that draws its own frame. * Default: true */ property bool framedView: true /** * extraFooterTopPadding: bool * Whether the footer should have extra space and a separator line drawn * above it. Set this to true in a KCM with a custom footer and a ListView * immediately above it. * Default: false */ property bool extraFooterTopPadding: false /** * headerPaddingEnabled: bool * Whether the contents of the header will have automatic padding around it. * Should be disabled when using an InlineMessage or custom content item in * the header that's intended to touch the window edges. * Default: true */ property bool headerPaddingEnabled: true /** * footerPaddingEnabled: bool * Whether the contents of the footer will have automatic padding around it. * Should be disabled when using an InlineMessage or custom content item in * the footer that's intended to touch the window edges. * Default: true */ property bool footerPaddingEnabled: true property bool sidebarMode: false function __itemVisible(item: Item): bool { return item !== null && item.visible && item.implicitHeight > 0; } function __headerContentVisible(): bool { return __itemVisible(headerParent.contentItem); } function __footerContentVisible(): bool { return __itemVisible(footerParent.contentItem); } // Deliberately not checking for __footerContentVisible because // we always want the footer line to be visible when the scrollview // doesn't have a frame of its own, because System Settings always // adds its own footer for the Apply, Help, and Defaults buttons function __headerSeparatorVisible(): bool { return !framedView && __headerContentVisible(); } function __footerSeparatorVisible(): bool { return !framedView && extraFooterTopPadding; } title: (typeof kcm !== "undefined") ? kcm.name : "" // Make pages fill the whole view by default Kirigami.ColumnView.fillWidth: sidebarMode ? Kirigami.ColumnView.view && (Kirigami.ColumnView.view.width < Kirigami.Units.gridUnit * 36 || Kirigami.ColumnView.index >= Kirigami.ColumnView.view.count - 1) : true padding: 0 topPadding: framedView && !__headerContentVisible() ? margins : 0 leftPadding: undefined rightPadding: undefined bottomPadding: framedView && !__footerContentVisible() ? margins : 0 verticalPadding: undefined horizontalPadding: framedView ? margins : 0 header: Column { Kirigami.Padding { id: headerParent anchors { left: parent.left right: parent.right } height: root.__headerContentVisible() ? undefined : 0 padding: root.headerPaddingEnabled ? root.margins : 0 } // When the scrollview isn't drawing its own frame, we need to add a // line below the header (when visible) to separate it from the view Kirigami.Separator { anchors { left: parent.left right: parent.right } visible: root.__headerSeparatorVisible() } } // View background, shown when the scrollview isn't drawing its own frame Rectangle { anchors.fill: parent visible: !root.framedView Kirigami.Theme.colorSet: Kirigami.Theme.View Kirigami.Theme.inherit: false color: Kirigami.Theme.backgroundColor } footer: Column { // When the scrollview isn't drawing its own frame, we need to add a // line above the footer ourselves to separate it from the view Kirigami.Separator { anchors { left: parent.left right: parent.right } visible: root.__footerSeparatorVisible() } Kirigami.Padding { id: footerParent anchors { left: parent.left right: parent.right } height: root.__footerContentVisible() ? undefined : 0 padding: root.footerPaddingEnabled ? root.margins : 0 } } function __swapContentIntoContainer(property: string, container: Item): void { const content = this[property]; const rootContainer = container.parent; if (content && content !== rootContainer) { // Revert the effect of repeated onHeaderChanged invocations // during initialization in Page super-type. content.anchors.top = undefined; this[property] = rootContainer; container.contentItem = content; } } function __adoptOverlaySheets(): void { // Search overlaysheets in contentItem, parent to root if found for (const object of contentItem.data) { if (object instanceof Kirigami.OverlaySheet) { if (object.parent === null) { object.parent = this; } data.push(object); } } } Component.onCompleted: { __swapContentIntoContainer("header", headerParent); __swapContentIntoContainer("footer", footerParent); __adoptOverlaySheets(); } }