Skip to content

Commit efa6907

Browse files
authored
Merge pull request #701 from XimoCP/main
feat(hyprland-visual-editor): add icon/color settings and i18n support
2 parents 9efe266 + 796c6e7 commit efa6907

20 files changed

Lines changed: 1305 additions & 1231 deletions

hyprland-visual-editor/BarWidget.qml

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import QtQuick
12
import Quickshell
23
import qs.Commons
34
import qs.Services.UI
@@ -6,39 +7,59 @@ import qs.Widgets
67
NIconButton {
78
id: root
89

10+
// ── Injected Properties ──────────────────────────────────────────────
911
property var pluginApi: null
10-
1112
property ShellScreen screen
1213
property string widgetId: ""
1314
property string section: ""
1415
property int sectionWidgetIndex: -1
1516
property int sectionWidgetsCount: 0
1617

18+
// ── Configuration Logic (Fallback Pattern) ──────────────────────────
1719
property var cfg: pluginApi?.pluginSettings || ({})
1820
property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
1921

20-
readonly property string iconColorKey: cfg.iconColor ?? defaults.iconColor ?? "onSurface"
21-
22-
icon: "adjustments-horizontal"
22+
readonly property string iconKey: cfg.icon ?? defaults.icon ?? "adjustments-horizontal"
23+
readonly property string iconColorKey: cfg.iconColor ?? defaults.iconColor ?? "primary"
24+
25+
// ── Visual Configuration ─────────────────────────────────────────────────
26+
icon: iconKey
27+
28+
// NIconButton already manages tooltips automatically with these two properties:
2329
tooltipText: pluginApi?.tr("widget.tooltip")
24-
2530
tooltipDirection: BarService.getTooltipDirection(screen?.name)
26-
baseSize: Style.getCapsuleHeightForScreen(screen?.name)
2731

32+
baseSize: Style.getCapsuleHeightForScreen(screen?.name)
2833
customRadius: Style.radiusM
2934

3035
colorBg: Style.capsuleColor
31-
colorFg: Color.resolveColorKey(iconColorKey)
36+
37+
// Color resolution with transparency protection (Alpha check)
38+
colorFg: {
39+
let resolved = Color.resolveColorKeyOptional(iconColorKey);
40+
if (root.containsMouse) return Color.mOnHover;
41+
return resolved.a > 0 ? resolved : Color.mOnSurface;
42+
}
3243

3344
border.color: Style.capsuleBorderColor
3445
border.width: Style.borderS
3546

47+
// Color transition smoothing
48+
Behavior on colorFg {
49+
ColorAnimation {
50+
duration: Style.animationFast
51+
easing.type: Easing.InOutQuad
52+
}
53+
}
54+
55+
// ── Interacciones ────────────────────────────────────────────────────────
3656
onClicked: {
3757
if (pluginApi) {
3858
pluginApi.openPanel(root.screen, this);
3959
}
4060
}
4161

62+
// Context menu (Right click)
4263
NPopupContextMenu {
4364
id: contextMenu
4465

hyprland-visual-editor/Main.qml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import QtQuick
2+
import Quickshell
3+
import Quickshell.Io
4+
import qs.Commons
5+
6+
Item {
7+
id: root
8+
property var pluginApi: null
9+
10+
// Shared state accessible from other components via pluginApi.mainInstance
11+
property bool isActive: false
12+
13+
// IPC handler for CLI control (qs ipc call plugin:my-plugin commandName)
14+
IpcHandler {
15+
target: "plugin:hyprland-visual-editor"
16+
17+
function toggle() {
18+
if (pluginApi) {
19+
pluginApi.withCurrentScreen(screen => {
20+
pluginApi.togglePanel(screen);
21+
});
22+
}
23+
}
24+
}
25+
}
Lines changed: 76 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,100 @@
11
import QtQuick
22
import QtQuick.Layouts
3+
import Quickshell
34
import qs.Commons
45
import qs.Widgets
56

67
ColumnLayout {
78
id: root
8-
99
property var pluginApi: null
1010

11-
property var cfg: pluginApi?.pluginSettings || ({})
12-
property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
11+
// Settings and default values (Official Noctalia pattern)
12+
readonly property var cfg: pluginApi?.pluginSettings || ({})
13+
readonly property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
14+
15+
// 1. Local state ('edit' convention to avoid unnecessary disk writes)
16+
property string editOverlayPath: cfg.overlayPath ?? defaults.overlayPath ?? "~/.cache/noctalia/HVE/overlay.conf"
17+
property bool editAutoApply: cfg.autoApply ?? defaults.autoApply ?? true
18+
property string editIcon: cfg.icon ?? defaults.icon ?? "adjustments-horizontal"
19+
property string editIconColor: cfg.iconColor ?? defaults.iconColor ?? "primary"
1320

14-
property string valueOverlayPath: cfg.overlayPath ?? defaults.overlayPath ?? "~/.cache/noctalia/HVE/overlay.conf"
15-
property bool valueAutoApply: cfg.autoApply ?? defaults.autoApply ?? true
21+
spacing: Style.marginM
1622

17-
spacing: Style.marginL
23+
// ── Preview ──────────────────────────────────────────────────────────
24+
RowLayout {
25+
spacing: Style.marginM
26+
Layout.alignment: Qt.AlignHCenter
27+
Layout.topMargin: Style.marginL
28+
Layout.bottomMargin: Style.marginL
1829

19-
Component.onCompleted: {
20-
Logger.d("HVE", "Settings UI loaded");
30+
NIcon {
31+
icon: root.editIcon
32+
pointSize: Style.fontSizeXXL * 2
33+
color: {
34+
let res = Color.resolveColorKeyOptional(root.editIconColor);
35+
return res.a > 0 ? res : Color.mOnSurface;
36+
}
37+
}
38+
39+
NText {
40+
text: pluginApi?.tr("settings.preview_label")
41+
font.weight: Font.Bold
42+
}
2143
}
2244

23-
ColumnLayout {
24-
spacing: Style.marginM
45+
// ── Icon Configuration ────────────────────────────────────────────────
46+
NButton {
2547
Layout.fillWidth: true
48+
text: pluginApi?.tr("settings.change_icon_button")
49+
icon: "search"
50+
onClicked: iconPicker.open()
51+
}
2652

27-
NTextInput {
28-
Layout.fillWidth: true
29-
label: pluginApi?.tr("settings.path.label")
30-
description: pluginApi?.tr("settings.path.desc")
31-
text: root.valueOverlayPath
32-
onTextChanged: root.valueOverlayPath = text
33-
readOnly: true
53+
NIconPicker {
54+
id: iconPicker
55+
initialIcon: root.editIcon
56+
onIconSelected: iconName => {
57+
root.editIcon = iconName
3458
}
59+
}
3560

36-
NToggle {
37-
Layout.fillWidth: true
38-
label: pluginApi?.tr("settings.autoapply.label")
39-
description: pluginApi?.tr("settings.autoapply.desc")
40-
checked: root.valueAutoApply
41-
onToggled: root.valueAutoApply = !root.valueAutoApply
42-
}
61+
NColorChoice {
62+
label: pluginApi?.tr("settings.icon_color_label")
63+
currentKey: root.editIconColor
64+
onSelected: key => { root.editIconColor = key }
65+
defaultValue: defaults.iconColor || "primary"
4366
}
4467

45-
function saveSettings() {
46-
if (!pluginApi) {
47-
Logger.e("HVE", "Cannot save settings: pluginApi is null");
48-
return;
49-
}
68+
NDivider { Layout.fillWidth: true }
69+
70+
// ── Files and Application Configuration ────────────────────────────────
71+
NTextInput {
72+
Layout.fillWidth: true
73+
label: pluginApi?.tr("settings.path_label")
74+
description: pluginApi?.tr("settings.path_desc")
75+
text: root.editOverlayPath
76+
onTextChanged: root.editOverlayPath = text
77+
readOnly: true
78+
}
5079

51-
pluginApi.pluginSettings.overlayPath = root.valueOverlayPath;
52-
pluginApi.pluginSettings.autoApply = root.valueAutoApply;
53-
pluginApi.saveSettings();
80+
NToggle {
81+
Layout.fillWidth: true
82+
label: pluginApi?.tr("settings.autoapply_label")
83+
description: pluginApi?.tr("settings.autoapply_description")
84+
checked: root.editAutoApply
85+
onToggled: checked => { root.editAutoApply = checked }
86+
}
5487

55-
Logger.d("HVE", "Settings saved successfully");
88+
// ── Save Function (Required by the Shell) ──────────────────────────
89+
function saveSettings() {
90+
if (!pluginApi) return
91+
92+
pluginApi.pluginSettings.overlayPath = root.editOverlayPath
93+
pluginApi.pluginSettings.autoApply = root.editAutoApply
94+
pluginApi.pluginSettings.icon = root.editIcon
95+
pluginApi.pluginSettings.iconColor = root.editIconColor
96+
97+
pluginApi.saveSettings()
98+
Logger.i("HVE", "Settings saved")
5699
}
57100
}

hyprland-visual-editor/i18n/de.json

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,12 @@
239239
}
240240
},
241241
"settings": {
242-
"path": {
243-
"label": "Konfigurationspfad",
244-
"desc": "Absoluter Pfad für die Satelliten-Konfigurationsdatei."
245-
},
246-
"autoapply": {
247-
"label": "Automatisch anwenden",
248-
"desc": "Hyprland automatisch neu laden, wenn sich die Einstellungen ändern."
249-
}
242+
"preview_label": "Vorschau",
243+
"change_icon_button": "Widget-Icon ändern",
244+
"icon_color_label": "Icon-Farbe",
245+
"autoapply_label": "Automatisch anwenden",
246+
"autoapply_description": "Hyprland sofort neu laden beim Speichern",
247+
"path_label": "Konfigurationspfad",
248+
"path_desc": "Absoluter Pfad für die Satelliten-Konfigurationsdatei."
250249
}
251250
}

hyprland-visual-editor/i18n/en.json

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,12 @@
239239
}
240240
},
241241
"settings": {
242-
"path": {
243-
"label": "Config Path",
244-
"desc": "Absolute path for the satellite configuration file."
245-
},
246-
"autoapply": {
247-
"label": "Auto Apply",
248-
"desc": "Automatically reload Hyprland when settings change."
249-
}
242+
"preview_label": "Preview",
243+
"change_icon_button": "Change Widget Icon",
244+
"icon_color_label": "Icon Color",
245+
"autoapply_label": "Auto Apply",
246+
"autoapply_description": "Instantly reload Hyprland when saving",
247+
"path_label": "Config Path",
248+
"path_desc": "Absolute path for the satellite configuration file."
250249
}
251250
}

hyprland-visual-editor/i18n/es.json

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,12 @@
239239
}
240240
},
241241
"settings": {
242-
"path": {
243-
"label": "Ruta de Configuración",
244-
"desc": "Ruta absoluta para el archivo de configuración satélite."
245-
},
246-
"autoapply": {
247-
"label": "Aplicación Automática",
248-
"desc": "Recargar Hyprland automáticamente al cambiar los ajustes."
249-
}
242+
"preview_label": "Vista previa",
243+
"change_icon_button": "Cambiar icono del widget",
244+
"icon_color_label": "Color del icono",
245+
"autoapply_label": "Aplicar automáticamente",
246+
"autoapply_description": "Actualiza Hyprland al instante al guardar",
247+
"path_label": "Ruta de Configuración",
248+
"path_desc": "Ruta absoluta para el archivo de configuración satélite."
250249
}
251250
}

hyprland-visual-editor/i18n/fr.json

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,12 @@
239239
}
240240
},
241241
"settings": {
242-
"path": {
243-
"label": "Chemin de configuration",
244-
"desc": "Chemin absolu pour le fichier de configuration satellite."
245-
},
246-
"autoapply": {
247-
"label": "Application automatique",
248-
"desc": "Recharger automatiquement Hyprland lorsque les paramètres changent."
249-
}
242+
"preview_label": "Aperçu",
243+
"change_icon_button": "Changer l'icône du widget",
244+
"icon_color_label": "Couleur de l'icône",
245+
"autoapply_label": "Application automatique",
246+
"autoapply_description": "Recharger instantanément Hyprland lors de la sauvegarde",
247+
"path_label": "Chemin de configuration",
248+
"path_desc": "Chemin absolu pour le fichier de configuration satellite."
250249
}
251250
}

0 commit comments

Comments
 (0)