From 1cd113316c84d879a9d9069342458d48d0e432a0 Mon Sep 17 00:00:00 2001 From: Mentalflow <312902918@qq.com> Date: Sun, 30 Jun 2024 03:56:15 +0800 Subject: [PATCH] RibbonPageIndicator: Added. --- example/qml/Qt5/components/TabBar.qml | 19 +++ example/qml/Qt6/components/TabBar.qml | 19 +++ lib_source/CMakeLists.txt | 2 +- lib_source/qml/Qt5/RibbonPageIndicator.qml | 159 +++++++++++++++++++++ lib_source/qml/Qt6/RibbonPageIndicator.qml | 159 +++++++++++++++++++++ 5 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 lib_source/qml/Qt5/RibbonPageIndicator.qml create mode 100644 lib_source/qml/Qt6/RibbonPageIndicator.qml diff --git a/example/qml/Qt5/components/TabBar.qml b/example/qml/Qt5/components/TabBar.qml index 64652c0..667aa94 100644 --- a/example/qml/Qt5/components/TabBar.qml +++ b/example/qml/Qt5/components/TabBar.qml @@ -648,6 +648,25 @@ RibbonTabBar { } } } + RibbonTabGroup{ + text: qsTr("PageIndicator") + width: pageindicator_layout.width + 30 + ColumnLayout{ + id: pageindicator_layout + anchors.centerIn: parent + height: parent.height + RibbonPageIndicator{ + count: 100 + showPagination: true + Layout.alignment: Qt.AlignHCenter + } + RibbonPageIndicator{ + count: 10 + showPagination: false + Layout.alignment: Qt.AlignHCenter + } + } + } } RibbonTabPage{ title: qsTr("Views") diff --git a/example/qml/Qt6/components/TabBar.qml b/example/qml/Qt6/components/TabBar.qml index 9f157ba..96c48cb 100644 --- a/example/qml/Qt6/components/TabBar.qml +++ b/example/qml/Qt6/components/TabBar.qml @@ -648,6 +648,25 @@ RibbonTabBar { } } } + RibbonTabGroup{ + text: qsTr("PageIndicator") + width: pageindicator_layout.width + 30 + ColumnLayout{ + id: pageindicator_layout + anchors.centerIn: parent + height: parent.height + RibbonPageIndicator{ + count: 100 + showPagination: true + Layout.alignment: Qt.AlignHCenter + } + RibbonPageIndicator{ + count: 10 + showPagination: false + Layout.alignment: Qt.AlignHCenter + } + } + } } RibbonTabPage{ title: qsTr("Views") diff --git a/lib_source/CMakeLists.txt b/lib_source/CMakeLists.txt index 9737e50..1a8ec8e 100644 --- a/lib_source/CMakeLists.txt +++ b/lib_source/CMakeLists.txt @@ -41,7 +41,7 @@ set(qml_files RibbonTabBar.qml RibbonTabButton.qml RibbonView.qml RibbonBackStageView.qml RibbonBackStagePage.qml RibbonBackStageGroup.qml RibbonRadioButton.qml RibbonBackStageMenuItem.qml RibbonTourItem.qml RibbonObject.qml RibbonProgressBar.qml RibbonProgressRing.qml - RibbonBusyBar.qml RibbonBusyRing.qml) + RibbonBusyBar.qml RibbonBusyRing.qml RibbonPageIndicator.qml) set(qml_prefix "qml/Qt${QT_VERSION_MAJOR}/") diff --git a/lib_source/qml/Qt5/RibbonPageIndicator.qml b/lib_source/qml/Qt5/RibbonPageIndicator.qml new file mode 100644 index 0000000..fd6fd34 --- /dev/null +++ b/lib_source/qml/Qt5/RibbonPageIndicator.qml @@ -0,0 +1,159 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.11 +import RibbonUI 1.0 + +PageIndicator { + id: control + + property real paginationHeight: 12 + property real paginationWidth: 12 + property int headCount: 4 + property int tailCount: 4 + property int previewWindow: 2 + property bool showPagination: true + property bool startWithZero: false + property bool modernStyle: RibbonTheme.modernStyle + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + padding: 6 + spacing: 6 + + delegate: Rectangle { + id: item + implicitWidth: showPagination ? Math.max(pagination_text.contentWidth + padding * 2, paginationWidth, + pagination_text.contentHeight + padding * 3 / 4, paginationHeight) : paginationWidth + implicitHeight: showPagination ? previous_btn.height : paginationHeight + + radius: showPagination ? modernStyle ? Math.min(width, height) * 0.22 : Math.min(width, height) * 0.15 : Math.min(width, height) / 2 + color: { + if(!mouse.containsMouse) + return RibbonTheme.isDarkMode ? "#2F2F2F" : "white" + let alpha = (mouse.containsPress ? 0.55 : mouse.containsMouse ? 0.75 : (modelData ? modelData : index) === control.currentIndex ? 0.95 : 0.45) - (showPagination ? 0.65 : 0) + return RibbonTheme.isDarkMode ? Qt.rgba(255,255,255,alpha) : Qt.rgba(0,0,0,alpha) + } + border.width: (modelData ? modelData : index) === control.currentIndex ? 2 : 1 + border.color: RibbonTheme.isDarkMode ? "#5C5D5D" : "#B5B4B5" + + scale: { + if(showPagination) + return 1 + let minimumScale = 0.5 + let ave = 0 + if(mouse.containsMouse) + return 1.1 + else if((modelData ? modelData : index) === control.currentIndex) + return 1 + else{ + if(index < control.currentIndex){ + ave = (1 - minimumScale) / control.currentIndex + } + else if(index > control.currentIndex){ + ave = (1 - minimumScale) / (control.count - control.currentIndex - 1) + } + return 1 - ave * Math.abs(index - control.currentIndex) + } + } + + required property int index + required property int modelData + + RibbonText{ + id: pagination_text + viewOnly: true + visible: showPagination + anchors.centerIn: parent + text: startWithZero ? modelData ? modelData : index : (modelData ? modelData : index) + 1 + font.bold: (modelData ? modelData : index) === control.currentIndex + } + + Behavior on opacity { OpacityAnimator { duration: 100 } } + + MouseArea{ + id: mouse + anchors.fill: parent + hoverEnabled: true + onClicked: control.currentIndex = modelData ? modelData : index + } + } + + contentItem: RowLayout { + id: row + spacing: control.spacing + property int head: headCount + property int middle: Math.max(head,tail) + property int tail: tailCount + + RibbonButton{ + id: previous_btn + text: qsTr("Previous") + iconSource: RibbonIcons.Previous + onClicked: control.currentIndex-- + enabled: control.currentIndex !== 0 + visible: showPagination + } + + Repeater { + id: head_repeater + model: showPagination ? ((control.currentIndex + 1 > row.head - control.previewWindow) && (control.count > row.head + row.tail) ? control.previewWindow : control.count > row.head ? row.head : control.count ) : control.count + delegate: control.delegate + } + + RibbonText{ + viewOnly: true + visible: showPagination && control.currentIndex > row.head - control.previewWindow && (control.count > row.head + row.tail) + text: "...." + font.bold: true + } + + Repeater { + id: mid_repeater + property int begin: (control.currentIndex - Math.floor((row.middle - control.previewWindow)/2)) + row.middle > control.count - 1 ? end - row.middle + 1: (control.currentIndex - Math.floor((row.middle - control.previewWindow)/2)) < row.head ? control.currentIndex : (control.currentIndex - Math.floor((row.middle - control.previewWindow)/2)) + property int end: control.count - 1 - control.currentIndex < row.middle ? control.count - 1 : control.currentIndex + row.middle - Math.ceil((row.middle - control.previewWindow)/2) + model: { + let list = [] + if(showPagination && (control.currentIndex + 1 > row.head - control.previewWindow) && (control.count > (control.previewWindow * 2 + row.middle)) && row.head + row.tail < control.count){ + for(let i = begin; i <= end; i++){ + list.push(i) + } + } + return list + } + delegate: control.delegate + } + + RibbonText{ + viewOnly: true + visible: showPagination && (control.currentIndex + 1 < control.count - 1 - row.tail) && (control.count > (control.previewWindow * 2 + row.middle)) && head_repeater.model + tail_repeater.model.length < control.count + text: "...." + font.bold: true + } + + Repeater { + id: tail_repeater + model: { + let list = [], begin = mid_repeater.model.length ? control.count - 1 - mid_repeater.end < control.previewWindow ? mid_repeater.end + 1 : control.count - control.previewWindow : control.count < row.head + row.tail ? row.head : control.count - row.tail + if(showPagination && ((control.count >= row.head + row.tail) && (control.currentIndex < control.count - row.tail) || !mid_repeater.model.length)){ + for(let i = begin; i < control.count; i++){ + list.push(i) + } + } + return list + } + delegate: control.delegate + } + + RibbonButton{ + id: next_btn + text: qsTr("Next") + iconSource: RibbonIcons.Next + onClicked: control.currentIndex++ + enabled: control.currentIndex !== control.count - 1 + visible: showPagination + } + } +} diff --git a/lib_source/qml/Qt6/RibbonPageIndicator.qml b/lib_source/qml/Qt6/RibbonPageIndicator.qml new file mode 100644 index 0000000..aeb399a --- /dev/null +++ b/lib_source/qml/Qt6/RibbonPageIndicator.qml @@ -0,0 +1,159 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import RibbonUI + +PageIndicator { + id: control + + property real paginationHeight: 12 + property real paginationWidth: 12 + property int headCount: 4 + property int tailCount: 4 + property int previewWindow: 2 + property bool showPagination: true + property bool startWithZero: false + property bool modernStyle: RibbonTheme.modernStyle + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + padding: 6 + spacing: 6 + + delegate: Rectangle { + id: item + implicitWidth: showPagination ? Math.max(pagination_text.contentWidth + padding * 2, paginationWidth, + pagination_text.contentHeight + padding * 3 / 4, paginationHeight) : paginationWidth + implicitHeight: showPagination ? previous_btn.height : paginationHeight + + radius: showPagination ? modernStyle ? Math.min(width, height) * 0.22 : Math.min(width, height) * 0.15 : Math.min(width, height) / 2 + color: { + if(!mouse.containsMouse) + return RibbonTheme.isDarkMode ? "#2F2F2F" : "white" + let alpha = (mouse.containsPress ? 0.55 : mouse.containsMouse ? 0.75 : (modelData ? modelData : index) === control.currentIndex ? 0.95 : 0.45) - (showPagination ? 0.65 : 0) + return RibbonTheme.isDarkMode ? Qt.rgba(255,255,255,alpha) : Qt.rgba(0,0,0,alpha) + } + border.width: (modelData ? modelData : index) === control.currentIndex ? 2 : 1 + border.color: RibbonTheme.isDarkMode ? "#5C5D5D" : "#B5B4B5" + + scale: { + if(showPagination) + return 1 + let minimumScale = 0.5 + let ave = 0 + if(mouse.containsMouse) + return 1.1 + else if((modelData ? modelData : index) === control.currentIndex) + return 1 + else{ + if(index < control.currentIndex){ + ave = (1 - minimumScale) / control.currentIndex + } + else if(index > control.currentIndex){ + ave = (1 - minimumScale) / (control.count - control.currentIndex - 1) + } + return 1 - ave * Math.abs(index - control.currentIndex) + } + } + + required property int index + required property int modelData + + RibbonText{ + id: pagination_text + viewOnly: true + visible: showPagination + anchors.centerIn: parent + text: startWithZero ? modelData ? modelData : index : (modelData ? modelData : index) + 1 + font.bold: (modelData ? modelData : index) === control.currentIndex + } + + Behavior on opacity { OpacityAnimator { duration: 100 } } + + MouseArea{ + id: mouse + anchors.fill: parent + hoverEnabled: true + onClicked: control.currentIndex = modelData ? modelData : index + } + } + + contentItem: RowLayout { + id: row + spacing: control.spacing + property int head: headCount + property int middle: Math.max(head,tail) + property int tail: tailCount + + RibbonButton{ + id: previous_btn + text: qsTr("Previous") + iconSource: RibbonIcons.Previous + onClicked: control.currentIndex-- + enabled: control.currentIndex !== 0 + visible: showPagination + } + + Repeater { + id: head_repeater + model: showPagination ? ((control.currentIndex + 1 > row.head - control.previewWindow) && (control.count > row.head + row.tail) ? control.previewWindow : control.count > row.head ? row.head : control.count ) : control.count + delegate: control.delegate + } + + RibbonText{ + viewOnly: true + visible: showPagination && control.currentIndex > row.head - control.previewWindow && (control.count > row.head + row.tail) + text: "...." + font.bold: true + } + + Repeater { + id: mid_repeater + property int begin: (control.currentIndex - Math.floor((row.middle - control.previewWindow)/2)) + row.middle > control.count - 1 ? end - row.middle + 1: (control.currentIndex - Math.floor((row.middle - control.previewWindow)/2)) < row.head ? control.currentIndex : (control.currentIndex - Math.floor((row.middle - control.previewWindow)/2)) + property int end: control.count - 1 - control.currentIndex < row.middle ? control.count - 1 : control.currentIndex + row.middle - Math.ceil((row.middle - control.previewWindow)/2) + model: { + let list = [] + if(showPagination && (control.currentIndex + 1 > row.head - control.previewWindow) && (control.count > (control.previewWindow * 2 + row.middle)) && row.head + row.tail < control.count){ + for(let i = begin; i <= end; i++){ + list.push(i) + } + } + return list + } + delegate: control.delegate + } + + RibbonText{ + viewOnly: true + visible: showPagination && (control.currentIndex + 1 < control.count - 1 - row.tail) && (control.count > (control.previewWindow * 2 + row.middle)) && head_repeater.model + tail_repeater.model.length < control.count + text: "...." + font.bold: true + } + + Repeater { + id: tail_repeater + model: { + let list = [], begin = mid_repeater.model.length ? control.count - 1 - mid_repeater.end < control.previewWindow ? mid_repeater.end + 1 : control.count - control.previewWindow : control.count < row.head + row.tail ? row.head : control.count - row.tail + if(showPagination && ((control.count >= row.head + row.tail) && (control.currentIndex < control.count - row.tail) || !mid_repeater.model.length)){ + for(let i = begin; i < control.count; i++){ + list.push(i) + } + } + return list + } + delegate: control.delegate + } + + RibbonButton{ + id: next_btn + text: qsTr("Next") + iconSource: RibbonIcons.Next + onClicked: control.currentIndex++ + enabled: control.currentIndex !== control.count - 1 + visible: showPagination + } + } +}