diff --git a/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml b/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml index 474bdc591..d606c9e17 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml @@ -9,7 +9,7 @@ ColumnLayout { id: root spacing: 0 required property var tabButtonList // Something like [{"icon": "notifications", "name": Translation.tr("Notifications")}, {"icon": "volume_up", "name": Translation.tr("Volume mixer")}] - property int currentIndex + property alias currentIndex: tabBar.currentIndex property bool enableIndicatorAnimation: false property color colIndicator: Appearance?.colors.colPrimary ?? "#65558F" property color colBorder: Appearance?.m3colors.m3outlineVariant ?? "#C6C6D0" @@ -26,17 +26,14 @@ ColumnLayout { TabBar { id: tabBar Layout.fillWidth: true - Synchronizer on currentIndex { - property alias source: root.currentIndex - } background: Item { WheelHandler { onWheel: (event) => { if (event.angleDelta.y < 0) - tabBar.currentIndex = Math.min(tabBar.currentIndex + 1, root.tabButtonList.length - 1) + tabBar.incrementCurrentIndex() else if (event.angleDelta.y > 0) - tabBar.currentIndex = Math.max(tabBar.currentIndex - 1, 0) + tabBar.decrementCurrentIndex() } acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad } @@ -49,7 +46,7 @@ ColumnLayout { buttonText: modelData.name buttonIcon: modelData.icon minimumWidth: 160 - onClicked: root.currentIndex = index + onClicked: tabBar.setCurrentIndex(index) } } } diff --git a/dots/.config/quickshell/ii/modules/common/widgets/Toolbar.qml b/dots/.config/quickshell/ii/modules/common/widgets/Toolbar.qml index 85112160f..51348c4fa 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/Toolbar.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/Toolbar.qml @@ -10,6 +10,7 @@ import qs.modules.common.widgets Item { id: root + property bool enableShadow: true property real padding: 8 property alias colBackground: background.color property alias spacing: toolbarLayout.spacing @@ -18,15 +19,20 @@ Item { implicitHeight: background.implicitHeight property alias radius: background.radius - StyledRectangularShadow { - target: background + Loader { + active: root.enableShadow + anchors.fill: background + sourceComponent: StyledRectangularShadow { + target: background + anchors.fill: undefined + } } Rectangle { id: background anchors.fill: parent color: Appearance.m3colors.m3surfaceContainer - implicitHeight: Math.max(toolbarLayout.implicitHeight + root.padding * 2, 56) + implicitHeight: 56 implicitWidth: toolbarLayout.implicitWidth + root.padding * 2 radius: height / 2 diff --git a/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabBar.qml b/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabBar.qml new file mode 100644 index 000000000..c72263a9c --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabBar.qml @@ -0,0 +1,103 @@ +pragma ComponentBehavior: Bound +import qs.modules.common +import qs.modules.common.models +import qs.services +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt.labs.synchronizer + +Item { + id: root + property alias currentIndex: tabBar.currentIndex + required property var tabButtonList + + function incrementCurrentIndex() { + tabBar.incrementCurrentIndex() + } + function decrementCurrentIndex() { + tabBar.decrementCurrentIndex() + } + function setCurrentIndex(index) { + tabBar.setCurrentIndex(index) + } + + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + implicitWidth: contentItem.implicitWidth + implicitHeight: 40 + + Row { + id: contentItem + z: 1 + anchors.centerIn: parent + spacing: 4 + + Repeater { + model: root.tabButtonList + delegate: ToolbarTabButton { + required property int index + required property var modelData + current: index == root.currentIndex + text: modelData.name + materialSymbol: modelData.icon + onClicked: { + root.setCurrentIndex(index) + } + } + } + } + + Rectangle { + id: activeIndicator + z: 0 + color: Appearance.colors.colSecondaryContainer + implicitWidth: contentItem.children[root.currentIndex].implicitWidth + implicitHeight: contentItem.children[root.currentIndex].implicitHeight + radius: height / 2 + // Animation + property Item targetItem: contentItem.children[root.currentIndex] + AnimatedTabIndexPair { + id: leftBound + idx1Duration: 50 + idx2Duration: 200 + index: activeIndicator.targetItem.x + } + AnimatedTabIndexPair { + id: rightBound + idx1Duration: 50 + idx2Duration: 200 + index: activeIndicator.targetItem.x + activeIndicator.targetItem.width + } + x: Math.min(leftBound.idx1, leftBound.idx2) + width: Math.max(rightBound.idx1, rightBound.idx2) - x + } + + MouseArea { + anchors.fill: parent + z: 2 + acceptedButtons: Qt.NoButton + cursorShape: Qt.PointingHandCursor + onWheel: (event) => { + if (event.angleDelta.y < 0) { + root.incrementCurrentIndex(); + } + else { + root.decrementCurrentIndex(); + } + } + } + + // TabBar doesn't allow tabs to be of different sizes. Literally unusable. + // We use it only for the logic and draw stuff manually + TabBar { + id: tabBar + z: -1 + background: null + Repeater { // This is to fool the TabBar that it has tabs so it does the indices properly + model: root.tabButtonList.length + delegate: TabButton { + background: null + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabButton.qml new file mode 100644 index 000000000..e53518875 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/ToolbarTabButton.qml @@ -0,0 +1,40 @@ +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.functions +import Qt5Compat.GraphicalEffects +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +RippleButton { + id: root + required property string materialSymbol + required property bool current + horizontalPadding: 10 + + implicitHeight: 40 + implicitWidth: implicitContentWidth + horizontalPadding * 2 + buttonRadius: height / 2 + + colBackground: ColorUtils.transparentize(Appearance.colors.colSurfaceContainer) + colBackgroundHover: ColorUtils.transparentize(Appearance.colors.colOnSurface, current ? 1 : 0.95) + colRipple: ColorUtils.transparentize(Appearance.colors.colOnSurface, 0.95) + + contentItem: Row { + id: contentRow + anchors.centerIn: parent + spacing: 6 + + MaterialSymbol { + id: icon + anchors.verticalCenter: parent.verticalCenter + iconSize: 22 + text: root.materialSymbol + } + StyledText { + id: label + anchors.verticalCenter: parent.verticalCenter + text: root.text + } + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml index ff1c34509..063a2866f 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml @@ -21,7 +21,6 @@ Item { ...(root.translatorEnabled ? [{"icon": "translate", "name": Translation.tr("Translator")}] : []), ...((root.animeEnabled && !root.animeCloset) ? [{"icon": "bookmark_heart", "name": Translation.tr("Anime")}] : []) ] - property int selectedTab: 0 property int tabCount: swipeView.count function focusActiveItem() { @@ -31,36 +30,39 @@ Item { Keys.onPressed: (event) => { if (event.modifiers === Qt.ControlModifier) { if (event.key === Qt.Key_PageDown) { - root.selectedTab = Math.min(root.selectedTab + 1, root.tabCount - 1) + swipeView.incrementCurrentIndex() event.accepted = true; - } + } else if (event.key === Qt.Key_PageUp) { - root.selectedTab = Math.max(root.selectedTab - 1, 0) + swipeView.decrementCurrentIndex() event.accepted = true; } else if (event.key === Qt.Key_Tab) { - root.selectedTab = (root.selectedTab + 1) % root.tabCount; + swipeView.setCurrentIndex((swipeView.currentIndex + 1) % swipeView.count); event.accepted = true; } else if (event.key === Qt.Key_Backtab) { - root.selectedTab = (root.selectedTab - 1 + root.tabCount) % root.tabCount; + swipeView.setCurrentIndex((swipeView.currentIndex - 1 + swipeView.count) % swipeView.count); event.accepted = true; } } } ColumnLayout { - anchors.fill: parent - anchors.margins: sidebarPadding - + anchors { + fill: parent + margins: sidebarPadding + } spacing: sidebarPadding - PrimaryTabBar { // Tab strip - id: tabBar - visible: root.tabButtonList.length > 1 - tabButtonList: root.tabButtonList - Synchronizer on currentIndex { - property alias source: root.selectedTab + Toolbar { + Layout.alignment: Qt.AlignHCenter + enableShadow: false + ToolbarTabBar { + id: tabBar + Layout.alignment: Qt.AlignHCenter + tabButtonList: root.tabButtonList + currentIndex: swipeView.currentIndex } } @@ -70,12 +72,7 @@ Item { Layout.fillWidth: true Layout.fillHeight: true spacing: 10 - - currentIndex: root.selectedTab - onCurrentIndexChanged: { - tabBar.enableIndicatorAnimation = true - root.selectedTab = currentIndex - } + currentIndex: tabBar.currentIndex clip: true layer.enabled: true