From f3597a25b74d806c3ce90c9c23d919ec3ccac2c8 Mon Sep 17 00:00:00 2001 From: Mentalflow <312902918@qq.com> Date: Sat, 29 Jun 2024 16:12:27 +0800 Subject: [PATCH] RibbonBusyBar,RibbonBusyRing: Added. --- example/qml/Qt5/components/TabBar.qml | 37 +++++++++ example/qml/Qt6/components/TabBar.qml | 37 +++++++++ lib_source/CMakeLists.txt | 3 +- lib_source/qml/Qt5/RibbonBusyBar.qml | 101 ++++++++++++++++++++++ lib_source/qml/Qt5/RibbonBusyRing.qml | 115 ++++++++++++++++++++++++++ lib_source/qml/Qt6/RibbonBusyBar.qml | 101 ++++++++++++++++++++++ lib_source/qml/Qt6/RibbonBusyRing.qml | 115 ++++++++++++++++++++++++++ 7 files changed, 508 insertions(+), 1 deletion(-) create mode 100644 lib_source/qml/Qt5/RibbonBusyBar.qml create mode 100644 lib_source/qml/Qt5/RibbonBusyRing.qml create mode 100644 lib_source/qml/Qt6/RibbonBusyBar.qml create mode 100644 lib_source/qml/Qt6/RibbonBusyRing.qml diff --git a/example/qml/Qt5/components/TabBar.qml b/example/qml/Qt5/components/TabBar.qml index 034a6c8..64652c0 100644 --- a/example/qml/Qt5/components/TabBar.qml +++ b/example/qml/Qt5/components/TabBar.qml @@ -612,6 +612,43 @@ RibbonTabBar { } } } + RibbonTabPage{ + title: qsTr("Indicator") + RibbonTabGroup{ + text: qsTr("BusyRing") + width: busyring_layout.width + 30 + RowLayout{ + id: busyring_layout + anchors.centerIn: parent + height: parent.height + RibbonBusyRing{ + running: true + } + RibbonBusyRing{ + running: true + clockwise: false + } + } + } + RibbonTabGroup{ + text: qsTr("BusyBar") + width: busybar_layout.width + 30 + ColumnLayout{ + id: busybar_layout + anchors.centerIn: parent + height: parent.height + RibbonBusyBar{ + running: true + barWidth: 100 + } + RibbonBusyBar{ + running: true + reversed: true + barWidth: 100 + } + } + } + } RibbonTabPage{ title: qsTr("Views") RibbonTabGroup{ diff --git a/example/qml/Qt6/components/TabBar.qml b/example/qml/Qt6/components/TabBar.qml index e7da321..9f157ba 100644 --- a/example/qml/Qt6/components/TabBar.qml +++ b/example/qml/Qt6/components/TabBar.qml @@ -612,6 +612,43 @@ RibbonTabBar { } } } + RibbonTabPage{ + title: qsTr("Indicator") + RibbonTabGroup{ + text: qsTr("BusyRing") + width: busyring_layout.width + 30 + RowLayout{ + id: busyring_layout + anchors.centerIn: parent + height: parent.height + RibbonBusyRing{ + running: true + } + RibbonBusyRing{ + running: true + clockwise: false + } + } + } + RibbonTabGroup{ + text: qsTr("BusyBar") + width: busybar_layout.width + 30 + ColumnLayout{ + id: busybar_layout + anchors.centerIn: parent + height: parent.height + RibbonBusyBar{ + running: true + barWidth: 100 + } + RibbonBusyBar{ + running: true + reversed: true + barWidth: 100 + } + } + } + } RibbonTabPage{ title: qsTr("Views") RibbonTabGroup{ diff --git a/lib_source/CMakeLists.txt b/lib_source/CMakeLists.txt index 702723b..9737e50 100644 --- a/lib_source/CMakeLists.txt +++ b/lib_source/CMakeLists.txt @@ -40,7 +40,8 @@ set(qml_files RibbonTabBar.qml RibbonTabButton.qml RibbonView.qml RibbonMessageListView.qml RibbonTour.qml RibbonTourContent.qml RibbonBackStageView.qml RibbonBackStagePage.qml RibbonBackStageGroup.qml RibbonRadioButton.qml RibbonBackStageMenuItem.qml RibbonTourItem.qml - RibbonObject.qml RibbonProgressBar.qml RibbonProgressRing.qml) + RibbonObject.qml RibbonProgressBar.qml RibbonProgressRing.qml + RibbonBusyBar.qml RibbonBusyRing.qml) set(qml_prefix "qml/Qt${QT_VERSION_MAJOR}/") diff --git a/lib_source/qml/Qt5/RibbonBusyBar.qml b/lib_source/qml/Qt5/RibbonBusyBar.qml new file mode 100644 index 0000000..58c9fe0 --- /dev/null +++ b/lib_source/qml/Qt5/RibbonBusyBar.qml @@ -0,0 +1,101 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtGraphicalEffects 1.0 +import RibbonUI 1.0 + +BusyIndicator { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + padding: 2 + property real barWidth: 200 + property real barHeight: 4 + property real indicatorWidth: 4 + property real indicatorHeight: 4 + property int indicatorNumber: 5 + property int animationDurarion: 2000 + property bool reversed: false + + QtObject{ + id: private_property + } + + contentItem: Item { + id: item + implicitWidth: barWidth + implicitHeight: barHeight + clip: true + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle{ + implicitWidth: item.width + implicitHeight: item.height + radius: item.height / 2 + } + } + Repeater { + id: repeater + anchors.centerIn: parent + model: indicatorNumber + delegate: Rectangle { + width: indicatorWidth + height: indicatorHeight + color: RibbonTheme.isDarkMode ? "white" : "black" + x: -(index + 1) * indicatorWidth + y: (barHeight.height / 2 - height / 2) + radius: Math.min(width,height)/2 + opacity: 0.5 + SequentialAnimation { + loops: Animation.Infinite + running: control.running + + PropertyAnimation { + target: repeater.itemAt(index) + property: "opacity" + from: 0 + to: 0.5 + duration: 50 * index + easing.type: Easing.OutExpo + } + + NumberAnimation { + target: repeater.itemAt(index) + property: "x" + from: control.reversed ? barWidth + (index + 1) * indicatorWidth : -(index + 1) * indicatorWidth + to: control.reversed ? (index + 1) * indicatorWidth : barWidth - (index + 1) * indicatorWidth + duration: animationDurarion * 9 / 10 + easing.type: Easing.OutInCubic + } + + ParallelAnimation{ + NumberAnimation { + target: repeater.itemAt(index) + property: "x" + from: control.reversed ? (index + 1) * indicatorWidth : barWidth - (index + 1) * indicatorWidth + to: control.reversed ? -(index + 1) * indicatorWidth - control.indicatorNumber*indicatorWidth : barWidth + (index + 1) * indicatorWidth + control.indicatorNumber*indicatorWidth + duration: animationDurarion / 10 + easing.type: Easing.OutInCubic + } + + PropertyAnimation { + target: repeater.itemAt(index) + property: "opacity" + from: 0.5 + to: 0 + duration: animationDurarion / 10 + easing.type: Easing.OutExpo + } + } + + PauseAnimation { + duration: 50 * (control.indicatorNumber - index - 1) + } + } + } + } + } +} diff --git a/lib_source/qml/Qt5/RibbonBusyRing.qml b/lib_source/qml/Qt5/RibbonBusyRing.qml new file mode 100644 index 0000000..52ac62a --- /dev/null +++ b/lib_source/qml/Qt5/RibbonBusyRing.qml @@ -0,0 +1,115 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import RibbonUI 1.0 + +BusyIndicator { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + padding: 6 + property real ringWidth: RibbonTheme.modernStyle ? radiusWidth : radiusLength * 7 / 12 + property real radiusLength: 15 + property real radiusWidth: 4 + property int lineNumber: RibbonTheme.modernStyle ? 10 : 8 + property real default_saturation: 0 + property int animationDurarion: RibbonTheme.modernStyle ? 4000 : 1000 + property bool clockwise: true + + onAnimationDurarionChanged: { + running = !running + Qt.callLater(()=>running = !running) // Fix Qt 5 animation duration doesn't change + } + + QtObject{ + id: private_property + property real angle: 360 / lineNumber + property real saturation: (1 - default_saturation) / lineNumber + } + + contentItem: Item { + id: item + implicitWidth: radiusLength * 2 + implicitHeight: radiusLength * 2 + property real dynamic_index: 0 + + PropertyAnimation on dynamic_index { + running: control.running && !RibbonTheme.modernStyle + from: clockwise ? lineNumber : 0 + to: clockwise ? 0 : lineNumber + loops: Animation.Infinite + duration: animationDurarion + } + + Repeater { + id: repeater + anchors.centerIn: parent + model: RibbonTheme.modernStyle ? lineNumber / 2 : lineNumber + delegate: Rectangle { + width: radiusWidth + height: ringWidth + property real item_saturation: (index + item.dynamic_index) % lineNumber * private_property.saturation + default_saturation + color: Qt.hsla(0, 0, RibbonTheme.modernStyle ? RibbonTheme.isDarkMode ? 1 : 0 : item_saturation, 1) + rotation: index * private_property.angle + x: (parent.width / 2) - (radiusLength - ringWidth) * Math.sin(rotation/180 * Math.PI) + y: (parent.height / 2 - height / 2) + (radiusLength - ringWidth) * Math.cos(rotation/180 * Math.PI) + transformOrigin: Item.Top + radius: Math.min(width,height)/2 + opacity: RibbonTheme.modernStyle ? 0 : 0.5 + SequentialAnimation { + loops: Animation.Infinite + running: control.running && RibbonTheme.modernStyle + + PropertyAnimation { + target: repeater.itemAt(index) + property: "opacity" + from: 0 + to: 0.5 + duration: 50 * index + easing.type: Easing.OutExpo + } + + NumberAnimation { + target: repeater.itemAt(index) + property: "rotation" + from: (clockwise ? 1 : -1) * 0 + to: (clockwise ? 1 : -1) * (360 - (index - lineNumber / 4 + 0.5) * private_property.angle * 1.4) + duration: animationDurarion / 2 + easing.type: Easing.OutInQuad + } + + ParallelAnimation{ + NumberAnimation { + target: repeater.itemAt(index) + property: "rotation" + from: (clockwise ? 1 : -1) * (360 - (index - lineNumber / 4 + 0.5) * private_property.angle * 1.4) + to: (clockwise ? 1 : -1) * 720 + duration: animationDurarion / 2 + easing.type: Easing.OutInQuad + } + SequentialAnimation{ + PauseAnimation { + duration: animationDurarion / 2 - animationDurarion / 20 + } + PropertyAnimation { + target: repeater.itemAt(index) + property: "opacity" + from: 0.5 + to: 0 + duration: animationDurarion / 20 + easing.type: Easing.OutExpo + } + } + } + + PauseAnimation { + duration: 50 * (control.lineNumber - index - 1) + } + } + } + } + } +} diff --git a/lib_source/qml/Qt6/RibbonBusyBar.qml b/lib_source/qml/Qt6/RibbonBusyBar.qml new file mode 100644 index 0000000..59ea3a6 --- /dev/null +++ b/lib_source/qml/Qt6/RibbonBusyBar.qml @@ -0,0 +1,101 @@ +import QtQuick +import QtQuick.Controls +import Qt5Compat.GraphicalEffects +import RibbonUI + +BusyIndicator { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + padding: 2 + property real barWidth: 200 + property real barHeight: 4 + property real indicatorWidth: 4 + property real indicatorHeight: 4 + property int indicatorNumber: 5 + property int animationDurarion: 2000 + property bool reversed: false + + QtObject{ + id: private_property + } + + contentItem: Item { + id: item + implicitWidth: barWidth + implicitHeight: barHeight + clip: true + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle{ + implicitWidth: item.width + implicitHeight: item.height + radius: item.height / 2 + } + } + Repeater { + id: repeater + anchors.centerIn: parent + model: indicatorNumber + delegate: Rectangle { + width: indicatorWidth + height: indicatorHeight + color: RibbonTheme.isDarkMode ? "white" : "black" + x: -(index + 1) * indicatorWidth + y: (barHeight.height / 2 - height / 2) + radius: Math.min(width,height)/2 + opacity: 0.5 + SequentialAnimation { + loops: Animation.Infinite + running: control.running + + PropertyAnimation { + target: repeater.itemAt(index) + property: "opacity" + from: 0 + to: 0.5 + duration: 50 * index + easing.type: Easing.OutExpo + } + + NumberAnimation { + target: repeater.itemAt(index) + property: "x" + from: control.reversed ? barWidth + (index + 1) * indicatorWidth : -(index + 1) * indicatorWidth + to: control.reversed ? (index + 1) * indicatorWidth : barWidth - (index + 1) * indicatorWidth + duration: animationDurarion * 9 / 10 + easing.type: Easing.OutInCubic + } + + ParallelAnimation{ + NumberAnimation { + target: repeater.itemAt(index) + property: "x" + from: control.reversed ? (index + 1) * indicatorWidth : barWidth - (index + 1) * indicatorWidth + to: control.reversed ? -(index + 1) * indicatorWidth - control.indicatorNumber*indicatorWidth : barWidth + (index + 1) * indicatorWidth + control.indicatorNumber*indicatorWidth + duration: animationDurarion / 10 + easing.type: Easing.OutInCubic + } + + PropertyAnimation { + target: repeater.itemAt(index) + property: "opacity" + from: 0.5 + to: 0 + duration: animationDurarion / 10 + easing.type: Easing.OutExpo + } + } + + PauseAnimation { + duration: 50 * (control.indicatorNumber - index - 1) + } + } + } + } + } +} diff --git a/lib_source/qml/Qt6/RibbonBusyRing.qml b/lib_source/qml/Qt6/RibbonBusyRing.qml new file mode 100644 index 0000000..77c2451 --- /dev/null +++ b/lib_source/qml/Qt6/RibbonBusyRing.qml @@ -0,0 +1,115 @@ +import QtQuick +import QtQuick.Controls +import RibbonUI + +BusyIndicator { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + padding: 6 + property real ringWidth: RibbonTheme.modernStyle ? radiusWidth : radiusLength * 7 / 12 + property real radiusLength: 15 + property real radiusWidth: 4 + property int lineNumber: RibbonTheme.modernStyle ? 10 : 8 + property real default_saturation: 0 + property int animationDurarion: RibbonTheme.modernStyle ? 4000 : 1000 + property bool clockwise: true + + onAnimationDurarionChanged: { + running = !running + Qt.callLater(()=>running = !running) // Fix Qt 5 animation duration doesn't change + } + + QtObject{ + id: private_property + property real angle: 360 / lineNumber + property real saturation: (1 - default_saturation) / lineNumber + } + + contentItem: Item { + id: item + implicitWidth: radiusLength * 2 + implicitHeight: radiusLength * 2 + property real dynamic_index: 0 + + PropertyAnimation on dynamic_index { + running: control.running && !RibbonTheme.modernStyle + from: clockwise ? lineNumber : 0 + to: clockwise ? 0 : lineNumber + loops: Animation.Infinite + duration: animationDurarion + } + + Repeater { + id: repeater + anchors.centerIn: parent + model: RibbonTheme.modernStyle ? lineNumber / 2 : lineNumber + delegate: Rectangle { + width: radiusWidth + height: ringWidth + property real item_saturation: (index + item.dynamic_index) % lineNumber * private_property.saturation + default_saturation + color: Qt.hsla(0, 0, RibbonTheme.modernStyle ? RibbonTheme.isDarkMode ? 1 : 0 : item_saturation, 1) + rotation: index * private_property.angle + x: (parent.width / 2) - (radiusLength - ringWidth) * Math.sin(rotation/180 * Math.PI) + y: (parent.height / 2 - height / 2) + (radiusLength - ringWidth) * Math.cos(rotation/180 * Math.PI) + transformOrigin: Item.Top + radius: Math.min(width,height)/2 + opacity: RibbonTheme.modernStyle ? 0 : 0.5 + SequentialAnimation { + loops: Animation.Infinite + running: control.running && RibbonTheme.modernStyle + + PropertyAnimation { + target: repeater.itemAt(index) + property: "opacity" + from: 0 + to: 0.5 + duration: 50 * index + easing.type: Easing.OutExpo + } + + NumberAnimation { + target: repeater.itemAt(index) + property: "rotation" + from: (clockwise ? 1 : -1) * 0 + to: (clockwise ? 1 : -1) * (360 - (index - lineNumber / 4 + 0.5) * private_property.angle * 1.4) + duration: animationDurarion / 2 + easing.type: Easing.OutInQuad + } + + ParallelAnimation{ + NumberAnimation { + target: repeater.itemAt(index) + property: "rotation" + from: (clockwise ? 1 : -1) * (360 - (index - lineNumber / 4 + 0.5) * private_property.angle * 1.4) + to: (clockwise ? 1 : -1) * 720 + duration: animationDurarion / 2 + easing.type: Easing.OutInQuad + } + SequentialAnimation{ + PauseAnimation { + duration: animationDurarion / 2 - animationDurarion / 20 + } + PropertyAnimation { + target: repeater.itemAt(index) + property: "opacity" + from: 0.5 + to: 0 + duration: animationDurarion / 20 + easing.type: Easing.OutExpo + } + } + } + + PauseAnimation { + duration: 50 * (control.lineNumber - index - 1) + } + } + } + } + } +}