[plasma/kscreen] kcm: kscreen: use output priority for monitor numbers

Nate Graham <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit a77e6b466412c7943d6d63df0de302dfd7834972 by Nate Graham, on behalf of Ramil Nurmanov.
Committed on 23/07/2026 at 22:13.
Pushed by ngraham into branch 'master'.

kscreen: use output priority for monitor numbers

Use output priority when assigning numbers to monitor badges in the
Display Configuration KCM.

Previously, monitor numbers were based on their order in the output
model. As a result, the primary monitor could be displayed with a
number other than 1.

Enabled outputs are now ordered by priority, ensuring that the primary
monitor with priority 1 is always displayed as monitor 1.

Disabled outputs are not ordered by priority because they retain their
last priority value after being disabled. They are placed after all
enabled outputs and ordered by name instead.

ENHANCEMENT: 523182
FIXED-IN: 6.8.0

M  +13   -4    kcm/output_model.cpp
M  +103  -35   kcm/ui/main.qml

https://invent.kde.org/plasma/kscreen/-/commit/a77e6b466412c7943d6d63df0de302dfd7834972

diff --git a/kcm/output_model.cpp b/kcm/output_model.cpp
index 36033a38..723a91ac 100644
--- a/kcm/output_model.cpp
+++ b/kcm/output_model.cpp
@@ -25,7 +25,7 @@ OutputModel::OutputModel(ConfigHandler *configHandler)
 {
     connect(m_config->config().data(), &KScreen::Config::prioritiesChanged, this, [this]() {
         if (rowCount() > 0) {
-            Q_EMIT dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0), {PriorityRole});
+            Q_EMIT dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0), {PriorityRole, NumberByConnectorRole, ReplicationSourceModelWithNumbersRole});
         }
     });
 }
@@ -477,7 +477,7 @@ void OutputModel::add(const KScreen::OutputPtr &output)
         QModelIndex index = createIndex(j, 0);
         // Calling this directly ignores possible optimization when the
         // refresh rate hasn't changed in fact. But that's ok.
-        Q_EMIT dataChanged(index, index, {ReplicationSourceModelRole, ReplicationSourceModelWithNumbersRole, ReplicationSourceIndexRole});
+        Q_EMIT dataChanged(index, index, {ReplicationSourceModelRole, ReplicationSourceModelWithNumbersRole, ReplicationSourceIndexRole, NumberByConnectorRole});
     }
 }
 
@@ -491,6 +491,11 @@ void OutputModel::remove(int outputId)
         beginRemoveRows(QModelIndex(), index, index);
         m_outputs.erase(it);
         endRemoveRows();
+
+        for (int outputIndex : std::views::iota(0, m_outputs.size())) {
+            const QModelIndex modelIndex = createIndex(outputIndex, 0);
+            Q_EMIT dataChanged(modelIndex, modelIndex, {ReplicationSourceModelRole, ReplicationSourceModelWithNumbersRole, NumberByConnectorRole});
+        }
     }
 }
 
@@ -588,7 +593,7 @@ bool OutputModel::setEnabled(int outputIndex, bool enable)
 
     for (int outputIndex : std::views::iota(0, m_outputs.size())) {
         const QModelIndex index = createIndex(outputIndex, 0);
-        Q_EMIT dataChanged(index, index, {ReplicationSourceModelRole, ReplicationSourceModelWithNumbersRole});
+        Q_EMIT dataChanged(index, index, {ReplicationSourceModelRole, ReplicationSourceModelWithNumbersRole, NumberByConnectorRole});
     }
     return true;
 }
@@ -997,7 +1002,11 @@ int OutputModel::numberByConnector(const KScreen::OutputPtr &output) const
     if (!output)
         return 0;
     auto sorted = m_outputs;
-    std::sort(sorted.begin(), sorted.end(), [](const Output &a, const Output &b){
+    std::sort(sorted.begin(), sorted.end(), [](const Output &a, const Output &b) {
+        if (a.ptr->isEnabled() != b.ptr->isEnabled())
+            return a.ptr->isEnabled();
+        if (a.ptr->isEnabled())
+            return a.ptr->priority() < b.ptr->priority();
         return QString::compare(a.ptr->name(), b.ptr->name(), Qt::CaseInsensitive) < 0;
     });
     auto it = std::find_if(sorted.begin(), sorted.end(), [&](const Output &o) { return o.ptr == output; });
diff --git a/kcm/ui/main.qml b/kcm/ui/main.qml
index 63e58c46..be7d508d 100644
--- a/kcm/ui/main.qml
+++ b/kcm/ui/main.qml
@@ -227,62 +227,130 @@ KCM.AbstractKCM {
             standardButtons: Kirigami.Dialog.Ok
             padding: 0
 
-            contentItem: ListView {
+            contentItem: Item {
                 id: reorderView
 
                 implicitWidth: Math.min(root.width * 0.75, Kirigami.Units.gridUnit * 32)
-                implicitHeight: contentHeight
+                implicitHeight: rowHeight * enabledOutputsModel.count
 
-                reuseItems: true
-                model: KSortFilterProxyModel {
+                readonly property real rowHeight: rowMetrics.implicitHeight
+                readonly property real numberColumnWidth: badgeMetrics.implicitWidth + Kirigami.Units.largeSpacing * 2
+
+                KSortFilterProxyModel {
                     id: enabledOutputsModel
                     sourceModel: kcm.outputModel
                     filterRoleName: "enabled"
                     filterString: "true"
-                    sortRoleName: "priority"
-                    sortOrder: Qt.AscendingOrder
                 }
-                delegate: Kirigami.SwipeListItem {
-                    id: delegate
-
-                    property var output: model
 
-                    width: ListView.view.width
-
-                    background: null
+                OutputNumberBadge {
+                    id: badgeMetrics
+                    visible: false
+                    number: 1
+                }
+                QQC2.ItemDelegate {
+                    id: rowMetrics
+                    visible: false
                     contentItem: RowLayout {
                         spacing: Kirigami.Units.largeSpacing
-                        OutputNumberBadge {
-                            number: delegate.output.numberByConnector
-                        }
                         Kirigami.TitleSubtitle {
-                            title: delegate.output.display
-                            subtitle: (delegate.output.priority === 1) ? i18n("Primary") : ""
+                            title: "Metrics"
+                            subtitle: "Primary"
+                            reserveSpaceForSubtitle: true
                             Layout.fillWidth: true
                         }
-                    }
-                    actions: [
-                        Kirigami.Action {
+                        QQC2.ToolButton {
                             icon.name: "arrow-up"
                             text: i18n("Raise priority")
-                            enabled: delegate.output.priority > 1
-                            onTriggered: {
-                                if (enabled) {
-                                    delegate.output.priority -= 1;
-                                }
-                            }
-                        },
-                        Kirigami.Action {
+                            display: QQC2.AbstractButton.IconOnly
+
+                            QQC2.ToolTip.visible: hovered || activeFocus
+                            QQC2.ToolTip.text: text
+                            QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
+                        }
+                        QQC2.ToolButton {
                             icon.name: "arrow-down"
                             text: i18n("Lower priority")
-                            enabled: delegate.output.priority < reorderView.count
-                            onTriggered: {
-                                if (enabled) {
-                                    delegate.output.priority += 1;
-                                }
+                            display: QQC2.AbstractButton.IconOnly
+
+                            QQC2.ToolTip.visible: hovered || activeFocus
+                            QQC2.ToolTip.text: text
+                            QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
+                        }
+                    }
+                }
+
+                Repeater {
+                    model: enabledOutputsModel.count
+                    delegate: QQC2.ItemDelegate {
+                        x: 0
+                        y: index * reorderView.rowHeight
+                        width: reorderView.numberColumnWidth
+                        height: reorderView.rowHeight
+                        hoverEnabled: false
+
+                        contentItem: Item {
+                            OutputNumberBadge {
+                                anchors.centerIn: parent
+                                number: index + 1
                             }
                         }
-                    ]
+                    }
+                }
+
+                Repeater {
+                    model: enabledOutputsModel
+
+                    delegate: QQC2.ItemDelegate {
+                        id: delegate
+
+                        property var output: model
+
+                        x: reorderView.numberColumnWidth
+                        width: reorderView.width - reorderView.numberColumnWidth
+                        height: reorderView.rowHeight
+                        hoverEnabled: true
+
+                        y: (output.priority - 1) * reorderView.rowHeight
+                        Behavior on y {
+                            NumberAnimation {
+                                duration: Kirigami.Units.longDuration
+                                easing.type: Easing.InOutQuad
+                            }
+                        }
+
+                        contentItem: RowLayout {
+                            spacing: Kirigami.Units.largeSpacing
+                            Kirigami.TitleSubtitle {
+                                title: delegate.output.display
+                                subtitle: (delegate.output.priority === 1) ? i18n("Primary") : ""
+                                reserveSpaceForSubtitle: true
+                                Layout.fillWidth: true
+                            }
+                            QQC2.ToolButton {
+                                icon.name: "arrow-up"
+                                text: i18n("Raise priority")
+                                display: QQC2.AbstractButton.IconOnly
+                                enabled: delegate.output.priority > 1
+                                onClicked: delegate.output.priority -= 1
+
+                                QQC2.ToolTip.visible: hovered || activeFocus
+                                QQC2.ToolTip.text: text
+                                QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
+                            }
+                            QQC2.ToolButton {
+                                icon.name: "arrow-down"
+                                text: i18n("Lower priority")
+                                display: QQC2.AbstractButton.IconOnly
+                                enabled: delegate.output.priority < enabledOutputsModel.count
+                                onClicked: delegate.output.priority += 1
+
+                                QQC2.ToolTip.visible: hovered || activeFocus
+                                QQC2.ToolTip.text: text
+                                QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
+                            }
+                        }
+                    }
                 }
             }
         }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.