mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-29 07:52:50 -05:00
Add DankIconPicker
This commit is contained in:
@@ -40,6 +40,7 @@ Singleton {
|
|||||||
property bool showControlCenterButton: true
|
property bool showControlCenterButton: true
|
||||||
property bool showWorkspaceIndex: false
|
property bool showWorkspaceIndex: false
|
||||||
property bool showWorkspacePadding: false
|
property bool showWorkspacePadding: false
|
||||||
|
property var workspaceNameIcons: ({})
|
||||||
property bool clockCompactMode: false
|
property bool clockCompactMode: false
|
||||||
property string clockDateFormat: "ddd d"
|
property string clockDateFormat: "ddd d"
|
||||||
property string lockDateFormat: "dddd, MMMM d"
|
property string lockDateFormat: "dddd, MMMM d"
|
||||||
@@ -85,6 +86,7 @@ Singleton {
|
|||||||
|
|
||||||
signal forceTopBarLayoutRefresh()
|
signal forceTopBarLayoutRefresh()
|
||||||
signal widgetDataChanged()
|
signal widgetDataChanged()
|
||||||
|
signal workspaceIconsUpdated()
|
||||||
|
|
||||||
function initializeListModels() {
|
function initializeListModels() {
|
||||||
updateListModel(leftWidgetsModel, topBarLeftWidgets);
|
updateListModel(leftWidgetsModel, topBarLeftWidgets);
|
||||||
@@ -132,6 +134,7 @@ Singleton {
|
|||||||
showControlCenterButton = settings.showControlCenterButton !== undefined ? settings.showControlCenterButton : true;
|
showControlCenterButton = settings.showControlCenterButton !== undefined ? settings.showControlCenterButton : true;
|
||||||
showWorkspaceIndex = settings.showWorkspaceIndex !== undefined ? settings.showWorkspaceIndex : false;
|
showWorkspaceIndex = settings.showWorkspaceIndex !== undefined ? settings.showWorkspaceIndex : false;
|
||||||
showWorkspacePadding = settings.showWorkspacePadding !== undefined ? settings.showWorkspacePadding : false;
|
showWorkspacePadding = settings.showWorkspacePadding !== undefined ? settings.showWorkspacePadding : false;
|
||||||
|
workspaceNameIcons = settings.workspaceNameIcons !== undefined ? settings.workspaceNameIcons : ({});
|
||||||
clockCompactMode = settings.clockCompactMode !== undefined ? settings.clockCompactMode : false;
|
clockCompactMode = settings.clockCompactMode !== undefined ? settings.clockCompactMode : false;
|
||||||
clockDateFormat = settings.clockDateFormat !== undefined ? settings.clockDateFormat : "ddd d";
|
clockDateFormat = settings.clockDateFormat !== undefined ? settings.clockDateFormat : "ddd d";
|
||||||
lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : "dddd, MMMM d";
|
lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : "dddd, MMMM d";
|
||||||
@@ -226,6 +229,7 @@ Singleton {
|
|||||||
"showControlCenterButton": showControlCenterButton,
|
"showControlCenterButton": showControlCenterButton,
|
||||||
"showWorkspaceIndex": showWorkspaceIndex,
|
"showWorkspaceIndex": showWorkspaceIndex,
|
||||||
"showWorkspacePadding": showWorkspacePadding,
|
"showWorkspacePadding": showWorkspacePadding,
|
||||||
|
"workspaceNameIcons": workspaceNameIcons,
|
||||||
"clockCompactMode": clockCompactMode,
|
"clockCompactMode": clockCompactMode,
|
||||||
"clockDateFormat": clockDateFormat,
|
"clockDateFormat": clockDateFormat,
|
||||||
"lockDateFormat": lockDateFormat,
|
"lockDateFormat": lockDateFormat,
|
||||||
@@ -268,6 +272,52 @@ Singleton {
|
|||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setWorkspaceNameIcon(workspaceName, iconData) {
|
||||||
|
var iconMap = JSON.parse(JSON.stringify(workspaceNameIcons));
|
||||||
|
iconMap[workspaceName] = iconData;
|
||||||
|
workspaceNameIcons = iconMap;
|
||||||
|
saveSettings();
|
||||||
|
workspaceIconsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeWorkspaceNameIcon(workspaceName) {
|
||||||
|
var iconMap = JSON.parse(JSON.stringify(workspaceNameIcons));
|
||||||
|
delete iconMap[workspaceName];
|
||||||
|
workspaceNameIcons = iconMap;
|
||||||
|
saveSettings();
|
||||||
|
workspaceIconsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWorkspaceNameIcon(workspaceName) {
|
||||||
|
return workspaceNameIcons[workspaceName] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasNamedWorkspaces() {
|
||||||
|
if (typeof NiriService === "undefined" || !NiriService.niriAvailable)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
||||||
|
var ws = NiriService.allWorkspaces[i];
|
||||||
|
if (ws.name && ws.name.trim() !== "")
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNamedWorkspaces() {
|
||||||
|
var namedWorkspaces = [];
|
||||||
|
if (typeof NiriService === "undefined" || !NiriService.niriAvailable)
|
||||||
|
return namedWorkspaces;
|
||||||
|
|
||||||
|
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
||||||
|
var ws = NiriService.allWorkspaces[i];
|
||||||
|
if (ws.name && ws.name.trim() !== "") {
|
||||||
|
namedWorkspaces.push(ws.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return namedWorkspaces;
|
||||||
|
}
|
||||||
|
|
||||||
function setClockCompactMode(enabled) {
|
function setClockCompactMode(enabled) {
|
||||||
clockCompactMode = enabled;
|
clockCompactMode = enabled;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
|
|||||||
@@ -456,6 +456,12 @@ Item {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
sourceComponent: workspaceComponent
|
sourceComponent: workspaceComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
width: parent.width
|
||||||
|
sourceComponent: workspaceIconsComponent
|
||||||
|
visible: SettingsData.hasNamedWorkspaces()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,6 +785,159 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Workspace Icons Component
|
||||||
|
Component {
|
||||||
|
id: workspaceIconsComponent
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
width: parent.width
|
||||||
|
height: workspaceIconsSection.implicitHeight + Theme.spacingL * 2
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
||||||
|
Theme.surfaceVariant.b, 0.3)
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||||
|
Theme.outline.b, 0.2)
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: workspaceIconsSection
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "label"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Named Workspace Icons"
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width
|
||||||
|
text: "Configure icons for named workspaces. Icons take priority over numbers when both are enabled."
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.outline
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: SettingsData.getNamedWorkspaces()
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: workspaceIconRow.implicitHeight + Theme.spacingM
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
|
||||||
|
Theme.surfaceContainer.b, 0.5)
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||||
|
Theme.outline.b, 0.3)
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: workspaceIconRow
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: Theme.spacingM
|
||||||
|
anchors.rightMargin: Theme.spacingM
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "\"" + modelData + "\""
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: 150
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIconPicker {
|
||||||
|
id: iconPicker
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
var iconData = SettingsData.getWorkspaceNameIcon(modelData)
|
||||||
|
if (iconData) {
|
||||||
|
setIcon(iconData.value, iconData.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onIconSelected: (iconName, iconType) => {
|
||||||
|
SettingsData.setWorkspaceNameIcon(modelData, {
|
||||||
|
type: iconType,
|
||||||
|
value: iconName
|
||||||
|
})
|
||||||
|
setIcon(iconName, iconType)
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: SettingsData
|
||||||
|
function onWorkspaceIconsUpdated() {
|
||||||
|
var iconData = SettingsData.getWorkspaceNameIcon(modelData)
|
||||||
|
if (iconData) {
|
||||||
|
iconPicker.setIcon(iconData.value, iconData.type)
|
||||||
|
} else {
|
||||||
|
iconPicker.setIcon("", "icon")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 28
|
||||||
|
height: 28
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: clearMouseArea.containsMouse ? Theme.errorHover : Theme.surfaceContainer
|
||||||
|
border.color: clearMouseArea.containsMouse ? Theme.error : Theme.outline
|
||||||
|
border.width: 1
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "close"
|
||||||
|
size: 16
|
||||||
|
color: clearMouseArea.containsMouse ? Theme.error : Theme.outline
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: clearMouseArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
SettingsData.removeWorkspaceNameIcon(modelData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width - 150 - 240 - 28 - Theme.spacingM * 4
|
||||||
|
height: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DankWidgetSelectionPopup {
|
DankWidgetSelectionPopup {
|
||||||
id: widgetSelectionPopup
|
id: widgetSelectionPopup
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,16 @@ Rectangle {
|
|||||||
property bool isPlaceholder: modelData === -1
|
property bool isPlaceholder: modelData === -1
|
||||||
property bool isHovered: mouseArea.containsMouse
|
property bool isHovered: mouseArea.containsMouse
|
||||||
property int sequentialNumber: index + 1
|
property int sequentialNumber: index + 1
|
||||||
|
property var workspaceData: {
|
||||||
|
if (isPlaceholder || !NiriService.niriAvailable) return null
|
||||||
|
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
||||||
|
var ws = NiriService.allWorkspaces[i]
|
||||||
|
if (ws.idx + 1 === modelData) return ws
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
property var iconData: workspaceData && workspaceData.name ? SettingsData.getWorkspaceNameIcon(workspaceData.name) : null
|
||||||
|
property bool hasIcon: iconData !== null
|
||||||
|
|
||||||
width: isActive ? Theme.spacingXL + Theme.spacingM : Theme.spacingL + Theme.spacingXS
|
width: isActive ? Theme.spacingXL + Theme.spacingM : Theme.spacingL + Theme.spacingXS
|
||||||
height: Theme.spacingL
|
height: Theme.spacingL
|
||||||
@@ -137,8 +147,37 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Icon display (priority over numbers)
|
||||||
|
DankIcon {
|
||||||
|
visible: hasIcon && iconData.type === "icon"
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: hasIcon && iconData.type === "icon" ? iconData.value : ""
|
||||||
|
size: Theme.fontSizeSmall
|
||||||
|
color: isActive ? Qt.rgba(
|
||||||
|
Theme.surfaceContainer.r,
|
||||||
|
Theme.surfaceContainer.g,
|
||||||
|
Theme.surfaceContainer.b,
|
||||||
|
0.95) : Theme.surfaceTextMedium
|
||||||
|
weight: isActive && !isPlaceholder ? 500 : 400
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom text display (priority over numbers)
|
||||||
StyledText {
|
StyledText {
|
||||||
visible: SettingsData.showWorkspaceIndex
|
visible: hasIcon && iconData.type === "text"
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: hasIcon && iconData.type === "text" ? iconData.value : ""
|
||||||
|
color: isActive ? Qt.rgba(
|
||||||
|
Theme.surfaceContainer.r,
|
||||||
|
Theme.surfaceContainer.g,
|
||||||
|
Theme.surfaceContainer.b,
|
||||||
|
0.95) : Theme.surfaceTextMedium
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: isActive && !isPlaceholder ? Font.DemiBold : Font.Normal
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number display (secondary priority, only when no icon)
|
||||||
|
StyledText {
|
||||||
|
visible: SettingsData.showWorkspaceIndex && !hasIcon
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: isPlaceholder ? sequentialNumber : sequentialNumber
|
text: isPlaceholder ? sequentialNumber : sequentialNumber
|
||||||
color: isActive ? Qt.rgba(
|
color: isActive ? Qt.rgba(
|
||||||
|
|||||||
330
Widgets/DankIconPicker.qml
Normal file
330
Widgets/DankIconPicker.qml
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Effects
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import qs.Common
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string currentIcon: ""
|
||||||
|
property string currentText: ""
|
||||||
|
property string iconType: "icon" // "icon" or "text"
|
||||||
|
|
||||||
|
signal iconSelected(string iconName, string iconType)
|
||||||
|
|
||||||
|
width: 240
|
||||||
|
height: 32
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
border.color: dropdownPopup.visible ? Theme.primary : (mouseArea.containsMouse ? Theme.outline : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.5))
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
property var iconCategories: [
|
||||||
|
{
|
||||||
|
name: "Workspace",
|
||||||
|
icons: ["work", "laptop", "desktop_windows", "code", "terminal", "build", "settings", "folder", "view_module", "dashboard", "apps", "grid_view"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Development",
|
||||||
|
icons: ["code", "terminal", "bug_report", "build", "engineering", "integration_instructions", "data_object", "schema", "api", "webhook"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Communication",
|
||||||
|
icons: ["chat", "mail", "forum", "message", "video_call", "call", "contacts", "group", "notifications", "campaign"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Media",
|
||||||
|
icons: ["music_note", "headphones", "mic", "videocam", "photo", "movie", "library_music", "album", "radio", "volume_up"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "System",
|
||||||
|
icons: ["memory", "storage", "developer_board", "monitor", "keyboard", "mouse", "battery_std", "wifi", "bluetooth", "security"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Navigation",
|
||||||
|
icons: ["home", "arrow_forward", "arrow_back", "expand_more", "expand_less", "menu", "close", "search", "filter_list", "sort"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Actions",
|
||||||
|
icons: ["add", "remove", "edit", "delete", "save", "download", "upload", "share", "content_copy", "content_paste", "content_cut", "undo", "redo"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Status",
|
||||||
|
icons: ["check", "close", "error", "warning", "info", "done", "pending", "schedule", "update", "sync", "offline_bolt"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fun",
|
||||||
|
icons: ["celebration", "cake", "star", "favorite", "pets", "sports_esports", "local_fire_department", "bolt", "auto_awesome", "diamond"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: {
|
||||||
|
if (dropdownPopup.visible) {
|
||||||
|
dropdownPopup.visible = false
|
||||||
|
} else {
|
||||||
|
dropdownPopup.visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: root.iconType === "icon" && root.currentIcon ? root.currentIcon : (root.iconType === "text" ? "text_fields" : "add")
|
||||||
|
size: 16
|
||||||
|
color: root.currentIcon || root.currentText ? Theme.surfaceText : Theme.outline
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: {
|
||||||
|
if (root.iconType === "text" && root.currentText) return root.currentText
|
||||||
|
if (root.iconType === "icon" && root.currentIcon) return root.currentIcon
|
||||||
|
return "Choose icon or text"
|
||||||
|
}
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: root.currentIcon || root.currentText ? Theme.surfaceText : Theme.outline
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: 160
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: dropdownPopup.visible ? "expand_less" : "expand_more"
|
||||||
|
size: 16
|
||||||
|
color: Theme.outline
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: dropdownPopup
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
implicitWidth: 320
|
||||||
|
implicitHeight: Math.min(500, dropdownContent.implicitHeight + 32)
|
||||||
|
color: "transparent"
|
||||||
|
WlrLayershell.layer: WlrLayershell.Overlay
|
||||||
|
WlrLayershell.exclusiveZone: -1
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
left: true
|
||||||
|
right: true
|
||||||
|
bottom: true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click outside to close
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: dropdownPopup.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 320
|
||||||
|
height: Math.min(500, dropdownContent.implicitHeight + 32)
|
||||||
|
x: {
|
||||||
|
// Get the root picker's position relative to the screen
|
||||||
|
var pickerPos = root.mapToItem(null, 0, 0)
|
||||||
|
return Math.max(16, Math.min(pickerPos.x, parent.width - width - 16))
|
||||||
|
}
|
||||||
|
y: {
|
||||||
|
// Position below the picker button
|
||||||
|
var pickerPos = root.mapToItem(null, 0, root.height + 4)
|
||||||
|
return Math.max(16, Math.min(pickerPos.y, parent.height - height - 16))
|
||||||
|
}
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surface
|
||||||
|
border.color: Theme.outline
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
// Prevent this from closing the dropdown when clicked
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
// Don't propagate clicks to parent
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: MultiEffect {
|
||||||
|
shadowEnabled: true
|
||||||
|
shadowColor: Theme.shadowDark
|
||||||
|
shadowBlur: 0.8
|
||||||
|
shadowHorizontalOffset: 0
|
||||||
|
shadowVerticalOffset: 4
|
||||||
|
}
|
||||||
|
|
||||||
|
DankFlickable {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
contentHeight: dropdownContent.height
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: dropdownContent
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
// Custom text section
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: customTextSection.implicitHeight + Theme.spacingS * 2
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: customTextSection
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Custom Text"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 28
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
border.color: customTextInput.activeFocus ? Theme.primary : Theme.outline
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "text_fields"
|
||||||
|
size: 14
|
||||||
|
color: Theme.outline
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
TextInput {
|
||||||
|
id: customTextInput
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: 200
|
||||||
|
text: root.iconType === "text" ? root.currentText : ""
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
selectByMouse: true
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
var trimmedText = text.trim()
|
||||||
|
if (trimmedText) {
|
||||||
|
root.iconSelected(trimmedText, "text")
|
||||||
|
dropdownPopup.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingS + 14 + Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: "1-2 characters"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.outline
|
||||||
|
opacity: 0.6
|
||||||
|
visible: customTextInput.text === ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Icon categories
|
||||||
|
Repeater {
|
||||||
|
model: root.iconCategories
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: modelData.name
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
Flow {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: modelData.icons
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 36
|
||||||
|
height: 36
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: iconMouseArea.containsMouse ? Theme.primaryHover : "transparent"
|
||||||
|
border.color: root.currentIcon === modelData ? Theme.primary : "transparent"
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: modelData
|
||||||
|
size: 20
|
||||||
|
color: root.currentIcon === modelData ? Theme.primary : Theme.surfaceText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: iconMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
root.iconSelected(modelData, "icon")
|
||||||
|
dropdownPopup.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setIcon(iconName, type) {
|
||||||
|
if (type === "text") {
|
||||||
|
root.currentText = iconName
|
||||||
|
root.currentIcon = ""
|
||||||
|
root.iconType = "text"
|
||||||
|
} else {
|
||||||
|
root.currentIcon = iconName
|
||||||
|
root.currentText = ""
|
||||||
|
root.iconType = "icon"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user