diff --git a/Panel.qml b/Panel.qml index 5e42cf0..2ccac43 100644 --- a/Panel.qml +++ b/Panel.qml @@ -76,6 +76,44 @@ Panel { return -1 } + function isOsdEnabled() { + var v = setting("showOsd", true) + return v === true || v === "true" || v === 1 || v === "1" + } + + property string currentDisplayMode: String(setting("displayMode", "flag")) + property bool currentShowOsd: isOsdEnabled() + + onSettingsChanged: { + currentDisplayMode = String(setting("displayMode", "flag")) + currentShowOsd = isOsdEnabled() + } + + function updateDisplayMode(mode) { + currentDisplayMode = String(mode) + if (root.bar) root.bar.run("omarchy bar set glafeara.languages displayMode " + mode) + } + + function updateShowOsd(enabled) { + var boolVal = (enabled === true || enabled === "true" || enabled === 1 || enabled === "1") + currentShowOsd = boolVal + if (root.bar) root.bar.run("omarchy bar set glafeara.languages showOsd " + (boolVal ? "true" : "false") + " --json") + } + + readonly property string activeCode: { + if (activeIndex >= 0) return String(layouts[activeIndex].code).toLowerCase() + var key = codesByName[String(activeKeymap)] + if (key) return String(key).replace(/\(.*$/, "").toLowerCase() + return fallbackAbbrev(activeKeymap).toLowerCase() + } + + function flagPathFor(code) { + if (!code) return "" + var c = String(code).toLowerCase().trim().replace(/[^a-z0-9_]/g, "") + if (c === "en") c = "us" + return Qt.resolvedUrl("flags/" + c + ".svg") + } + readonly property string barLabel: activeIndex >= 0 ? abbrevFor(layouts[activeIndex].code) : (activeKeymap !== "" ? fallbackAbbrev(activeKeymap) : "") @@ -208,7 +246,7 @@ Panel { function showOsd(label) { if (!root.primaryInstance) return - if (setting("showOsd", true) !== true || label === "") return + if (!root.currentShowOsd || label === "") return root.osdText = label root.osdVisible = true osdTimer.restart() @@ -439,30 +477,61 @@ Panel { id: button anchors.fill: parent bar: root.bar - text: root.barLabel + text: root.currentDisplayMode === "flag" ? " " : (root.currentDisplayMode === "both" ? " " + root.barLabel : root.barLabel) fontSize: Style.font.body - horizontalMargin: 7 + horizontalMargin: root.currentDisplayMode === "flag" ? 6 : 7 onPressed: function(buttonCode) { if (buttonCode === Qt.RightButton) root.cycleLayout() else root.toggle() } - // The stock label is 10px regular — too faint to read at a glance next to - // the bar's 13px icons. Hide it (it still sizes the slot) and paint the - // abbreviation bold at body size instead. labelVisible: false - Text { + Row { anchors.centerIn: parent - // Box-centering puts cap-height ink a hair above the optical center the - // bar icons sit on; one pixel down lines the label up with them. - anchors.verticalCenterOffset: 1 - text: root.barLabel - color: button.active && button.useActiveColor ? button.activeColor : button.foreground - font.family: root.fontFamily - font.pixelSize: Style.font.body - font.bold: true - renderType: Text.NativeRendering + anchors.verticalCenterOffset: 0 + spacing: Style.space(6) + + Rectangle { + id: flagBadge + visible: root.currentDisplayMode !== "text" && flagImg.status === Image.Ready + width: Style.space(19) + height: Style.space(13) + anchors.verticalCenter: parent.verticalCenter + radius: Style.space(2) + color: "transparent" + clip: true + + Image { + id: flagImg + anchors.fill: parent + source: root.flagPathFor(root.activeCode) + sourceSize.width: 38 + sourceSize.height: 26 + fillMode: Image.PreserveAspectCrop + smooth: true + } + + Rectangle { + anchors.fill: parent + radius: parent.radius + color: "transparent" + border.color: Qt.rgba(1, 1, 1, 0.18) + border.width: 1 + } + } + + Text { + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: 1 + visible: root.currentDisplayMode !== "flag" || flagImg.status !== Image.Ready + text: root.barLabel + color: button.active && button.useActiveColor ? button.activeColor : button.foreground + font.family: root.fontFamily + font.pixelSize: Style.font.body + font.bold: true + renderType: Text.NativeRendering + } } } @@ -558,9 +627,39 @@ Panel { } } + Rectangle { + id: rowFlagBadge + anchors.left: parent.left + anchors.leftMargin: Style.space(8) + anchors.verticalCenter: parent.verticalCenter + width: Style.space(20) + height: Style.space(14) + radius: Style.space(2) + color: "transparent" + clip: true + + Image { + id: rowFlagImg + anchors.fill: parent + source: root.flagPathFor(row.modelData.code) + sourceSize.width: 40 + sourceSize.height: 28 + fillMode: Image.PreserveAspectCrop + smooth: true + } + + Rectangle { + anchors.fill: parent + radius: parent.radius + color: "transparent" + border.color: Qt.rgba(1, 1, 1, 0.15) + border.width: 1 + } + } + Text { id: rowAbbrev - anchors.left: parent.left + anchors.left: rowFlagBadge.right anchors.leftMargin: Style.space(8) anchors.verticalCenter: parent.verticalCenter text: root.abbrevFor(row.modelData.code) @@ -661,6 +760,109 @@ Panel { } } + PanelSeparator { + foreground: root.foreground + } + + Row { + width: column.width + spacing: Style.space(6) + + Text { + width: Style.space(78) + anchors.verticalCenter: parent.verticalCenter + text: "Display:" + color: root.dim + font.family: root.fontFamily + font.pixelSize: Style.font.caption + } + + Repeater { + model: [ + { id: "flag", label: "Flag" }, + { id: "text", label: "Text" }, + { id: "both", label: "Both" } + ] + + delegate: CursorSurface { + id: modeChip + required property var modelData + readonly property bool isSelected: root.currentDisplayMode === modelData.id + width: (column.width - Style.space(78) - Style.space(18)) / 3 + height: Style.space(26) + radius: Style.space(4) + color: isSelected ? Qt.rgba(1, 1, 1, 0.12) : "transparent" + border.color: isSelected ? Color.accent : Qt.rgba(1, 1, 1, 0.1) + border.width: 1 + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: root.updateDisplayMode(modeChip.modelData.id) + } + + Text { + anchors.centerIn: parent + text: modeChip.modelData.label + color: modeChip.isSelected ? Color.accent : root.foreground + font.family: root.fontFamily + font.pixelSize: Style.font.caption + font.bold: modeChip.isSelected + } + } + } + } + + Row { + width: column.width + spacing: Style.space(6) + + Text { + width: Style.space(78) + anchors.verticalCenter: parent.verticalCenter + text: "OSD Popup:" + color: root.dim + font.family: root.fontFamily + font.pixelSize: Style.font.caption + } + + Repeater { + model: [ + { val: true, label: "Enabled" }, + { val: false, label: "Disabled" } + ] + + delegate: CursorSurface { + id: osdChip + required property var modelData + readonly property bool isSelected: root.currentShowOsd === modelData.val + width: (column.width - Style.space(78) - Style.space(12)) / 2 + height: Style.space(26) + radius: Style.space(4) + color: isSelected ? Qt.rgba(1, 1, 1, 0.12) : "transparent" + border.color: isSelected ? Color.accent : Qt.rgba(1, 1, 1, 0.1) + border.width: 1 + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: root.updateShowOsd(osdChip.modelData.val) + } + + Text { + anchors.centerIn: parent + text: osdChip.modelData.label + color: osdChip.isSelected ? Color.accent : root.foreground + font.family: root.fontFamily + font.pixelSize: Style.font.caption + font.bold: osdChip.isSelected + } + } + } + } + Text { width: column.width visible: root.lastError !== "" @@ -699,6 +901,8 @@ Panel { // whatever the user is typing into. mask: Region {} + readonly property bool osdIsFlagOnly: root.currentDisplayMode === "flag" && osdFlagImg.status === Image.Ready + BorderSurface { id: osdCard anchors.centerIn: parent @@ -706,11 +910,41 @@ Panel { // Mirrors the theme's decoration:rounding, like the stock OSD card. radius: Style.cornerRadius borderSpec: Border.surfaceSpec("popups", "border", Color.popups.border, Math.max(1, Style.space(2))) - width: Math.max(osdLabel.implicitHeight, osdLabel.implicitWidth) + Style.space(48) - height: osdLabel.implicitHeight + Style.space(48) + width: osdWindow.osdIsFlagOnly ? Style.space(136) : (Math.max(osdLabel.implicitHeight, osdLabel.implicitWidth) + Style.space(48)) + height: osdWindow.osdIsFlagOnly ? Style.space(96) : (osdLabel.implicitHeight + Style.space(48)) + + Rectangle { + id: osdFlagBadge + visible: osdWindow.osdIsFlagOnly + anchors.centerIn: parent + width: Style.space(96) + height: Style.space(64) + radius: Style.space(6) + color: "transparent" + clip: true + + Image { + id: osdFlagImg + anchors.fill: parent + source: root.flagPathFor(root.osdText) + sourceSize.width: 192 + sourceSize.height: 128 + fillMode: Image.PreserveAspectCrop + smooth: true + } + + Rectangle { + anchors.fill: parent + radius: parent.radius + color: "transparent" + border.color: Qt.rgba(1, 1, 1, 0.22) + border.width: 1 + } + } Text { id: osdLabel + visible: !osdWindow.osdIsFlagOnly anchors.centerIn: parent text: root.osdText color: Color.popups.text diff --git a/flags/am.svg b/flags/am.svg new file mode 100644 index 0000000..d51219b --- /dev/null +++ b/flags/am.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/flags/by.svg b/flags/by.svg new file mode 100644 index 0000000..bf96fa9 --- /dev/null +++ b/flags/by.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/flags/ca.svg b/flags/ca.svg new file mode 100644 index 0000000..4521509 --- /dev/null +++ b/flags/ca.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/flags/cn.svg b/flags/cn.svg new file mode 100644 index 0000000..eecc923 --- /dev/null +++ b/flags/cn.svg @@ -0,0 +1,4 @@ + + + + diff --git a/flags/de.svg b/flags/de.svg new file mode 100644 index 0000000..b6d60e3 --- /dev/null +++ b/flags/de.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/flags/ee.svg b/flags/ee.svg new file mode 100644 index 0000000..3e6f465 --- /dev/null +++ b/flags/ee.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/flags/es.svg b/flags/es.svg new file mode 100644 index 0000000..03b489a --- /dev/null +++ b/flags/es.svg @@ -0,0 +1,4 @@ + + + + diff --git a/flags/fi.svg b/flags/fi.svg new file mode 100644 index 0000000..7f1f271 --- /dev/null +++ b/flags/fi.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/flags/fr.svg b/flags/fr.svg new file mode 100644 index 0000000..5582acb --- /dev/null +++ b/flags/fr.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/flags/gb.svg b/flags/gb.svg new file mode 100644 index 0000000..edcf98d --- /dev/null +++ b/flags/gb.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/flags/ge.svg b/flags/ge.svg new file mode 100644 index 0000000..dd460f1 --- /dev/null +++ b/flags/ge.svg @@ -0,0 +1,4 @@ + + + + diff --git a/flags/it.svg b/flags/it.svg new file mode 100644 index 0000000..60e5a51 --- /dev/null +++ b/flags/it.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/flags/jp.svg b/flags/jp.svg new file mode 100644 index 0000000..1b0d1c7 --- /dev/null +++ b/flags/jp.svg @@ -0,0 +1,4 @@ + + + + diff --git a/flags/kz.svg b/flags/kz.svg new file mode 100644 index 0000000..bf3666e --- /dev/null +++ b/flags/kz.svg @@ -0,0 +1,4 @@ + + + + diff --git a/flags/pl.svg b/flags/pl.svg new file mode 100644 index 0000000..f2c5863 --- /dev/null +++ b/flags/pl.svg @@ -0,0 +1,4 @@ + + + + diff --git a/flags/ru.svg b/flags/ru.svg new file mode 100644 index 0000000..5c6314d --- /dev/null +++ b/flags/ru.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/flags/tr.svg b/flags/tr.svg new file mode 100644 index 0000000..918a0d7 --- /dev/null +++ b/flags/tr.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/flags/ua.svg b/flags/ua.svg new file mode 100644 index 0000000..8ae40fb --- /dev/null +++ b/flags/ua.svg @@ -0,0 +1,4 @@ + + + + diff --git a/flags/us.svg b/flags/us.svg new file mode 100644 index 0000000..e9188b1 --- /dev/null +++ b/flags/us.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/manifest.json b/manifest.json index a4df406..3a37db6 100644 --- a/manifest.json +++ b/manifest.json @@ -19,10 +19,17 @@ "allowMultiple": false, "defaultSection": "right", "defaults": { + "displayMode": "flag", "osdDurationMs": 750, "showOsd": true }, "schema": [ + { + "key": "displayMode", + "type": "string", + "label": "Display mode (flag, text, both)", + "defaultValue": "flag" + }, { "key": "osdDurationMs", "type": "integer",