diff options
| author | nippy <you@example.com> | 2026-04-18 13:49:56 +0200 |
|---|---|---|
| committer | nippy <you@example.com> | 2026-04-18 13:49:56 +0200 |
| commit | 5d94c0a7d44a2255b81815a52a7056a94a39842d (patch) | |
| tree | 759bdea9645c6a62f9e1e4c001f7d81cccd120d2 /raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsSidebar.qml | |
| parent | e79cdf210b267f21a186255ce1a4d50029439d54 (diff) | |
| download | RaveOS-PKGBUILD-5d94c0a7d44a2255b81815a52a7056a94a39842d.tar.gz RaveOS-PKGBUILD-5d94c0a7d44a2255b81815a52a7056a94a39842d.zip | |
update Raveos themes
Diffstat (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsSidebar.qml')
| -rw-r--r-- | raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsSidebar.qml | 1023 |
1 files changed, 1023 insertions, 0 deletions
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsSidebar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsSidebar.qml new file mode 100644 index 0000000..092881c --- /dev/null +++ b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/Settings/SettingsSidebar.qml @@ -0,0 +1,1023 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import qs.Common +import qs.Modals.Settings +import qs.Services +import qs.Widgets + +Rectangle { + id: root + + LayoutMirroring.enabled: I18n.isRtl + LayoutMirroring.childrenInherit: true + + property int currentIndex: 0 + property var parentModal: null + + signal tabChangeRequested(int tabIndex) + property string _expandedIds: "," + property string _collapsedIds: "," + property string _autoExpandedIds: "," + property bool searchActive: searchField.text.length > 0 + property int searchSelectedIndex: 0 + property int keyboardHighlightIndex: -1 + + function focusSearch() { + searchField.forceActiveFocus(); + } + + function highlightNext() { + var flatItems = getFlatNavigableItems(); + if (flatItems.length === 0) + return; + var currentPos = flatItems.findIndex(item => item.tabIndex === keyboardHighlightIndex); + if (currentPos === -1) { + currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex); + } + var nextPos = (currentPos + 1) % flatItems.length; + keyboardHighlightIndex = flatItems[nextPos].tabIndex; + autoExpandForTab(keyboardHighlightIndex); + } + + function highlightPrevious() { + var flatItems = getFlatNavigableItems(); + if (flatItems.length === 0) + return; + var currentPos = flatItems.findIndex(item => item.tabIndex === keyboardHighlightIndex); + if (currentPos === -1) { + currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex); + } + var prevPos = (currentPos - 1 + flatItems.length) % flatItems.length; + keyboardHighlightIndex = flatItems[prevPos].tabIndex; + autoExpandForTab(keyboardHighlightIndex); + } + + function selectHighlighted() { + if (keyboardHighlightIndex < 0) + return; + var oldIndex = currentIndex; + var newIndex = keyboardHighlightIndex; + tabChangeRequested(newIndex); + autoCollapseIfNeeded(oldIndex, newIndex); + keyboardHighlightIndex = -1; + Qt.callLater(searchField.forceActiveFocus); + } + + readonly property var categoryStructure: [ + { + "id": "personalization", + "text": I18n.tr("Personalization"), + "icon": "palette", + "children": [ + { + "id": "wallpaper", + "text": I18n.tr("Wallpaper"), + "icon": "wallpaper", + "tabIndex": 0 + }, + { + "id": "theme", + "text": I18n.tr("Theme & Colors"), + "icon": "format_paint", + "tabIndex": 10 + }, + { + "id": "typography", + "text": I18n.tr("Typography & Motion"), + "icon": "text_fields", + "tabIndex": 14 + }, + { + "id": "time_weather", + "text": I18n.tr("Time & Weather"), + "icon": "schedule", + "tabIndex": 1 + }, + { + "id": "sounds", + "text": I18n.tr("Sounds"), + "icon": "volume_up", + "tabIndex": 15, + "soundsOnly": true + } + ] + }, + { + "id": "dankbar", + "text": I18n.tr("Dank Bar"), + "icon": "toolbar", + "children": [ + { + "id": "dankbar_settings", + "text": I18n.tr("Settings"), + "icon": "tune", + "tabIndex": 3 + }, + { + "id": "dankbar_widgets", + "text": I18n.tr("Widgets"), + "icon": "widgets", + "tabIndex": 22 + } + ] + }, + { + "id": "workspaces_widgets", + "text": I18n.tr("Workspaces & Widgets"), + "icon": "dashboard", + "collapsedByDefault": true, + "children": [ + { + "id": "workspaces", + "text": I18n.tr("Workspaces"), + "icon": "view_module", + "tabIndex": 4 + }, + { + "id": "media_player", + "text": I18n.tr("Media Player"), + "icon": "music_note", + "tabIndex": 16 + }, + { + "id": "notifications", + "text": I18n.tr("Notifications"), + "icon": "notifications", + "tabIndex": 17 + }, + { + "id": "osd", + "text": I18n.tr("On-screen Displays"), + "icon": "tune", + "tabIndex": 18 + }, + { + "id": "running_apps", + "text": I18n.tr("Running Apps"), + "icon": "app_registration", + "tabIndex": 19, + "hyprlandNiriOnly": true + }, + { + "id": "updater", + "text": I18n.tr("System Updater"), + "icon": "refresh", + "tabIndex": 20 + }, + { + "id": "desktop_widgets", + "text": I18n.tr("Desktop Widgets"), + "icon": "widgets", + "tabIndex": 27 + } + ] + }, + { + "id": "dock_launcher", + "text": I18n.tr("Dock & Launcher"), + "icon": "apps", + "collapsedByDefault": true, + "children": [ + { + "id": "dock", + "text": I18n.tr("Dock"), + "icon": "dock_to_bottom", + "tabIndex": 5 + }, + { + "id": "launcher", + "text": I18n.tr("Launcher"), + "icon": "grid_view", + "tabIndex": 9 + } + ] + }, + { + "id": "keybinds", + "text": I18n.tr("Keyboard Shortcuts"), + "icon": "keyboard", + "tabIndex": 2, + "shortcutsOnly": true + }, + { + "id": "displays", + "text": I18n.tr("Displays"), + "icon": "monitor", + "collapsedByDefault": true, + "children": [ + { + "id": "display_config", + "text": I18n.tr("Configuration"), + "icon": "display_settings", + "tabIndex": 24 + }, + { + "id": "display_gamma", + "text": I18n.tr("Gamma Control"), + "icon": "brightness_6", + "tabIndex": 25 + }, + { + "id": "display_widgets", + "text": I18n.tr("Widgets", "settings_displays"), + "icon": "widgets", + "tabIndex": 26 + } + ] + }, + { + "id": "network", + "text": I18n.tr("Network"), + "icon": "wifi", + "tabIndex": 7, + "dmsOnly": true + }, + { + "id": "system", + "text": I18n.tr("System"), + "icon": "memory", + "collapsedByDefault": true, + "children": [ + { + "id": "audio", + "text": I18n.tr("Audio"), + "icon": "headphones", + "tabIndex": 29 + }, + { + "id": "locale", + "text": I18n.tr("Locale"), + "icon": "language", + "tabIndex": 30 + }, + { + "id": "clipboard", + "text": I18n.tr("Clipboard"), + "icon": "content_paste", + "tabIndex": 23, + "clipboardOnly": true + }, + { + "id": "printers", + "text": I18n.tr("Printers"), + "icon": "print", + "tabIndex": 8, + "cupsOnly": true + }, + { + "id": "multiplexers", + "text": I18n.tr("Multiplexers"), + "icon": "terminal", + "tabIndex": 32 + }, + { + "id": "window_rules", + "text": I18n.tr("Window Rules"), + "icon": "select_window", + "tabIndex": 28, + "niriOnly": true + } + ] + }, + { + "id": "power_security", + "text": I18n.tr("Power & Security"), + "icon": "security", + "collapsedByDefault": true, + "children": [ + { + "id": "lock_screen", + "text": I18n.tr("Lock Screen"), + "icon": "lock", + "tabIndex": 11 + }, + { + "id": "greeter", + "text": I18n.tr("Greeter"), + "icon": "login", + "tabIndex": 31 + }, + { + "id": "power_sleep", + "text": I18n.tr("Power & Sleep"), + "icon": "power_settings_new", + "tabIndex": 21 + } + ] + }, + { + "id": "plugins", + "text": I18n.tr("Plugins"), + "icon": "extension", + "tabIndex": 12 + }, + { + "id": "separator", + "separator": true + }, + { + "id": "about", + "text": I18n.tr("About"), + "icon": "info", + "tabIndex": 13 + } + ] + + function isItemVisible(item) { + if (item.dmsOnly && NetworkService.usingLegacy) + return false; + if (item.cupsOnly && !CupsService.cupsAvailable) + return false; + if (item.shortcutsOnly && !KeybindsService.available) + return false; + if (item.soundsOnly && !AudioService.soundsAvailable) + return false; + if (item.hyprlandNiriOnly && !CompositorService.isNiri && !CompositorService.isHyprland) + return false; + if (item.niriOnly && !CompositorService.isNiri) + return false; + if (item.clipboardOnly && (!DMSService.isConnected || DMSService.apiVersion < 23)) + return false; + return true; + } + + function hasVisibleChildren(category) { + if (!category.children) + return false; + return category.children.some(child => isItemVisible(child)); + } + + function isCategoryVisible(category) { + if (category.separator) + return true; + if (!isItemVisible(category)) + return false; + if (category.children && !hasVisibleChildren(category)) + return false; + return true; + } + + function _setExpanded(id, expanded) { + var marker = "," + id + ","; + if (expanded) { + if (_expandedIds.indexOf(marker) < 0) + _expandedIds = _expandedIds + id + ","; + _collapsedIds = _collapsedIds.replace(marker, ","); + } else { + _expandedIds = _expandedIds.replace(marker, ","); + if (_collapsedIds.indexOf(marker) < 0) + _collapsedIds = _collapsedIds + id + ","; + } + SessionData.setSettingsSidebarState(_expandedIds, _collapsedIds); + } + + function _setAutoExpanded(id, value) { + var marker = "," + id + ","; + if (value) { + if (_autoExpandedIds.indexOf(marker) < 0) + _autoExpandedIds = _autoExpandedIds + id + ","; + } else { + _autoExpandedIds = _autoExpandedIds.replace(marker, ","); + } + } + + function _isAutoExpanded(id) { + return _autoExpandedIds.indexOf("," + id + ",") >= 0; + } + + function toggleCategory(categoryId) { + _setExpanded(categoryId, !isCategoryExpanded(categoryId)); + _setAutoExpanded(categoryId, false); + } + + function isCategoryExpanded(categoryId) { + if (_collapsedIds.indexOf("," + categoryId + ",") >= 0) + return false; + if (_expandedIds.indexOf("," + categoryId + ",") >= 0) + return true; + var category = categoryStructure.find(cat => cat.id === categoryId); + if (category && category.collapsedByDefault) + return false; + return true; + } + + function isChildActive(category) { + if (!category.children) + return false; + return category.children.some(child => child.tabIndex === currentIndex); + } + + function findParentCategory(tabIndex) { + for (var i = 0; i < categoryStructure.length; i++) { + var cat = categoryStructure[i]; + if (cat.children) { + for (var j = 0; j < cat.children.length; j++) { + if (cat.children[j].tabIndex === tabIndex) { + return cat; + } + } + } + } + return null; + } + + function autoExpandForTab(tabIndex) { + var parent = findParentCategory(tabIndex); + if (!parent) + return; + + if (!isCategoryExpanded(parent.id)) { + _setExpanded(parent.id, true); + _setAutoExpanded(parent.id, true); + } + } + + function autoCollapseIfNeeded(oldTabIndex, newTabIndex) { + var oldParent = findParentCategory(oldTabIndex); + var newParent = findParentCategory(newTabIndex); + + if (oldParent && oldParent !== newParent && _isAutoExpanded(oldParent.id)) { + _setExpanded(oldParent.id, false); + _setAutoExpanded(oldParent.id, false); + } + } + + function navigateNext() { + var flatItems = getFlatNavigableItems(); + var currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex); + var oldIndex = currentIndex; + var newIndex; + if (currentPos === -1) { + newIndex = flatItems[0]?.tabIndex ?? 0; + } else { + var nextPos = (currentPos + 1) % flatItems.length; + newIndex = flatItems[nextPos].tabIndex; + } + tabChangeRequested(newIndex); + autoCollapseIfNeeded(oldIndex, newIndex); + autoExpandForTab(newIndex); + } + + function navigatePrevious() { + var flatItems = getFlatNavigableItems(); + var currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex); + var oldIndex = currentIndex; + var newIndex; + if (currentPos === -1) { + newIndex = flatItems[0]?.tabIndex ?? 0; + } else { + var prevPos = (currentPos - 1 + flatItems.length) % flatItems.length; + newIndex = flatItems[prevPos].tabIndex; + } + tabChangeRequested(newIndex); + autoCollapseIfNeeded(oldIndex, newIndex); + autoExpandForTab(newIndex); + } + + function getFlatNavigableItems() { + var items = []; + for (var i = 0; i < categoryStructure.length; i++) { + var cat = categoryStructure[i]; + if (cat.separator || !isCategoryVisible(cat)) + continue; + + if (cat.tabIndex !== undefined && !cat.children) { + items.push(cat); + } + + if (cat.children) { + for (var j = 0; j < cat.children.length; j++) { + var child = cat.children[j]; + if (isItemVisible(child)) { + items.push(child); + } + } + } + } + return items; + } + + function resolveTabIndex(name: string): int { + if (!name) + return -1; + + var normalized = name.toLowerCase().replace(/[_\-\s]/g, ""); + + for (var i = 0; i < categoryStructure.length; i++) { + var cat = categoryStructure[i]; + if (cat.separator) + continue; + + var catId = (cat.id || "").toLowerCase().replace(/[_\-\s]/g, ""); + if (catId === normalized) { + if (cat.tabIndex !== undefined) + return cat.tabIndex; + if (cat.children && cat.children.length > 0) + return cat.children[0].tabIndex; + } + + if (cat.children) { + for (var j = 0; j < cat.children.length; j++) { + var child = cat.children[j]; + var childId = (child.id || "").toLowerCase().replace(/[_\-\s]/g, ""); + if (childId === normalized) + return child.tabIndex; + } + } + } + return -1; + } + + property real __maxTextWidth: Math.max(__m1.advanceWidth, __m2.advanceWidth, __m3.advanceWidth, __m4.advanceWidth, __m5.advanceWidth, __m6.advanceWidth) + property real __calculatedWidth: Math.max(270, __maxTextWidth + Theme.iconSize * 2 + Theme.spacingM * 4 + Theme.spacingS * 2) + + implicitWidth: __calculatedWidth + width: __calculatedWidth + height: parent.height + color: Theme.surfaceContainer + radius: Theme.cornerRadius + + Component.onCompleted: { + root._expandedIds = SessionData.settingsSidebarExpandedIds; + root._collapsedIds = SessionData.settingsSidebarCollapsedIds; + } + + StyledTextMetrics { + id: __m1 + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + text: I18n.tr("Workspaces & Widgets") + } + StyledTextMetrics { + id: __m2 + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + text: I18n.tr("Typography & Motion") + } + StyledTextMetrics { + id: __m3 + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + text: I18n.tr("Keyboard Shortcuts") + } + StyledTextMetrics { + id: __m4 + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + text: I18n.tr("Power & Security") + } + StyledTextMetrics { + id: __m5 + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + text: I18n.tr("Dock & Launcher") + } + StyledTextMetrics { + id: __m6 + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + text: I18n.tr("Personalization") + } + + function selectSearchResult(result) { + if (!result) + return; + if (result.section) { + SettingsSearchService.navigateToSection(result.section); + } + var oldIndex = root.currentIndex; + tabChangeRequested(result.tabIndex); + autoCollapseIfNeeded(oldIndex, result.tabIndex); + autoExpandForTab(result.tabIndex); + searchField.text = ""; + SettingsSearchService.clear(); + searchSelectedIndex = 0; + keyboardHighlightIndex = -1; + Qt.callLater(searchField.forceActiveFocus); + } + + function navigateSearchResults(delta) { + if (SettingsSearchService.results.length === 0) + return; + searchSelectedIndex = Math.max(0, Math.min(searchSelectedIndex + delta, SettingsSearchService.results.length - 1)); + } + + DankFlickable { + anchors.fill: parent + clip: true + contentHeight: sidebarColumn.height + + Column { + id: sidebarColumn + width: parent.width + leftPadding: Theme.spacingS + rightPadding: Theme.spacingS + bottomPadding: Theme.spacingL + topPadding: Theme.spacingM + 2 + spacing: 2 + + ProfileSection { + width: parent.width - parent.leftPadding - parent.rightPadding + parentModal: root.parentModal + } + + Rectangle { + width: parent.width - parent.leftPadding - parent.rightPadding + height: 1 + color: Theme.outline + opacity: 0.2 + } + + Item { + width: parent.width - parent.leftPadding - parent.rightPadding + height: Theme.spacingXS + } + + DankTextField { + id: searchField + width: parent.width - parent.leftPadding - parent.rightPadding + placeholderText: I18n.tr("Search...") + normalBorderColor: Theme.outlineMedium + focusedBorderColor: Theme.primary + leftIconName: "search" + leftIconSize: Theme.iconSize - 4 + showClearButton: text.length > 0 + usePopupTransparency: false + onTextChanged: { + SettingsSearchService.search(text); + root.searchSelectedIndex = 0; + } + keyForwardTargets: [keyHandler] + + Item { + id: keyHandler + function navNext() { + if (root.searchActive) { + root.navigateSearchResults(1); + } else { + root.highlightNext(); + } + } + function navPrev() { + if (root.searchActive) { + root.navigateSearchResults(-1); + } else { + root.highlightPrevious(); + } + } + function navSelect() { + if (root.searchActive && SettingsSearchService.results.length > 0) { + root.selectSearchResult(SettingsSearchService.results[root.searchSelectedIndex]); + } else if (root.keyboardHighlightIndex >= 0) { + root.selectHighlighted(); + } + } + Keys.onDownPressed: event => { + navNext(); + event.accepted = true; + } + Keys.onUpPressed: event => { + navPrev(); + event.accepted = true; + } + Keys.onTabPressed: event => { + navNext(); + event.accepted = true; + } + Keys.onBacktabPressed: event => { + navPrev(); + event.accepted = true; + } + Keys.onReturnPressed: event => { + navSelect(); + event.accepted = true; + } + Keys.onEscapePressed: event => { + if (root.searchActive) { + searchField.text = ""; + SettingsSearchService.clear(); + } else { + root.keyboardHighlightIndex = -1; + } + event.accepted = true; + } + } + } + + Column { + id: searchResultsColumn + width: parent.width - parent.leftPadding - parent.rightPadding + spacing: 2 + visible: root.searchActive + + Item { + width: parent.width + height: Theme.spacingS + } + + Repeater { + model: ScriptModel { + values: SettingsSearchService.results + } + + Rectangle { + id: resultDelegate + required property int index + required property var modelData + + width: searchResultsColumn.width + height: resultContent.height + Theme.spacingM * 2 + radius: Theme.cornerRadius + color: { + if (root.searchSelectedIndex === index) + return Theme.buttonBg; + if (resultMouseArea.containsMouse) + return Theme.surfaceHover; + return "transparent"; + } + + DankRipple { + id: resultRipple + rippleColor: root.searchSelectedIndex === resultDelegate.index ? Theme.buttonText : Theme.surfaceText + cornerRadius: resultDelegate.radius + } + + Row { + id: resultContent + anchors.left: parent.left + anchors.leftMargin: Theme.spacingM + anchors.right: parent.right + anchors.rightMargin: Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingM + + DankIcon { + name: resultDelegate.modelData.icon || "settings" + size: Theme.iconSize - 2 + color: root.searchSelectedIndex === resultDelegate.index ? Theme.buttonText : Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + Column { + width: parent.width - Theme.iconSize - Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + spacing: 2 + + StyledText { + text: resultDelegate.modelData.label + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + color: root.searchSelectedIndex === resultDelegate.index ? Theme.buttonText : Theme.surfaceText + width: parent.width + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignLeft + } + + StyledText { + text: resultDelegate.modelData.category + font.pixelSize: Theme.fontSizeSmall - 1 + color: root.searchSelectedIndex === resultDelegate.index ? Theme.withAlpha(Theme.buttonText, 0.7) : Theme.surfaceVariantText + width: parent.width + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignLeft + } + } + } + + MouseArea { + id: resultMouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onPressed: mouse => resultRipple.trigger(mouse.x, mouse.y) + onClicked: root.selectSearchResult(resultDelegate.modelData) + } + + Behavior on color { + ColorAnimation { + duration: Theme.shortDuration + easing.type: Theme.standardEasing + } + } + } + } + + StyledText { + width: parent.width + text: I18n.tr("No matches") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + horizontalAlignment: Text.AlignHCenter + visible: searchField.text.length > 0 && SettingsSearchService.results.length === 0 + topPadding: Theme.spacingM + } + } + + Item { + width: parent.width - parent.leftPadding - parent.rightPadding + height: Theme.spacingXS + visible: !root.searchActive + } + + Repeater { + model: root.categoryStructure + + delegate: Column { + id: categoryDelegate + required property int index + required property var modelData + + width: parent.width - parent.leftPadding - parent.rightPadding + visible: !root.searchActive && root.isCategoryVisible(modelData) + spacing: 2 + + Rectangle { + width: parent.width + height: 1 + color: Theme.outline + opacity: 0.15 + visible: categoryDelegate.modelData.separator === true + } + + Item { + width: parent.width + height: Theme.spacingS + visible: categoryDelegate.modelData.separator === true + } + + Rectangle { + id: categoryRow + width: parent.width + height: Math.max(Theme.iconSize, Theme.fontSizeMedium) + Theme.spacingS * 2 + radius: Theme.cornerRadius + visible: categoryDelegate.modelData.separator !== true + + readonly property bool hasTab: categoryDelegate.modelData.tabIndex !== undefined && !categoryDelegate.modelData.children + readonly property bool isActive: hasTab && root.currentIndex === categoryDelegate.modelData.tabIndex + readonly property bool isHighlighted: hasTab && root.keyboardHighlightIndex === categoryDelegate.modelData.tabIndex + + color: { + if (isActive) + return Theme.buttonBg; + if (isHighlighted) + return Theme.buttonHover; + if (categoryMouseArea.containsMouse) + return Theme.surfaceHover; + return "transparent"; + } + + DankRipple { + id: categoryRipple + rippleColor: categoryRow.isActive ? Theme.buttonText : Theme.surfaceText + cornerRadius: categoryRow.radius + } + + Row { + id: categoryRowContent + anchors.left: parent.left + anchors.leftMargin: Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingM + + DankIcon { + name: categoryDelegate.modelData.icon || "" + size: Theme.iconSize - 2 + color: categoryRow.isActive ? Theme.buttonText : Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: categoryDelegate.modelData.text || "" + font.pixelSize: Theme.fontSizeMedium + font.weight: (categoryRow.isActive || root.isChildActive(categoryDelegate.modelData)) ? Font.Medium : Font.Normal + color: categoryRow.isActive ? Theme.buttonText : Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + } + + DankIcon { + id: expandIcon + name: root.isCategoryExpanded(categoryDelegate.modelData.id) ? "expand_less" : "expand_more" + size: Theme.iconSize - 4 + color: Theme.surfaceVariantText + anchors.right: parent.right + anchors.rightMargin: Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + visible: categoryDelegate.modelData.children !== undefined && categoryDelegate.modelData.children.length > 0 + } + + MouseArea { + id: categoryMouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onPressed: mouse => categoryRipple.trigger(mouse.x, mouse.y) + onClicked: { + root.keyboardHighlightIndex = -1; + if (categoryDelegate.modelData.children) { + root.toggleCategory(categoryDelegate.modelData.id); + } else if (categoryDelegate.modelData.tabIndex !== undefined) { + root.tabChangeRequested(categoryDelegate.modelData.tabIndex); + } + Qt.callLater(searchField.forceActiveFocus); + } + } + + Behavior on color { + ColorAnimation { + duration: Theme.shortDuration + easing.type: Theme.standardEasing + } + } + } + + Column { + id: childrenColumn + width: parent.width + spacing: 2 + visible: categoryDelegate.modelData.children !== undefined && root.isCategoryExpanded(categoryDelegate.modelData.id) + clip: true + + Repeater { + model: categoryDelegate.modelData.children || [] + + delegate: Rectangle { + id: childDelegate + required property int index + required property var modelData + + readonly property bool isActive: root.currentIndex === modelData.tabIndex + readonly property bool isHighlighted: root.keyboardHighlightIndex === modelData.tabIndex + + width: childrenColumn.width + height: Math.max(Theme.iconSize - 4, Theme.fontSizeSmall + 1) + Theme.spacingS * 2 + radius: Theme.cornerRadius + visible: root.isItemVisible(modelData) + color: { + if (isActive) + return Theme.buttonBg; + if (isHighlighted) + return Theme.buttonHover; + if (childMouseArea.containsMouse) + return Theme.surfaceHover; + return "transparent"; + } + + DankRipple { + id: childRipple + rippleColor: childDelegate.isActive ? Theme.buttonText : Theme.surfaceText + cornerRadius: childDelegate.radius + } + + Row { + id: childRowContent + anchors.left: parent.left + anchors.leftMargin: Theme.spacingL + Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingM + + DankIcon { + name: childDelegate.modelData.icon || "" + size: Theme.iconSize - 4 + color: childDelegate.isActive ? Theme.buttonText : Theme.surfaceVariantText + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: childDelegate.modelData.text || "" + font.pixelSize: Theme.fontSizeSmall + 1 + font.weight: childDelegate.isActive ? Font.Medium : Font.Normal + color: childDelegate.isActive ? Theme.buttonText : Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + } + + MouseArea { + id: childMouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onPressed: mouse => childRipple.trigger(mouse.x, mouse.y) + onClicked: { + root.keyboardHighlightIndex = -1; + root.tabChangeRequested(childDelegate.modelData.tabIndex); + Qt.callLater(searchField.forceActiveFocus); + } + } + + Behavior on color { + ColorAnimation { + duration: Theme.shortDuration + easing.type: Theme.standardEasing + } + } + } + } + } + } + } + } + } +} |