Add i18n, delete button, resize handle and improved context menu
Features added: - Internationalization (i18n) with 6 languages: English, Spanish, Chinese, French, German, Portuguese - Auto-detects system language via Qt.locale() - Delete button appears on hover (top-right, 25% size, max 44px) - Resize handle in bottom-right corner to adjust preview size - Enhanced context menu with: Switch to, Rename, Delete, New Desktop - Updated config schema: previewSize range 80-200px, default 130px Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
99eb2dbe17
commit
4d13665893
|
|
@ -12,9 +12,9 @@
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
</entry>
|
</entry>
|
||||||
<entry name="previewSize" type="Int">
|
<entry name="previewSize" type="Int">
|
||||||
<default>80</default>
|
<default>130</default>
|
||||||
<min>40</min>
|
<min>80</min>
|
||||||
<max>150</max>
|
<max>200</max>
|
||||||
</entry>
|
</entry>
|
||||||
</group>
|
</group>
|
||||||
</kcfg>
|
</kcfg>
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,9 @@ Kirigami.FormLayout {
|
||||||
SpinBox {
|
SpinBox {
|
||||||
id: previewSize
|
id: previewSize
|
||||||
Kirigami.FormData.label: i18n("Preview Size:")
|
Kirigami.FormData.label: i18n("Preview Size:")
|
||||||
from: 40
|
from: 80
|
||||||
to: 150
|
to: 200
|
||||||
stepSize: 10
|
stepSize: 10
|
||||||
enabled: showWindowPreviews.checked
|
|
||||||
|
|
||||||
textFromValue: function(value) {
|
textFromValue: function(value) {
|
||||||
return value + " px"
|
return value + " px"
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,38 @@ Item {
|
||||||
id: root
|
id: root
|
||||||
Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation
|
Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
// INTERNATIONALIZATION (i18n)
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
readonly property string systemLang: Qt.locale().name.substring(0, 2)
|
||||||
|
readonly property var translations: ({
|
||||||
|
"en": { desktop: "Desktop", add: "Add", desktops: "desktops", rename: "Rename...", delete_: "Delete",
|
||||||
|
renameTitle: "Rename Desktop", switchTo: "Switch to", moveWindowHere: "Move window here",
|
||||||
|
newDesktop: "New Desktop", confirmDelete: "Delete this desktop?" },
|
||||||
|
"es": { desktop: "Escritorio", add: "Agregar", desktops: "escritorios", rename: "Renombrar...", delete_: "Eliminar",
|
||||||
|
renameTitle: "Renombrar Escritorio", switchTo: "Cambiar a", moveWindowHere: "Mover ventana aquí",
|
||||||
|
newDesktop: "Nuevo Escritorio", confirmDelete: "¿Eliminar este escritorio?" },
|
||||||
|
"zh": { desktop: "桌面", add: "添加", desktops: "个桌面", rename: "重命名...", delete_: "删除",
|
||||||
|
renameTitle: "重命名桌面", switchTo: "切换到", moveWindowHere: "移动窗口到此处",
|
||||||
|
newDesktop: "新建桌面", confirmDelete: "删除此桌面?" },
|
||||||
|
"fr": { desktop: "Bureau", add: "Ajouter", desktops: "bureaux", rename: "Renommer...", delete_: "Supprimer",
|
||||||
|
renameTitle: "Renommer le bureau", switchTo: "Basculer vers", moveWindowHere: "Déplacer la fenêtre ici",
|
||||||
|
newDesktop: "Nouveau bureau", confirmDelete: "Supprimer ce bureau ?" },
|
||||||
|
"de": { desktop: "Desktop", add: "Hinzufügen", desktops: "Desktops", rename: "Umbenennen...", delete_: "Löschen",
|
||||||
|
renameTitle: "Desktop umbenennen", switchTo: "Wechseln zu", moveWindowHere: "Fenster hierher verschieben",
|
||||||
|
newDesktop: "Neuer Desktop", confirmDelete: "Diesen Desktop löschen?" },
|
||||||
|
"pt": { desktop: "Área de trabalho", add: "Adicionar", desktops: "áreas de trabalho", rename: "Renomear...", delete_: "Excluir",
|
||||||
|
renameTitle: "Renomear área de trabalho", switchTo: "Mudar para", moveWindowHere: "Mover janela para cá",
|
||||||
|
newDesktop: "Nova área de trabalho", confirmDelete: "Excluir esta área de trabalho?" }
|
||||||
|
})
|
||||||
|
readonly property var t: translations[systemLang] || translations["en"]
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
// CONFIGURATION
|
// CONFIGURATION
|
||||||
// ─────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
readonly property bool showPreviews: plasmoid.configuration.showWindowPreviews
|
readonly property bool showPreviews: plasmoid.configuration.showWindowPreviews
|
||||||
readonly property bool showIcons: plasmoid.configuration.showWindowIcons
|
readonly property bool showIcons: plasmoid.configuration.showWindowIcons
|
||||||
|
readonly property int previewSize: plasmoid.configuration.previewSize || 130
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
// PAGER MODEL (native KDE plugin with real window geometry)
|
// PAGER MODEL (native KDE plugin with real window geometry)
|
||||||
|
|
@ -33,13 +60,18 @@ Item {
|
||||||
if (pagerModel.count > 0 && pagerModel.currentPage >= 0) {
|
if (pagerModel.count > 0 && pagerModel.currentPage >= 0) {
|
||||||
var idx = pagerModel.index(pagerModel.currentPage, 0)
|
var idx = pagerModel.index(pagerModel.currentPage, 0)
|
||||||
var name = pagerModel.data(idx, Qt.DisplayRole)
|
var name = pagerModel.data(idx, Qt.DisplayRole)
|
||||||
return name || ("Desktop " + (pagerModel.currentPage + 1))
|
return name || (t.desktop + " " + (pagerModel.currentPage + 1))
|
||||||
}
|
}
|
||||||
return "Desktop"
|
return t.desktop
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDesktop() { pagerModel.addDesktop() }
|
function addDesktop() { pagerModel.addDesktop() }
|
||||||
function removeDesktop() { pagerModel.removeDesktop() }
|
function removeDesktop(index) {
|
||||||
|
if (pagerModel.count > 1) {
|
||||||
|
pagerModel.changePage(index)
|
||||||
|
pagerModel.removeDesktop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
// HOVER TIMERS
|
// HOVER TIMERS
|
||||||
|
|
@ -89,7 +121,7 @@ Item {
|
||||||
|
|
||||||
readonly property int cols: Math.max(1, Math.ceil(Math.sqrt(pagerModel.count)))
|
readonly property int cols: Math.max(1, Math.ceil(Math.sqrt(pagerModel.count)))
|
||||||
readonly property int rows: Math.max(1, Math.ceil(pagerModel.count / cols))
|
readonly property int rows: Math.max(1, Math.ceil(pagerModel.count / cols))
|
||||||
readonly property real deskW: 130
|
readonly property real deskW: previewSize
|
||||||
readonly property real deskH: pagerModel.pagerItemSize.height > 0
|
readonly property real deskH: pagerModel.pagerItemSize.height > 0
|
||||||
? deskW * pagerModel.pagerItemSize.height / pagerModel.pagerItemSize.width
|
? deskW * pagerModel.pagerItemSize.height / pagerModel.pagerItemSize.width
|
||||||
: deskW * 9 / 16
|
: deskW * 9 / 16
|
||||||
|
|
@ -97,7 +129,7 @@ Item {
|
||||||
readonly property real scaleY: deskH / Math.max(1, pagerModel.pagerItemSize.height)
|
readonly property real scaleY: deskH / Math.max(1, pagerModel.pagerItemSize.height)
|
||||||
|
|
||||||
Layout.preferredWidth: cols * (deskW + 8) + 32
|
Layout.preferredWidth: cols * (deskW + 8) + 32
|
||||||
Layout.preferredHeight: rows * (deskH + 8) + 56
|
Layout.preferredHeight: rows * (deskH + 8) + 70
|
||||||
Layout.minimumWidth: 200
|
Layout.minimumWidth: 200
|
||||||
Layout.minimumHeight: 120
|
Layout.minimumHeight: 120
|
||||||
|
|
||||||
|
|
@ -133,25 +165,62 @@ Item {
|
||||||
width: popup.deskW
|
width: popup.deskW
|
||||||
height: popup.deskH
|
height: popup.deskH
|
||||||
|
|
||||||
readonly property string desktopName: model.display || ("Desktop " + (index + 1))
|
readonly property string desktopName: model.display || (t.desktop + " " + (index + 1))
|
||||||
readonly property bool isActive: index === pagerModel.currentPage
|
readonly property bool isActive: index === pagerModel.currentPage
|
||||||
|
property bool isHovered: false
|
||||||
|
|
||||||
color: isActive ? Qt.darker(PlasmaCore.Theme.highlightColor, 1.3) : PlasmaCore.Theme.backgroundColor
|
color: isActive ? Qt.darker(PlasmaCore.Theme.highlightColor, 1.3) : PlasmaCore.Theme.backgroundColor
|
||||||
border.width: isActive ? 2 : 1
|
border.width: isActive ? 2 : 1
|
||||||
border.color: isActive ? PlasmaCore.Theme.highlightColor : PlasmaCore.Theme.disabledTextColor
|
border.color: isActive ? PlasmaCore.Theme.highlightColor : PlasmaCore.Theme.disabledTextColor
|
||||||
radius: 4
|
radius: 4
|
||||||
clip: true
|
clip: true
|
||||||
|
opacity: isHovered ? 1 : 0.92
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
onEntered: { hoverPopup = true; closeTimer.stop(); parent.opacity = 1 }
|
onEntered: { hoverPopup = true; closeTimer.stop(); desktop.isHovered = true }
|
||||||
onExited: parent.opacity = 0.92
|
onExited: { desktop.isHovered = false }
|
||||||
onClicked: mouse.button === Qt.RightButton ? ctxMenu.popup() : (pagerModel.changePage(index), plasmoid.expanded = false)
|
onClicked: {
|
||||||
|
if (mouse.button === Qt.RightButton) {
|
||||||
|
ctxMenu.desktopIndex = index
|
||||||
|
ctxMenu.desktopName = desktop.desktopName
|
||||||
|
ctxMenu.popup()
|
||||||
|
} else {
|
||||||
|
pagerModel.changePage(index)
|
||||||
|
plasmoid.expanded = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
opacity: 0.92
|
// ─────────────────────────────────────────────────
|
||||||
|
// DELETE BUTTON (top-right, on hover)
|
||||||
|
// ─────────────────────────────────────────────────
|
||||||
|
Rectangle {
|
||||||
|
id: deleteBtn
|
||||||
|
visible: desktop.isHovered && pagerModel.count > 1
|
||||||
|
anchors { top: parent.top; right: parent.right; margins: 2 }
|
||||||
|
width: Math.min(parent.width * 0.25, 44)
|
||||||
|
height: width
|
||||||
|
radius: width / 2
|
||||||
|
color: deleteMouseArea.containsMouse ? "#e74c3c" : Qt.rgba(0,0,0,0.6)
|
||||||
|
|
||||||
|
PlasmaCore.IconItem {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width * 0.6
|
||||||
|
height: width
|
||||||
|
source: "edit-delete"
|
||||||
|
usesPlasmaTheme: false
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: deleteMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: removeDesktop(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────
|
||||||
// WINDOWS with real geometry
|
// WINDOWS with real geometry
|
||||||
|
|
@ -193,7 +262,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────
|
||||||
// DESKTOP LABEL (centered)
|
// DESKTOP LABEL (centered, when no previews)
|
||||||
// ─────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────
|
||||||
Column {
|
Column {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
@ -227,22 +296,6 @@ Item {
|
||||||
font.pixelSize: 11; font.bold: true; color: "white"
|
font.pixelSize: 11; font.bold: true; color: "white"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context menu
|
|
||||||
Menu {
|
|
||||||
id: ctxMenu
|
|
||||||
MenuItem {
|
|
||||||
text: "Rename..."
|
|
||||||
icon.name: "edit-rename"
|
|
||||||
onTriggered: { renameDlg.idx = index; renameDlg.open(); renameField.text = desktop.desktopName; renameField.selectAll() }
|
|
||||||
}
|
|
||||||
MenuItem {
|
|
||||||
text: "Delete"
|
|
||||||
icon.name: "edit-delete"
|
|
||||||
enabled: pagerModel.count > 1
|
|
||||||
onTriggered: pagerModel.removeDesktop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -261,15 +314,94 @@ Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 8
|
spacing: 8
|
||||||
PlasmaComponents.Button {
|
PlasmaComponents.Button {
|
||||||
icon.name: "list-add"; text: "Add"
|
icon.name: "list-add"; text: t.add
|
||||||
onClicked: pagerModel.addDesktop()
|
onClicked: pagerModel.addDesktop()
|
||||||
}
|
}
|
||||||
Item { Layout.fillWidth: true }
|
Item { Layout.fillWidth: true }
|
||||||
PlasmaComponents.Label {
|
PlasmaComponents.Label {
|
||||||
text: pagerModel.count + " desktops"
|
text: pagerModel.count + " " + t.desktops
|
||||||
opacity: 0.6; font.pixelSize: 11
|
opacity: 0.6; font.pixelSize: 11
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────
|
||||||
|
// RESIZE HANDLE
|
||||||
|
// ─────────────────────────────────────────────────
|
||||||
|
Rectangle {
|
||||||
|
width: 20; height: 20
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
PlasmaCore.IconItem {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: "transform-scale"
|
||||||
|
opacity: resizeMouseArea.containsMouse ? 1 : 0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: resizeMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.SizeFDiagCursor
|
||||||
|
|
||||||
|
property real startX: 0
|
||||||
|
property real startY: 0
|
||||||
|
property int startSize: 0
|
||||||
|
|
||||||
|
onPressed: {
|
||||||
|
startX = mouse.x
|
||||||
|
startY = mouse.y
|
||||||
|
startSize = previewSize
|
||||||
|
}
|
||||||
|
onPositionChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
var delta = (mouse.x - startX + mouse.y - startY) / 2
|
||||||
|
var newSize = Math.max(80, Math.min(200, startSize + delta))
|
||||||
|
plasmoid.configuration.previewSize = Math.round(newSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────
|
||||||
|
// CONTEXT MENU
|
||||||
|
// ─────────────────────────────────────────────────────────────────
|
||||||
|
Menu {
|
||||||
|
id: ctxMenu
|
||||||
|
property int desktopIndex: 0
|
||||||
|
property string desktopName: ""
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: t.switchTo + " \"" + ctxMenu.desktopName + "\""
|
||||||
|
icon.name: "go-jump"
|
||||||
|
onTriggered: {
|
||||||
|
pagerModel.changePage(ctxMenu.desktopIndex)
|
||||||
|
plasmoid.expanded = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MenuSeparator {}
|
||||||
|
MenuItem {
|
||||||
|
text: t.rename
|
||||||
|
icon.name: "edit-rename"
|
||||||
|
onTriggered: {
|
||||||
|
renameDlg.idx = ctxMenu.desktopIndex
|
||||||
|
renameDlg.open()
|
||||||
|
renameField.text = ctxMenu.desktopName
|
||||||
|
renameField.selectAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MenuItem {
|
||||||
|
text: t.delete_
|
||||||
|
icon.name: "edit-delete"
|
||||||
|
enabled: pagerModel.count > 1
|
||||||
|
onTriggered: removeDesktop(ctxMenu.desktopIndex)
|
||||||
|
}
|
||||||
|
MenuSeparator {}
|
||||||
|
MenuItem {
|
||||||
|
text: t.newDesktop
|
||||||
|
icon.name: "list-add"
|
||||||
|
onTriggered: pagerModel.addDesktop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,7 +411,7 @@ Item {
|
||||||
Dialog {
|
Dialog {
|
||||||
id: renameDlg
|
id: renameDlg
|
||||||
property int idx: 0
|
property int idx: 0
|
||||||
title: "Rename Desktop"
|
title: t.renameTitle
|
||||||
standardButtons: Dialog.Ok | Dialog.Cancel
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
contentItem: PlasmaComponents.TextField {
|
contentItem: PlasmaComponents.TextField {
|
||||||
|
|
@ -289,7 +421,6 @@ Item {
|
||||||
}
|
}
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
if (renameField.text.trim()) {
|
if (renameField.text.trim()) {
|
||||||
// Use KWin DBus to rename
|
|
||||||
var desktopItem = repeater.itemAt(idx)
|
var desktopItem = repeater.itemAt(idx)
|
||||||
if (desktopItem) {
|
if (desktopItem) {
|
||||||
execSource.connectSource("qdbus org.kde.KWin /VirtualDesktopManager setDesktopName '" +
|
execSource.connectSource("qdbus org.kde.KWin /VirtualDesktopManager setDesktopName '" +
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue