diff --git a/examples/swipenavigator/main.qml b/examples/swipenavigator/main.qml index 9326cda7..59db2315 100644 --- a/examples/swipenavigator/main.qml +++ b/examples/swipenavigator/main.qml @@ -1,27 +1,26 @@ import QtQuick 2.0 import org.kde.kirigami 2.13 as Kirigami Kirigami.ApplicationWindow { Kirigami.SwipeNavigator { anchors.fill: parent - largeHeader: false Kirigami.Page { icon.name: "globe" title: "World Clocks" } Kirigami.Page { icon.name: "clock" title: "Alarms" needsAttention: true } Kirigami.Page { icon.name: "clock" title: "Stopwatch" } Kirigami.Page { icon.name: "clock" title: "Timers" progress: 0.5 } } } diff --git a/src/controls/SwipeNavigator.qml b/src/controls/SwipeNavigator.qml deleted file mode 100644 index 93271463..00000000 --- a/src/controls/SwipeNavigator.qml +++ /dev/null @@ -1,225 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Carson Black - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 -import org.kde.kirigami 2.12 as Kirigami -import "private" as Private - -// We use a single-column GridLayout to allow using Layout.row for mobile -/** - * SwipeNavigator is a control providing for lateral navigation. - * - * @include swipenavigator/main.qml - */ -GridLayout { - id: swipeNavigatorRoot - rowSpacing: 0 - columns: 1 - - /** - * pages: list - * - * A list of pages to swipe between. - */ - default property list pages - - /** - * largeHeader: bool - * - * Whether this SwipeNavigator should use a larger header than normal. Designed - * for usage on televisions. - */ - property bool largeHeader: false - - /** - * layers: StackView - * - * The StackView holding the core item, allowing users of a SwipeNavigator - * in order to push pages on top of the SwipeNavigator. - */ - property alias layers: stackView - - ToolBar { - id: topToolBar - - padding: 0 - bottomPadding: 1 - position: Kirigami.Settings.isMobile ? ToolBar.Footer : ToolBar.Header - - Layout.row: Kirigami.Settings.isMobile ? 1 : 0 - - states: [ - State { - name: "small" - when: largeBar.implicitWidth > topToolBar.width - }, - State { - name: "large" - when: largeBar.implicitWidth <= topToolBar.width - } - ] - - Private.SwipeTabBar { - visible: topToolBar.state == "large" - id: largeBar - anchors { - top: parent.top - bottom: parent.bottom - horizontalCenter: parent.horizontalCenter - } - } - - Private.SwipeTabBar { - id: smallBar - visible: topToolBar.state == "small" - small: true - property bool tooBig: topToolBar.width < this.implicitWidth - parent: tooBig ? _scroll : topToolBar - anchors { - top: tooBig ? undefined : parent.top - bottom: tooBig ? undefined : parent.bottom - horizontalCenter: tooBig ? undefined : parent.horizontalCenter - } - onIndexChanged: { - if (tooBig) { - _scroll.ScrollBar.horizontal.position = xPos/smallBar.width - } - } - } - - ScrollView { - id: _scroll - anchors.fill: parent - contentWidth: smallBar.implicitWidth - clip: false - contentChildren: smallBar.tooBig ? [smallBar] : [] - ScrollBar.horizontal.visible: false - } - - Layout.preferredHeight: { - if (swipeNavigatorRoot.largeHeader) { - return Kirigami.Units.gridUnit*4 - } else if (topToolBar.state == "small") { - return Kirigami.Units.gridUnit*3 - } - return -1 - } - Layout.fillWidth: true - - Accessible.role: Accessible.PageTabList - } - - StackView { - id: stackView - - Layout.fillWidth: true - Layout.fillHeight: true - - Layout.row: Kirigami.Settings.isMobile ? 0 : 1 - - popEnter: Transition { - OpacityAnimator { - from: 0 - to: 1 - duration: Units.longDuration - easing.type: Easing.InOutCubic - } - } - popExit: Transition { - ParallelAnimation { - OpacityAnimator { - from: 1 - to: 0 - duration: Units.longDuration - easing.type: Easing.InOutCubic - } - YAnimator { - from: 0 - to: height/2 - duration: Units.longDuration - easing.type: Easing.InCubic - } - } - } - - pushEnter: Transition { - ParallelAnimation { - //NOTE: It's a PropertyAnimation instead of an Animator because with an animator the item will be visible for an instant before starting to fade - PropertyAnimation { - property: "opacity" - from: 0 - to: 1 - duration: Units.longDuration - easing.type: Easing.InOutCubic - } - YAnimator { - from: height/2 - to: 0 - duration: Units.longDuration - easing.type: Easing.OutCubic - } - } - } - - - pushExit: Transition { - OpacityAnimator { - from: 1 - to: 0 - duration: Units.longDuration - easing.type: Easing.InOutCubic - } - } - - replaceEnter: Transition { - ParallelAnimation { - OpacityAnimator { - from: 0 - to: 1 - duration: Units.longDuration - easing.type: Easing.InOutCubic - } - YAnimator { - from: height/2 - to: 0 - duration: Units.longDuration - easing.type: Easing.OutCubic - } - } - } - - replaceExit: Transition { - ParallelAnimation { - OpacityAnimator { - from: 1 - to: 0 - duration: Units.longDuration - easing.type: Easing.InCubic - } - YAnimator { - from: 0 - to: -height/2 - duration: Units.longDuration - easing.type: Easing.InOutCubic - } - } - } - - Kirigami.ColumnView { - id: columnView - columnResizeMode: Kirigami.ColumnView.SingleColumn - - contentChildren: swipeNavigatorRoot.pages - anchors.fill: parent - - Component.onCompleted: { - columnView.currentIndex = 0 - } - } - } -} diff --git a/src/controls/private/SwipeTabBar.qml b/src/controls/private/SwipeTabBar.qml deleted file mode 100644 index 78ffc3fa..00000000 --- a/src/controls/private/SwipeTabBar.qml +++ /dev/null @@ -1,217 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Carson Black - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -import QtQuick 2.12 -import QtQuick.Layouts 1.12 -import QtQuick.Controls 2.12 -import org.kde.kirigami 2.12 as Kirigami - -RowLayout { - id: swipeTabBarRoot - property bool small: false - - spacing: 0 - signal indexChanged(real xPos) - - Repeater { - model: swipeNavigatorRoot.pages - Rectangle { - id: tabRoot - - Keys.onPressed: { - if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { - columnView.currentIndex = index - } - } - activeFocusOnTab: true - - Connections { - target: columnView - function onCurrentIndexChanged() { - if (index == columnView.currentIndex) { - swipeTabBarRoot.indexChanged(tabRoot.x) - } - } - } - - Accessible.name: modelData.title - Accessible.description: { - if (!!modelData.progress) { - if (index == columnView.currentIndex) { - return i18nc("Accessibility text for a page tab. Keep the text as concise as possible and don't use a percent sign.", "Current page. Progress: %1 percent.", Math.round(modelData.progress*100)) - } else { - return i18nc("Accessibility text for a page tab. Keep the text as concise as possible.", "Navigate to %1. Progress: %1 percent.", modelData.title, Math.round(modelData.progress*100)) - } - } else { - if (index == columnView.currentIndex) { - return i18nc("Accessibility text for a page tab. Keep the text as concise as possible.", "Current page.") - } else if (modelData.needsAttention) { - return i18nc("Accessibility text for a page tab that's requesting the user's attention. Keep the text as concise as possible.", "Navigate to %1. Demanding attention.", modelData.title) - } else { - return i18nc("Accessibility text for a page tab that's requesting the user's attention. Keep the text as concise as possible.", "Navigate to %1.", modelData.title) - } - } - } - Accessible.role: Accessible.PageTab - Accessible.focusable: true - Accessible.onPressAction: columnView.currentIndex = index - - implicitWidth: largeTitleRow.implicitWidth - border { - width: activeFocus ? 2 : 0 - color: Kirigami.Theme.textColor - } - color: { - if (index == columnView.currentIndex) { - return Kirigami.ColorUtils.adjustColor(Kirigami.Theme.activeTextColor, {"alpha": 0.2*255}) - } else if (modelData.needsAttention) { - return Kirigami.ColorUtils.adjustColor(Kirigami.Theme.negativeTextColor, {"alpha": 0.2*255}) - } else { - return "transparent" - } - } - - Rectangle { - Accessible.ignored: true - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - } - - color: { - if (index == columnView.currentIndex) { - return Kirigami.Theme.activeTextColor - } else if (modelData.needsAttention) { - return Kirigami.Theme.negativeTextColor - } else { - return "transparent" - } - } - - // Unlike most things, we don't want to scale with the em grid, so we don't use a Unit. - height: 2 - } - - Rectangle { - Accessible.ignored: true - visible: !!modelData.progress - - anchors { - top: parent.top - bottom: parent.bottom - left: parent.left - } - width: parent.width * modelData.progress - color: Kirigami.ColorUtils.adjustColor(Kirigami.Theme.positiveTextColor, {"alpha": 0.2*255}) - - Rectangle { - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - } - - color: Kirigami.Theme.positiveTextColor - - // Unlike most things, we don't want to scale with the em grid, so we don't use a Unit. - height: 2 - } - } - - - Rectangle { - Accessible.ignored: true - visible: !!modelData.progress - - anchors { - top: parent.top - bottom: parent.bottom - right: parent.right - } - width: parent.width - (parent.width * modelData.progress) - color: Kirigami.ColorUtils.adjustColor(Kirigami.Theme.textColor, {"alpha": 0.1*255}) - - Rectangle { - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - } - - color: Kirigami.ColorUtils.adjustColor(Kirigami.Theme.textColor, {"alpha": 0.1*255}) - - // Unlike most things, we don't want to scale with the em grid, so we don't use a Unit. - height: 2 - } - } - - RowLayout { - id: largeTitleRow - anchors.fill: parent - Accessible.ignored: true - - GridLayout { - Layout.margins: Kirigami.Units.largeSpacing - Layout.alignment: Qt.AlignVCenter - - columns: 2 - rows: 2 - - flow: swipeTabBarRoot.small ? GridLayout.TopToBottom : GridLayout.LeftToRight - - Kirigami.Icon { - visible: !!modelData.icon.name - source: modelData.icon.name - - Layout.preferredHeight: swipeNavigatorRoot.largeHeader ? Kirigami.Units.iconSizes.medium : Kirigami.Units.iconSizes.small - Layout.preferredWidth: Layout.preferredHeight - - Layout.alignment: swipeTabBarRoot.small ? Qt.AlignHCenter : (Qt.AlignLeft | Qt.AlignVCenter) - } - Kirigami.Heading { - level: { - if (swipeNavigatorRoot.largeHeader) { - return 1 - } else if (swipeTabBarRoot.small) { - return 5 - } - return 2 - } - fontSizeMode: { - if (swipeNavigatorRoot.largeHeader) { - return Text.FixedSize - } else if (swipeTabBarRoot.small) { - return Text.HorizontalFit - } - return Text.FixedSize - } - text: modelData.title - // We fall back to Font.Normal, which will override user - // font choices. Not ideal, but there doesn't seem to be - // a way to reset this property. - font.weight: modelData.needsAttention ? Font.Black : Font.Normal - - Layout.fillWidth: true - Layout.alignment: swipeTabBarRoot.small ? Qt.AlignHCenter : (Qt.AlignLeft | Qt.AlignVCenter) - } - } - } - - MouseArea { - id: mouse - anchors.fill: parent - Accessible.ignored: true - onClicked: { - columnView.currentIndex = index - } - } - - Layout.fillHeight: true - Layout.alignment: Qt.AlignHCenter - } - } -} diff --git a/src/controls/swipenavigator/PrivateSwipeHighlight.qml b/src/controls/swipenavigator/PrivateSwipeHighlight.qml new file mode 100644 index 00000000..8abdb185 --- /dev/null +++ b/src/controls/swipenavigator/PrivateSwipeHighlight.qml @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2020 Carson Black + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 +import org.kde.kirigami 2.12 as Kirigami + +Rectangle { + Accessible.ignored: true + + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + + color: { + if (state == "highlighted") { + return Kirigami.Theme.activeTextColor + } else if (state == "requestingAttention") { + return Kirigami.Theme.negativeTextColor + } + return "transparent" + } + + // Unlike most things, we don't want to scale with the em grid, so we don't use a Unit. + height: 2 +} \ No newline at end of file diff --git a/src/controls/swipenavigator/PrivateSwipeProgress.qml b/src/controls/swipenavigator/PrivateSwipeProgress.qml new file mode 100644 index 00000000..950d37f2 --- /dev/null +++ b/src/controls/swipenavigator/PrivateSwipeProgress.qml @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: 2020 Carson Black + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 +import org.kde.kirigami 2.12 as Kirigami + +Item { + id: __progressRoot + property var progress + + Rectangle { + Accessible.ignored: true + + anchors { + top: parent.top + bottom: parent.bottom + left: parent.left + } + width: parent.width * __progressRoot.progress + color: Kirigami.ColorUtils.adjustColor(Kirigami.Theme.positiveTextColor, {"alpha": 0.2*255}) + + Rectangle { + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + + color: Kirigami.Theme.positiveTextColor + + // Unlike most things, we don't want to scale with the em grid, so we don't use a Unit. + height: 2 + } + } + + + Rectangle { + Accessible.ignored: true + + anchors { + top: parent.top + bottom: parent.bottom + right: parent.right + } + width: parent.width - (parent.width * __progressRoot.progress) + color: Kirigami.ColorUtils.adjustColor(Kirigami.Theme.textColor, {"alpha": 0.1*255}) + + Rectangle { + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + + color: Kirigami.ColorUtils.adjustColor(Kirigami.Theme.textColor, {"alpha": 0.1*255}) + + // Unlike most things, we don't want to scale with the em grid, so we don't use a Unit. + height: 2 + } + } +} \ No newline at end of file diff --git a/src/controls/swipenavigator/PrivateSwipeStack.qml b/src/controls/swipenavigator/PrivateSwipeStack.qml new file mode 100644 index 00000000..76f8e9c2 --- /dev/null +++ b/src/controls/swipenavigator/PrivateSwipeStack.qml @@ -0,0 +1,100 @@ +/* + * SPDX-FileCopyrightText: 2020 Carson Black + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 +import org.kde.kirigami 2.12 as Kirigami + +StackView { + popEnter: Transition { + OpacityAnimator { + from: 0 + to: 1 + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutCubic + } + } + popExit: Transition { + ParallelAnimation { + OpacityAnimator { + from: 1 + to: 0 + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutCubic + } + YAnimator { + from: 0 + to: height/2 + duration: Kirigami.Units.longDuration + easing.type: Easing.InCubic + } + } + } + + pushEnter: Transition { + ParallelAnimation { + //NOTE: It's a PropertyAnimation instead of an Animator because with an animator the item will be visible for an instant before starting to fade + PropertyAnimation { + property: "opacity" + from: 0 + to: 1 + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutCubic + } + YAnimator { + from: height/2 + to: 0 + duration: Kirigami.Units.longDuration + easing.type: Easing.OutCubic + } + } + } + + + pushExit: Transition { + OpacityAnimator { + from: 1 + to: 0 + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutCubic + } + } + + replaceEnter: Transition { + ParallelAnimation { + OpacityAnimator { + from: 0 + to: 1 + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutCubic + } + YAnimator { + from: height/2 + to: 0 + duration: Kirigami.Units.longDuration + easing.type: Easing.OutCubic + } + } + } + + replaceExit: Transition { + ParallelAnimation { + OpacityAnimator { + from: 1 + to: 0 + duration: Kirigami.Units.longDuration + easing.type: Easing.InCubic + } + YAnimator { + from: 0 + to: -height/2 + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutCubic + } + } + } +} \ No newline at end of file diff --git a/src/controls/swipenavigator/PrivateSwipeTab.qml b/src/controls/swipenavigator/PrivateSwipeTab.qml new file mode 100644 index 00000000..ab83bcba --- /dev/null +++ b/src/controls/swipenavigator/PrivateSwipeTab.qml @@ -0,0 +1,120 @@ +/* + * SPDX-FileCopyrightText: 2020 Carson Black + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 +import org.kde.kirigami 2.12 as Kirigami + +Rectangle { + id: tabRoot + + Keys.onPressed: { + if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + columnView.currentIndex = index + } + } + activeFocusOnTab: true + + Connections { + target: columnView + function onCurrentIndexChanged() { + if (index == columnView.currentIndex) { + swipeTabBarRoot.indexChanged(tabRoot.x) + } + } + } + + Accessible.name: modelData.title + Accessible.description: { + if (!!modelData.progress) { + if (index == columnView.currentIndex) { + return i18nc("Accessibility text for a page tab. Keep the text as concise as possible and don't use a percent sign.", "Current page. Progress: %1 percent.", Math.round(modelData.progress*100)) + } else { + return i18nc("Accessibility text for a page tab. Keep the text as concise as possible.", "Navigate to %1. Progress: %1 percent.", modelData.title, Math.round(modelData.progress*100)) + } + } else { + if (index == columnView.currentIndex) { + return i18nc("Accessibility text for a page tab. Keep the text as concise as possible.", "Current page.") + } else if (modelData.needsAttention) { + return i18nc("Accessibility text for a page tab that's requesting the user's attention. Keep the text as concise as possible.", "Navigate to %1. Demanding attention.", modelData.title) + } else { + return i18nc("Accessibility text for a page tab that's requesting the user's attention. Keep the text as concise as possible.", "Navigate to %1.", modelData.title) + } + } + } + Accessible.role: Accessible.PageTab + Accessible.focusable: true + Accessible.onPressAction: columnView.currentIndex = index + + implicitWidth: largeTitleRow.implicitWidth + border { + width: activeFocus ? 2 : 0 + color: Kirigami.Theme.textColor + } + color: { + if (index == columnView.currentIndex) { + return Kirigami.ColorUtils.adjustColor(Kirigami.Theme.activeTextColor, {"alpha": 0.2*255}) + } else if (modelData.needsAttention) { + return Kirigami.ColorUtils.adjustColor(Kirigami.Theme.negativeTextColor, {"alpha": 0.2*255}) + } else { + return "transparent" + } + } + + PrivateSwipeHighlight { + states: [ + State { name: "highlighted"; when: index == columnView.currentIndex }, + State { name: "requestingAttention"; when: modelData.needsAttention } + ] + } + + PrivateSwipeProgress { + anchors.fill: parent + visible: modelData.progress != undefined + progress: modelData.progress + } + + RowLayout { + id: largeTitleRow + anchors.fill: parent + Accessible.ignored: true + + RowLayout { + Layout.margins: Kirigami.Units.largeSpacing + Layout.alignment: Qt.AlignVCenter + + Kirigami.Icon { + visible: !!modelData.icon.name + source: modelData.icon.name + + Layout.preferredHeight: Kirigami.Units.iconSizes.small + Layout.preferredWidth: Layout.preferredHeight + + Layout.alignment: (Qt.AlignLeft | Qt.AlignVCenter) + } + Kirigami.Heading { + level: 2 + text: modelData.title + + Layout.fillWidth: true + Layout.alignment: (Qt.AlignLeft | Qt.AlignVCenter) + } + } + } + + MouseArea { + id: mouse + anchors.fill: parent + Accessible.ignored: true + onClicked: { + columnView.currentIndex = index + } + } + + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter +} \ No newline at end of file diff --git a/src/controls/swipenavigator/PrivateSwipeTabBar.qml b/src/controls/swipenavigator/PrivateSwipeTabBar.qml new file mode 100644 index 00000000..9649b721 --- /dev/null +++ b/src/controls/swipenavigator/PrivateSwipeTabBar.qml @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2020 Carson Black + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 +import org.kde.kirigami 2.12 as Kirigami + +RowLayout { + id: swipeTabBarRoot + property bool small: false + + spacing: 0 + signal indexChanged(real xPos) + + Repeater { + model: swipeNavigatorRoot.pages + delegate: PrivateSwipeTab { + Layout.fillHeight: true + } + } +} diff --git a/src/controls/swipenavigator/SwipeNavigator.qml b/src/controls/swipenavigator/SwipeNavigator.qml new file mode 100644 index 00000000..1bd0648d --- /dev/null +++ b/src/controls/swipenavigator/SwipeNavigator.qml @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2020 Carson Black + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.12 +import org.kde.kirigami 2.13 as Kirigami + +/** + * SwipeNavigator is a control providing for lateral navigation. + * + * @include swipenavigator/main.qml + */ +GridLayout { + id: swipeNavigatorRoot + rowSpacing: 0 + columns: 1 + + /** + * pages: list + * + * A list of pages to swipe between. + */ + default property list pages + + /** + * type: int + * + * What type of SwipeNavigator this is. + * * `Kirigami.SwipeNavigatorType.Top`: this SwipeNavigator presents its UI as a top bar. + * * `Kirigami.SwipeNavigatorType.Left`: this SwipeNavigator presents its UI as a sidebar or drawer depending on available width. + */ + property int type: Kirigami.SwipeNavigatorType.Top + + /** + * layers: StackView + * + * The StackView holding the core item, allowing users of a SwipeNavigator + * in order to push pages on top of the SwipeNavigator. + */ + property alias layers: stackView + + ToolBar { + id: topToolBar + + padding: 0 + bottomPadding: 1 + position: Kirigami.Settings.isMobile ? ToolBar.Footer : ToolBar.Header + + Layout.row: Kirigami.Settings.isMobile ? 1 : 0 + + ColumnLayout { + id: __column + spacing: 0 + anchors.fill: parent + RowLayout { + PrivateSwipeTabBar { + id: __main + Layout.fillWidth: true + Layout.fillHeight: true + } + Item { Layout.fillWidth: true } + } + } + + Layout.fillWidth: true + + Accessible.role: Accessible.PageTabList + } + + StackView { + id: stackView + + Layout.fillWidth: true + Layout.fillHeight: true + + Layout.row: Kirigami.Settings.isMobile ? 0 : 1 + + Kirigami.ColumnView { + id: columnView + columnResizeMode: Kirigami.ColumnView.SingleColumn + + contentChildren: swipeNavigatorRoot.pages + anchors.fill: parent + + Component.onCompleted: { + columnView.currentIndex = 0 + } + } + } +} diff --git a/src/enums.h b/src/enums.h index f41db3fb..4aaee922 100644 --- a/src/enums.h +++ b/src/enums.h @@ -1,50 +1,62 @@ /* * SPDX-FileCopyrightText: 2016 Marco Martin * * SPDX-License-Identifier: LGPL-2.0-or-later */ #ifndef ENUMS_H #define ENUMS_H #include class ApplicationHeaderStyle : public QObject { Q_OBJECT public: enum Status { Auto = 0, Breadcrumb, Titles, TabBar, ToolBar, ///@since 5.48 None ///@since 5.48 }; Q_ENUM(Status) enum NavigationButton { NoNavigationButtons = 0, ShowBackButton = 0x1, ShowForwardButton = 0x2 }; Q_ENUM(NavigationButton) Q_DECLARE_FLAGS(NavigationButtons, NavigationButton) }; +class SwipeNavigatorType : public QObject +{ + Q_OBJECT + +public: + enum Type { + Top = 0, + Left = 1 + }; + Q_ENUM(Type) +}; + class MessageType : public QObject { Q_OBJECT Q_ENUMS(Type) public: enum Type { Information = 0, Positive, Warning, Error }; }; #endif // ENUMS_H diff --git a/src/kirigamiplugin.cpp b/src/kirigamiplugin.cpp index 25cd28fc..507421f6 100644 --- a/src/kirigamiplugin.cpp +++ b/src/kirigamiplugin.cpp @@ -1,275 +1,274 @@ /* * SPDX-FileCopyrightText: 2009 Alan Alpert * SPDX-FileCopyrightText: 2010 Ménard Alexis * SPDX-FileCopyrightText: 2010 Marco Martin * * SPDX-License-Identifier: LGPL-2.0-or-later */ #include "kirigamiplugin.h" #include "columnview.h" #include "enums.h" #include "icon.h" #include "settings.h" #include "formlayoutattached.h" #include "mnemonicattached.h" #include "delegaterecycler.h" #include "pagepool.h" #include "scenepositionattached.h" #include "wheelhandler.h" #include "shadowedrectangle.h" #include "shadowedtexture.h" #include "colorutils.h" #include "pagerouter.h" #include "imagecolors.h" #include "avatar.h" #include #include #include #include #include #include #include "libkirigami/platformtheme.h" static QString s_selectedStyle; //Q_INIT_RESOURCE(kirigami); #ifdef KIRIGAMI_BUILD_TYPE_STATIC #include #endif class CopyHelperPrivate : public QObject { Q_OBJECT public: Q_INVOKABLE static void copyTextToClipboard(const QString& text) { qGuiApp->clipboard()->setText(text); } }; // we can't do this in the plugin object directly, as that can live in a different thread // and event filters are only allowed in the same thread as the filtered object class LanguageChangeEventFilter : public QObject { Q_OBJECT public: bool eventFilter(QObject *receiver, QEvent *event) override { if (event->type() == QEvent::LanguageChange && receiver == QCoreApplication::instance()) { emit languageChangeEvent(); } return QObject::eventFilter(receiver, event); } Q_SIGNALS: void languageChangeEvent(); }; KirigamiPlugin::KirigamiPlugin(QObject *parent) : QQmlExtensionPlugin(parent) { auto filter = new LanguageChangeEventFilter; filter->moveToThread(QCoreApplication::instance()->thread()); QCoreApplication::instance()->installEventFilter(filter); connect(filter, &LanguageChangeEventFilter::languageChangeEvent, this, &KirigamiPlugin::languageChangeEvent); } QUrl KirigamiPlugin::componentUrl(const QString &fileName) const { for (const QString &style : qAsConst(m_stylesFallbackChain)) { const QString candidate = QStringLiteral("styles/") + style + QLatin1Char('/') + fileName; if (QFile::exists(resolveFilePath(candidate))) { #ifdef KIRIGAMI_BUILD_TYPE_STATIC return QUrl(QStringLiteral("qrc:/org/kde/kirigami/styles/") + style + QLatin1Char('/') + fileName); #else return QUrl(resolveFileUrl(candidate)); #endif } } #ifdef KIRIGAMI_BUILD_TYPE_STATIC return QUrl(QStringLiteral("qrc:/org/kde/kirigami/") + fileName); #else return QUrl(resolveFileUrl(fileName)); #endif } void KirigamiPlugin::registerTypes(const char *uri) { #if defined(Q_OS_ANDROID) && QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QResource::registerResource(QStringLiteral("assets:/android_rcc_bundle.rcc")); #endif Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.kirigami")); const QString style = QQuickStyle::name(); if (QIcon::themeName().isEmpty() && !qEnvironmentVariableIsSet("XDG_CURRENT_DESKTOP")) { QIcon::setThemeSearchPaths({resolveFilePath(QStringLiteral(".")), QStringLiteral(":/icons")}); QIcon::setThemeName(QStringLiteral("breeze-internal")); } #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) //org.kde.desktop.plasma is a couple of files that fall back to desktop by purpose if ((style.isEmpty() || style == QStringLiteral("org.kde.desktop.plasma")) && QFile::exists(resolveFilePath(QStringLiteral("/styles/org.kde.desktop")))) { m_stylesFallbackChain.prepend(QStringLiteral("org.kde.desktop")); } #elif defined(Q_OS_ANDROID) if (!m_stylesFallbackChain.contains(QLatin1String("Material"))) { m_stylesFallbackChain.prepend(QStringLiteral("Material")); } #else // do we have an iOS specific style? if (!m_stylesFallbackChain.contains(QLatin1String("Material"))) { m_stylesFallbackChain.prepend(QStringLiteral("Material")); } #endif if (!style.isEmpty() && QFile::exists(resolveFilePath(QStringLiteral("/styles/") + style)) && !m_stylesFallbackChain.contains(style)) { m_stylesFallbackChain.prepend(style); //if we have plasma deps installed, use them for extra integration if (style == QStringLiteral("org.kde.desktop") && QFile::exists(resolveFilePath(QStringLiteral("/styles/org.kde.desktop.plasma")))) { m_stylesFallbackChain.prepend(QStringLiteral("org.kde.desktop.plasma")); } } else { #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) m_stylesFallbackChain.prepend(QStringLiteral("org.kde.desktop")); #endif } //At this point the fallback chain will be selected->org.kde.desktop->Fallback s_selectedStyle = m_stylesFallbackChain.first(); qmlRegisterSingletonType(uri, 2, 0, "Settings", [](QQmlEngine *e, QJSEngine*) -> QObject* { Settings *settings = Settings::self(); //singleton managed internally, qml should never delete it e->setObjectOwnership(settings, QQmlEngine::CppOwnership); settings->setStyle(s_selectedStyle); return settings; } ); qmlRegisterUncreatableType(uri, 2, 0, "ApplicationHeaderStyle", QStringLiteral("Cannot create objects of type ApplicationHeaderStyle")); //old legacy retrocompatible Theme qmlRegisterSingletonType(componentUrl(QStringLiteral("Theme.qml")), uri, 2, 0, "Theme"); qmlRegisterSingletonType(componentUrl(QStringLiteral("Units.qml")), uri, 2, 0, "Units"); qmlRegisterType(componentUrl(QStringLiteral("Action.qml")), uri, 2, 0, "Action"); qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationHeader.qml")), uri, 2, 0, "AbstractApplicationHeader"); qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationWindow.qml")), uri, 2, 0, "AbstractApplicationWindow"); qmlRegisterType(componentUrl(QStringLiteral("AbstractListItem.qml")), uri, 2, 0, "AbstractListItem"); qmlRegisterType(componentUrl(QStringLiteral("ApplicationHeader.qml")), uri, 2, 0, "ApplicationHeader"); qmlRegisterType(componentUrl(QStringLiteral("ToolBarApplicationHeader.qml")), uri, 2, 0, "ToolBarApplicationHeader"); qmlRegisterType(componentUrl(QStringLiteral("ApplicationWindow.qml")), uri, 2, 0, "ApplicationWindow"); qmlRegisterType(componentUrl(QStringLiteral("BasicListItem.qml")), uri, 2, 0, "BasicListItem"); qmlRegisterType(componentUrl(QStringLiteral("OverlayDrawer.qml")), uri, 2, 0, "OverlayDrawer"); qmlRegisterType(componentUrl(QStringLiteral("ContextDrawer.qml")), uri, 2, 0, "ContextDrawer"); qmlRegisterType(componentUrl(QStringLiteral("GlobalDrawer.qml")), uri, 2, 0, "GlobalDrawer"); qmlRegisterType(componentUrl(QStringLiteral("Heading.qml")), uri, 2, 0, "Heading"); qmlRegisterType(componentUrl(QStringLiteral("Separator.qml")), uri, 2, 0, "Separator"); qmlRegisterType(componentUrl(QStringLiteral("PageRow.qml")), uri, 2, 0, "PageRow"); qmlRegisterType(uri, 2, 0, "Icon"); qmlRegisterType(componentUrl(QStringLiteral("Label.qml")), uri, 2, 0, "Label"); //TODO: uncomment for 2.3 release //qmlRegisterTypeNotAvailable(uri, 2, 3, "Label", "Label type not supported anymore, use QtQuick.Controls.Label 2.0 instead"); qmlRegisterType(componentUrl(QStringLiteral("OverlaySheet.qml")), uri, 2, 0, "OverlaySheet"); qmlRegisterType(componentUrl(QStringLiteral("Page.qml")), uri, 2, 0, "Page"); qmlRegisterType(componentUrl(QStringLiteral("ScrollablePage.qml")), uri, 2, 0, "ScrollablePage"); qmlRegisterType(componentUrl(QStringLiteral("SplitDrawer.qml")), uri, 2, 0, "SplitDrawer"); qmlRegisterType(componentUrl(QStringLiteral("SwipeListItem.qml")), uri, 2, 0, "SwipeListItem"); //2.1 qmlRegisterType(componentUrl(QStringLiteral("AbstractItemViewHeader.qml")), uri, 2, 1, "AbstractItemViewHeader"); qmlRegisterType(componentUrl(QStringLiteral("ItemViewHeader.qml")), uri, 2, 1, "ItemViewHeader"); qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationItem.qml")), uri, 2, 1, "AbstractApplicationItem"); qmlRegisterType(componentUrl(QStringLiteral("ApplicationItem.qml")), uri, 2, 1, "ApplicationItem"); //2.2 //Theme changed from a singleton to an attached property qmlRegisterUncreatableType(uri, 2, 2, "Theme", QStringLiteral("Cannot create objects of type Theme, use it as an attached property")); //2.3 qmlRegisterType(componentUrl(QStringLiteral("FormLayout.qml")), uri, 2, 3, "FormLayout"); qmlRegisterUncreatableType(uri, 2, 3, "FormData", QStringLiteral("Cannot create objects of type FormData, use it as an attached property")); qmlRegisterUncreatableType(uri, 2, 3, "MnemonicData", QStringLiteral("Cannot create objects of type MnemonicData, use it as an attached property")); //2.4 qmlRegisterType(componentUrl(QStringLiteral("AbstractCard.qml")), uri, 2, 4, "AbstractCard"); qmlRegisterType(componentUrl(QStringLiteral("Card.qml")), uri, 2, 4, "Card"); qmlRegisterType(componentUrl(QStringLiteral("CardsListView.qml")), uri, 2, 4, "CardsListView"); qmlRegisterType(componentUrl(QStringLiteral("CardsGridView.qml")), uri, 2, 4, "CardsGridView"); qmlRegisterType(componentUrl(QStringLiteral("CardsLayout.qml")), uri, 2, 4, "CardsLayout"); qmlRegisterType(componentUrl(QStringLiteral("InlineMessage.qml")), uri, 2, 4, "InlineMessage"); qmlRegisterUncreatableType(uri, 2, 4, "MessageType", QStringLiteral("Cannot create objects of type MessageType")); qmlRegisterType(uri, 2, 4, "DelegateRecycler"); //2.5 qmlRegisterType(componentUrl(QStringLiteral("ListItemDragHandle.qml")), uri, 2, 5, "ListItemDragHandle"); qmlRegisterType(componentUrl(QStringLiteral("ActionToolBar.qml")), uri, 2, 5, "ActionToolBar"); qmlRegisterUncreatableType(uri, 2, 5, "ScenePosition", QStringLiteral("Cannot create objects of type ScenePosition, use it as an attached property")); //2.6 qmlRegisterType(componentUrl(QStringLiteral("AboutPage.qml")), uri, 2, 6, "AboutPage"); qmlRegisterType(componentUrl(QStringLiteral("LinkButton.qml")), uri, 2, 6, "LinkButton"); qmlRegisterType(componentUrl(QStringLiteral("UrlButton.qml")), uri, 2, 6, "UrlButton"); qmlRegisterSingletonType("org.kde.kirigami.private", 2, 6, "CopyHelperPrivate", [] (QQmlEngine*, QJSEngine*) -> QObject* { return new CopyHelperPrivate; }); //2.7 qmlRegisterType(uri, 2, 7, "ColumnView"); qmlRegisterType(componentUrl(QStringLiteral("ActionTextField.qml")), uri, 2, 7, "ActionTextField"); //2.8 qmlRegisterType(componentUrl(QStringLiteral("SearchField.qml")), uri, 2, 8, "SearchField"); qmlRegisterType(componentUrl(QStringLiteral("PasswordField.qml")), uri, 2, 8, "PasswordField"); //2.9 qmlRegisterType(uri, 2, 9, "WheelHandler"); qmlRegisterUncreatableType(uri, 2, 9, "WheelEvent", QStringLiteral("Cannot create objects of type WheelEvent.")); //2.10 qmlRegisterType(componentUrl(QStringLiteral("ListSectionHeader.qml")), uri, 2, 10, "ListSectionHeader"); // 2.11 qmlRegisterType(uri, 2, 11, "PagePool"); qmlRegisterType(componentUrl(QStringLiteral("PagePoolAction.qml")), uri, 2, 11, "PagePoolAction"); //TODO: remove qmlRegisterType(componentUrl(QStringLiteral("SwipeListItem2.qml")), uri, 2, 11, "SwipeListItem2"); // 2.12 qmlRegisterType(uri, 2, 12, "ShadowedRectangle"); qmlRegisterType(uri, 2, 12, "ShadowedTexture"); qmlRegisterType(componentUrl(QStringLiteral("ShadowedImage.qml")), uri, 2, 12, "ShadowedImage"); qmlRegisterType(componentUrl(QStringLiteral("PlaceholderMessage.qml")), uri, 2, 12, "PlaceholderMessage"); qmlRegisterUncreatableType(uri, 2, 12, "BorderGroup", QStringLiteral("Used as grouped property")); qmlRegisterUncreatableType(uri, 2, 12, "ShadowGroup", QStringLiteral("Used as grouped property")); qmlRegisterSingletonType(uri, 2, 12, "ColorUtils", [] (QQmlEngine*, QJSEngine*) -> QObject* { return new ColorUtils; }); qmlRegisterUncreatableType(uri, 2, 12, "CornersGroup", QStringLiteral("Used as grouped property")); qmlRegisterType(uri, 2, 12, "PageRouter"); qmlRegisterType(uri, 2, 12, "PageRoute"); qmlRegisterUncreatableType(uri, 2, 12, "PageRouterAttached", QStringLiteral("PageRouterAttached cannot be created")); qmlRegisterType(componentUrl(QStringLiteral("RouterWindow.qml")), uri, 2, 12, "RouterWindow"); // 2.13 qmlRegisterType(uri, 2, 13, "ImageColors"); qmlRegisterSingletonType("org.kde.kirigami.private", 2, 13, "AvatarPrivate", [] (QQmlEngine*, QJSEngine*) -> QObject* { return new AvatarPrivate; }); qmlRegisterType(componentUrl(QStringLiteral("Avatar.qml")), uri, 2, 13, "Avatar"); - qmlRegisterType(componentUrl(QStringLiteral("SwipeNavigator.qml")), uri, 2, 13, "SwipeNavigator"); - + qmlRegisterUncreatableType(uri, 2, 13, "SwipeNavigatorType", QStringLiteral("Cannot create objects of type SwipeNavigatorType")); qmlProtectModule(uri, 2); } void KirigamiPlugin::initializeEngine(QQmlEngine *engine, const char *uri) { Q_UNUSED(uri); connect(this, &KirigamiPlugin::languageChangeEvent, engine, &QQmlEngine::retranslate); } #include "kirigamiplugin.moc"