Files
sddm-theme/themes/sm1tee/components/LayoutSelector.qml
Ваше Имя ed9ba99412 update
2025-06-30 23:19:29 +03:00

241 lines
11 KiB
QML

import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
ColumnLayout {
id: selector
width: Config.layoutPopupWidth - (Config.menuAreaPopupsPadding * 2)
signal layoutChanged(layoutIndex: int)
signal close
property int currentLayoutIndex: (keyboard && keyboard.layouts && keyboard.layouts.length > 0) ? keyboard.currentLayout : 0
property string layoutName: ""
property string layoutShortName: ""
// FIX: Добавляем функцию принудительного обновления
function forceUpdate() {
console.log("LayoutSelector: Force updating layouts");
if (keyboard && keyboard.layouts) {
console.log("LayoutSelector: Found", keyboard.layouts.length, "layouts");
// Принудительно обновляем модель
layoutList.model = null;
layoutList.model = keyboard.layouts;
// Обновляем текущий индекс
selector.currentLayoutIndex = keyboard.currentLayout;
updateLayout();
} else {
console.log("LayoutSelector: No keyboard or layouts found");
}
}
function updateLayout() {
if (keyboard && keyboard.layouts && selector.currentLayoutIndex >= 0 && selector.currentLayoutIndex < keyboard.layouts.length) {
keyboard.currentLayout = selector.currentLayoutIndex;
selector.layoutName = keyboard.layouts[selector.currentLayoutIndex].longName;
selector.layoutShortName = keyboard.layouts[selector.currentLayoutIndex].shortName;
console.log("LayoutSelector: Updated to layout", selector.currentLayoutIndex, ":", selector.layoutShortName);
}
selector.layoutChanged(selector.currentLayoutIndex);
}
Component.onCompleted: {
console.log("LayoutSelector: Component completed");
// FIX: Принудительное обновление при создании компонента
Qt.callLater(function() {
forceUpdate();
});
selector.layoutName = keyboard && keyboard.layouts && keyboard.layouts.length > 0 ? keyboard.layouts[selector.currentLayoutIndex].longName : "";
selector.layoutShortName = keyboard && keyboard.layouts && keyboard.layouts.length > 0 ? keyboard.layouts[selector.currentLayoutIndex].shortName : "";
selector.layoutChanged(selector.currentLayoutIndex);
}
// FIX: Добавляем связь для отслеживания изменений раскладок
Connections {
target: keyboard
function onLayoutsChanged() {
console.log("LayoutSelector: Keyboard layouts changed");
forceUpdate();
}
function onCurrentLayoutChanged() {
console.log("LayoutSelector: Current layout changed to", keyboard.currentLayout);
selector.currentLayoutIndex = keyboard.currentLayout;
updateLayout();
}
}
Text {
id: noLayoutMessage
Layout.preferredWidth: parent.width - 5
text: "No keyboard layout could be found. This is a known issue with Wayland."
visible: keyboard == undefined || !keyboard.layouts || keyboard.layouts.length === 0
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
color: Config.menuAreaPopupsContentColor
font.pixelSize: Config.menuAreaPopupsFontSize
font.family: Config.menuAreaPopupsFontFamily
padding: 10
}
ListView {
id: layoutList
visible: !noLayoutMessage.visible
Layout.preferredWidth: parent.width
Layout.preferredHeight: Math.min((keyboard && keyboard.layouts ? keyboard.layouts.length : 0) * (Config.menuAreaPopupsItemHeight + 5 + spacing) - spacing, Config.menuAreaPopupsMaxHeight)
orientation: ListView.Vertical
interactive: true
clip: true
boundsBehavior: Flickable.StopAtBounds
spacing: Config.menuAreaPopupsSpacing
highlightFollowsCurrentItem: true
highlightMoveDuration: 0
contentHeight: (keyboard && keyboard.layouts ? keyboard.layouts.length : 0) * (Config.menuAreaPopupsItemHeight + 5 + spacing) - spacing
ScrollBar.vertical: ScrollBar {
id: scrollbar
policy: Config.menuAreaPopupsDisplayScrollbar && layoutList.contentHeight > layoutList.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
contentItem: Rectangle {
implicitWidth: 5
radius: 5
color: Config.menuAreaPopupsContentColor
opacity: Config.menuAreaPopupsActiveOptionBackgroundOpacity
}
}
model: keyboard && keyboard.layouts ? keyboard.layouts : []
delegate: Rectangle {
width: scrollbar.visible ? selector.width - Config.menuAreaPopupsPadding - scrollbar.width : selector.width
height: childrenRect.height
color: "transparent"
Rectangle {
anchors.fill: parent
color: Config.menuAreaPopupsActiveOptionBackgroundColor
opacity: index === currentLayoutIndex ? Config.menuAreaPopupsActiveOptionBackgroundOpacity : (mouseArea.containsMouse ? Config.menuAreaPopupsActiveOptionBackgroundOpacity : 0.0)
radius: 5
}
RowLayout {
width: parent.width
height: Config.menuAreaPopupsItemHeight + 5
spacing: 0
Rectangle {
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.preferredHeight: parent.height
Layout.preferredWidth: Layout.preferredHeight
color: "transparent"
Image {
anchors.centerIn: parent
// FIX: Улучшаем путь к флагам и добавляем fallback
source: {
var flagPath = `/usr/share/sddm/flags/${shortName}.png`;
// Альтернативные пути для флагов
if (!Qt.resolvedUrl(flagPath)) {
flagPath = `/usr/share/flags/${shortName}.png`;
}
if (!Qt.resolvedUrl(flagPath)) {
flagPath = `/usr/share/pixmaps/flags/${shortName}.png`;
}
return flagPath;
}
width: Config.menuAreaPopupsIconSize
height: width
sourceSize: Qt.size(width, height)
fillMode: Image.PreserveAspectFit
// FIX: Добавляем fallback для случая, когда флаг не найден
onStatusChanged: {
if (status === Image.Error) {
// Используем текстовую замену, если изображение не найдено
visible = false;
}
}
}
// FIX: Текстовая замена для флага, если изображение не найдено
Text {
anchors.centerIn: parent
text: shortName ? shortName.toUpperCase() : ""
visible: parent.children[0].status === Image.Error
color: index === currentLayoutIndex || mouseArea.containsMouse ? Config.menuAreaPopupsActiveContentColor : Config.menuAreaPopupsContentColor
font.pixelSize: Config.menuAreaPopupsFontSize - 4
font.family: Config.menuAreaPopupsFontFamily
font.weight: Font.Bold
}
}
Column {
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.fillWidth: true
Text {
width: parent.width
// FIX: Улучшаем получение имени языка
text: {
var label = Languages.getLabelFor(shortName);
if (!label || label.length === 0) {
// Fallback к короткому имени, если нет перевода
return shortName ? shortName.toUpperCase() : "";
}
return label;
}
visible: text && text.length > 0
color: index === currentLayoutIndex || mouseArea.containsMouse ? Config.menuAreaPopupsActiveContentColor : Config.menuAreaPopupsContentColor
font.pixelSize: Config.menuAreaPopupsFontSize
font.family: Config.menuAreaPopupsFontFamily
elide: Text.ElideRight
rightPadding: 10
}
Text {
width: parent.width
text: longName || shortName || "Unknown Layout"
color: index === currentLayoutIndex || mouseArea.containsMouse ? Config.menuAreaPopupsActiveContentColor : Config.menuAreaPopupsContentColor
opacity: 0.75
font.pixelSize: Config.menuAreaPopupsFontSize - 2
font.family: Config.menuAreaPopupsFontFamily
elide: Text.ElideRight
rightPadding: 10
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
enabled: index !== selector.currentLayoutIndex
hoverEnabled: index !== selector.currentLayoutIndex
z: 2
cursorShape: hoverEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
console.log("LayoutSelector: Clicked layout", index, ":", shortName);
selector.currentLayoutIndex = index;
selector.updateLayout();
}
}
}
}
Keys.onPressed: function (event) {
if (event.key === Qt.Key_Down) {
if (keyboard && keyboard.layouts && keyboard.layouts.length > 0) {
selector.currentLayoutIndex = (selector.currentLayoutIndex + keyboard.layouts.length + 1) % keyboard.layouts.length;
selector.updateLayout();
}
} else if (event.key === Qt.Key_Up) {
if (keyboard && keyboard.layouts && keyboard.layouts.length > 0) {
selector.currentLayoutIndex = (selector.currentLayoutIndex + keyboard.layouts.length - 1) % keyboard.layouts.length;
selector.updateLayout();
}
} else if (event.key == Qt.Key_Return || event.key == Qt.Key_Enter || event.key === Qt.Key_Space) {
selector.close();
} else if (event.key === Qt.Key_CapsLock) {
root.capsLockOn = !root.capsLockOn;
}
}
}