mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-29 16:02:51 -05:00
widgets: make dank icon picker a popup
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
@@ -10,7 +8,7 @@ Rectangle {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string currentIcon: ""
|
property string currentIcon: ""
|
||||||
property string iconType: "icon" // "icon" or "text"
|
property string iconType: "icon"
|
||||||
|
|
||||||
signal iconSelected(string iconName, string iconType)
|
signal iconSelected(string iconName, string iconType)
|
||||||
|
|
||||||
@@ -18,40 +16,73 @@ Rectangle {
|
|||||||
height: 32
|
height: 32
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceContainer
|
color: Theme.surfaceContainer
|
||||||
border.color: dropdownLoader.active ? Theme.primary : Theme.outline
|
border.color: iconPopup.visible ? Theme.primary : Theme.outline
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
|
||||||
property var iconCategories: [{
|
property var iconCategories: [
|
||||||
|
{
|
||||||
"name": I18n.tr("Numbers"),
|
"name": I18n.tr("Numbers"),
|
||||||
"icons": ["looks_one", "looks_two", "looks_3", "looks_4", "looks_5", "looks_6", "filter_1", "filter_2", "filter_3", "filter_4", "filter_5", "filter_6", "filter_7", "filter_8", "filter_9", "filter_9_plus", "plus_one", "exposure_plus_1", "exposure_plus_2"]
|
"icons": ["looks_one", "looks_two", "looks_3", "looks_4", "looks_5", "looks_6", "filter_1", "filter_2", "filter_3", "filter_4", "filter_5", "filter_6", "filter_7", "filter_8", "filter_9", "filter_9_plus", "plus_one", "exposure_plus_1", "exposure_plus_2"]
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": I18n.tr("Workspace"),
|
"name": I18n.tr("Workspace"),
|
||||||
"icons": ["work", "laptop", "desktop_windows", "folder", "view_module", "dashboard", "apps", "grid_view"]
|
"icons": ["work", "laptop", "desktop_windows", "folder", "view_module", "dashboard", "apps", "grid_view"]
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": I18n.tr("Development"),
|
"name": I18n.tr("Development"),
|
||||||
"icons": ["code", "terminal", "bug_report", "build", "engineering", "integration_instructions", "data_object", "schema", "api", "webhook"]
|
"icons": ["code", "terminal", "bug_report", "build", "engineering", "integration_instructions", "data_object", "schema", "api", "webhook"]
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": I18n.tr("Communication"),
|
"name": I18n.tr("Communication"),
|
||||||
"icons": ["chat", "mail", "forum", "message", "video_call", "call", "contacts", "group", "notifications", "campaign"]
|
"icons": ["chat", "mail", "forum", "message", "video_call", "call", "contacts", "group", "notifications", "campaign"]
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": I18n.tr("Media"),
|
"name": I18n.tr("Media"),
|
||||||
"icons": ["music_note", "headphones", "mic", "videocam", "photo", "movie", "library_music", "album", "radio", "volume_up"]
|
"icons": ["music_note", "headphones", "mic", "videocam", "photo", "movie", "library_music", "album", "radio", "volume_up"]
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": I18n.tr("System"),
|
"name": I18n.tr("System"),
|
||||||
"icons": ["memory", "storage", "developer_board", "monitor", "keyboard", "mouse", "battery_std", "wifi", "bluetooth", "security", "settings"]
|
"icons": ["memory", "storage", "developer_board", "monitor", "keyboard", "mouse", "battery_std", "wifi", "bluetooth", "security", "settings"]
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": I18n.tr("Navigation"),
|
"name": I18n.tr("Navigation"),
|
||||||
"icons": ["home", "arrow_forward", "arrow_back", "expand_more", "expand_less", "menu", "close", "search", "filter_list", "sort"]
|
"icons": ["home", "arrow_forward", "arrow_back", "expand_more", "expand_less", "menu", "close", "search", "filter_list", "sort"]
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": I18n.tr("Actions"),
|
"name": I18n.tr("Actions"),
|
||||||
"icons": ["add", "remove", "edit", "delete", "save", "download", "upload", "share", "content_copy", "content_paste", "content_cut", "undo", "redo"]
|
"icons": ["add", "remove", "edit", "delete", "save", "download", "upload", "share", "content_copy", "content_paste", "content_cut", "undo", "redo"]
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": I18n.tr("Status"),
|
"name": I18n.tr("Status"),
|
||||||
"icons": ["check", "error", "warning", "info", "done", "pending", "schedule", "update", "sync", "offline_bolt"]
|
"icons": ["check", "error", "warning", "info", "done", "pending", "schedule", "update", "sync", "offline_bolt"]
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"name": I18n.tr("Fun"),
|
"name": I18n.tr("Fun"),
|
||||||
"icons": ["celebration", "cake", "star", "favorite", "pets", "sports_esports", "local_fire_department", "bolt", "auto_awesome", "diamond"]
|
"icons": ["celebration", "cake", "star", "favorite", "pets", "sports_esports", "local_fire_department", "bolt", "auto_awesome", "diamond"]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
if (iconPopup.visible) {
|
||||||
|
iconPopup.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const pos = root.mapToItem(Overlay.overlay, 0, 0);
|
||||||
|
const popupHeight = 500;
|
||||||
|
const overlayHeight = Overlay.overlay?.height ?? 800;
|
||||||
|
iconPopup.x = pos.x;
|
||||||
|
if (pos.y + root.height + popupHeight + 4 > overlayHeight) {
|
||||||
|
iconPopup.y = pos.y - popupHeight - 4;
|
||||||
|
} else {
|
||||||
|
iconPopup.y = pos.y + root.height + 4;
|
||||||
|
}
|
||||||
|
iconPopup.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -73,18 +104,11 @@ Rectangle {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: 160
|
width: 160
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: {
|
|
||||||
dropdownLoader.active = !dropdownLoader.active
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: dropdownLoader.active ? "expand_less" : "expand_more"
|
name: iconPopup.visible ? "expand_less" : "expand_more"
|
||||||
size: 16
|
size: 16
|
||||||
color: Theme.outline
|
color: Theme.outline
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
@@ -92,185 +116,126 @@ Rectangle {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Popup {
|
||||||
id: dropdownLoader
|
id: iconPopup
|
||||||
active: false
|
|
||||||
asynchronous: true
|
|
||||||
|
|
||||||
sourceComponent: PanelWindow {
|
parent: Overlay.overlay
|
||||||
id: dropdownPopup
|
width: 320
|
||||||
|
height: Math.min(500, dropdownContent.implicitHeight + 32)
|
||||||
|
padding: 0
|
||||||
|
modal: true
|
||||||
|
dim: false
|
||||||
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||||
|
|
||||||
visible: true
|
background: Rectangle {
|
||||||
implicitWidth: 320
|
|
||||||
implicitHeight: Math.min(500, dropdownContent.implicitHeight + 32)
|
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
WlrLayershell.layer: WlrLayershell.Overlay
|
}
|
||||||
WlrLayershell.exclusiveZone: -1
|
|
||||||
|
|
||||||
anchors {
|
contentItem: Rectangle {
|
||||||
top: true
|
color: Theme.surface
|
||||||
left: true
|
radius: Theme.cornerRadius
|
||||||
right: true
|
|
||||||
bottom: true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top area - above popup
|
layer.enabled: true
|
||||||
MouseArea {
|
layer.effect: MultiEffect {
|
||||||
anchors.left: parent.left
|
shadowEnabled: true
|
||||||
anchors.right: parent.right
|
shadowColor: Theme.shadowStrong
|
||||||
anchors.top: parent.top
|
shadowBlur: 0.8
|
||||||
height: popupContainer.y
|
shadowHorizontalOffset: 0
|
||||||
onClicked: {
|
shadowVerticalOffset: 4
|
||||||
dropdownLoader.active = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bottom area - below popup
|
|
||||||
MouseArea {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: popupContainer.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
onClicked: {
|
|
||||||
dropdownLoader.active = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Left area - left of popup
|
|
||||||
MouseArea {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: popupContainer.top
|
|
||||||
anchors.bottom: popupContainer.bottom
|
|
||||||
width: popupContainer.x
|
|
||||||
onClicked: {
|
|
||||||
dropdownLoader.active = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right area - right of popup
|
|
||||||
MouseArea {
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: popupContainer.top
|
|
||||||
anchors.bottom: popupContainer.bottom
|
|
||||||
anchors.left: popupContainer.right
|
|
||||||
onClicked: {
|
|
||||||
dropdownLoader.active = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: popupContainer
|
width: 24
|
||||||
width: 320
|
height: 24
|
||||||
height: Math.min(500, dropdownContent.implicitHeight + 32)
|
radius: 12
|
||||||
x: Math.max(16, Math.min(root.mapToItem(null, 0, 0).x, parent.width - width - 16))
|
color: closeMouseArea.containsMouse ? Theme.errorHover : "transparent"
|
||||||
y: Math.max(16, Math.min(root.mapToItem(null, 0, root.height + 4).y, parent.height - height - 16))
|
anchors.top: parent.top
|
||||||
radius: Theme.cornerRadius
|
anchors.right: parent.right
|
||||||
color: Theme.surface
|
anchors.topMargin: Theme.spacingS
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
z: 1
|
||||||
|
|
||||||
layer.enabled: true
|
DankIcon {
|
||||||
layer.effect: MultiEffect {
|
name: "close"
|
||||||
shadowEnabled: true
|
size: 16
|
||||||
shadowColor: Theme.shadowStrong
|
color: closeMouseArea.containsMouse ? Theme.error : Theme.outline
|
||||||
shadowBlur: 0.8
|
anchors.centerIn: parent
|
||||||
shadowHorizontalOffset: 0
|
|
||||||
shadowVerticalOffset: 4
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close button
|
MouseArea {
|
||||||
Rectangle {
|
id: closeMouseArea
|
||||||
width: 24
|
|
||||||
height: 24
|
|
||||||
radius: 12
|
|
||||||
color: closeMouseArea.containsMouse ? Theme.errorHover : "transparent"
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.topMargin: Theme.spacingS
|
|
||||||
anchors.rightMargin: Theme.spacingS
|
|
||||||
z: 1
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: "close"
|
|
||||||
size: 16
|
|
||||||
color: closeMouseArea.containsMouse ? Theme.error : Theme.outline
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: closeMouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
dropdownLoader.active = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DankFlickable {
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingS
|
hoverEnabled: true
|
||||||
contentHeight: dropdownContent.height
|
cursorShape: Qt.PointingHandCursor
|
||||||
clip: true
|
onClicked: iconPopup.close()
|
||||||
pressDelay: 0
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
DankFlickable {
|
||||||
id: dropdownContent
|
anchors.fill: parent
|
||||||
width: parent.width
|
anchors.margins: Theme.spacingS
|
||||||
spacing: Theme.spacingM
|
contentHeight: dropdownContent.height
|
||||||
|
clip: true
|
||||||
|
pressDelay: 0
|
||||||
|
|
||||||
// Icon categories
|
Column {
|
||||||
Repeater {
|
id: dropdownContent
|
||||||
model: root.iconCategories
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Column {
|
Repeater {
|
||||||
|
model: root.iconCategories
|
||||||
|
|
||||||
|
Column {
|
||||||
|
required property var modelData
|
||||||
|
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
|
width: parent.width
|
||||||
spacing: Theme.spacingS
|
spacing: 4
|
||||||
|
|
||||||
StyledText {
|
Repeater {
|
||||||
text: modelData.name
|
model: modelData.icons
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
font.weight: Font.Medium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
Flow {
|
Rectangle {
|
||||||
width: parent.width
|
required property string modelData
|
||||||
spacing: 4
|
width: 36
|
||||||
|
height: 36
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: iconMouseArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.primaryHover, 0)
|
||||||
|
border.color: root.currentIcon === modelData ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
Repeater {
|
DankIcon {
|
||||||
model: modelData.icons
|
name: parent.modelData
|
||||||
|
size: 20
|
||||||
|
color: root.currentIcon === parent.modelData ? Theme.primary : Theme.surfaceText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
MouseArea {
|
||||||
width: 36
|
id: iconMouseArea
|
||||||
height: 36
|
anchors.fill: parent
|
||||||
radius: Theme.cornerRadius
|
hoverEnabled: true
|
||||||
color: iconMouseArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.primaryHover, 0)
|
cursorShape: Qt.PointingHandCursor
|
||||||
border.color: root.currentIcon === modelData ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
onClicked: {
|
||||||
border.width: 2
|
root.iconSelected(parent.modelData, "icon");
|
||||||
|
iconPopup.close();
|
||||||
DankIcon {
|
|
||||||
name: modelData
|
|
||||||
size: 20
|
|
||||||
color: root.currentIcon === modelData ? Theme.primary : Theme.surfaceText
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MouseArea {
|
Behavior on color {
|
||||||
id: iconMouseArea
|
ColorAnimation {
|
||||||
anchors.fill: parent
|
duration: Theme.shortDuration
|
||||||
hoverEnabled: true
|
easing.type: Theme.standardEasing
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
root.iconSelected(modelData, "icon")
|
|
||||||
dropdownLoader.active = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,8 +249,8 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setIcon(iconName, type) {
|
function setIcon(iconName, type) {
|
||||||
root.iconType = type
|
root.iconType = type;
|
||||||
root.iconType = "icon"
|
root.iconType = "icon";
|
||||||
root.currentIcon = iconName
|
root.currentIcon = iconName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user