Dock: add position setting

This commit is contained in:
Ly-sec
2026-01-10 14:39:00 +01:00
parent 8636e5be1d
commit c58abd7566
18 changed files with 149 additions and 33 deletions
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Laufende Indikatoren",
"appearance-pinned-static-description": "Gepinnten App-Symbole immer in statischer Reihenfolge nach links schieben.",
"appearance-pinned-static-label": "Statische angeheftete Apps",
"appearance-position-description": "Wählen Sie, wo das Dock auf dem Bildschirm angezeigt wird.",
"appearance-position-label": "Position",
"enabled-description": "Dock vollständig anzeigen oder ausblenden.",
"enabled-label": "Dock aktivieren",
"monitors-desc": "Dock auf bestimmten Monitoren anzeigen. Standardmäßig werden alle angezeigt, wenn keine ausgewählt wurden.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Running Indicators",
"appearance-pinned-static-description": "Always push pinned app icons to the left in static order.",
"appearance-pinned-static-label": "Static Pinned Apps",
"appearance-position-description": "Choose where the dock appears on screen.",
"appearance-position-label": "Position",
"enabled-description": "Show or hide the dock entirely.",
"enabled-label": "Enable dock",
"monitors-desc": "Show dock on specific monitors. Defaults to all if none are chosen.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Indicadores de ejecución",
"appearance-pinned-static-description": "Siempre empuja los iconos de las aplicaciones ancladas a la izquierda en orden estático.",
"appearance-pinned-static-label": "Aplicaciones ancladas estáticas",
"appearance-position-description": "Elige dónde aparece el dock en la pantalla.",
"appearance-position-label": "Posición",
"enabled-description": "Mostrar u ocultar el dock por completo",
"enabled-label": "Habilitar dock",
"monitors-desc": "Mostrar el dock en monitores específicos. Por defecto, se muestra en todos si no se elige ninguno.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Indicateurs de fonctionnement",
"appearance-pinned-static-description": "Toujours pousser les icônes d'applications épinglées vers la gauche dans un ordre statique.",
"appearance-pinned-static-label": "Applications épinglées statiques",
"appearance-position-description": "Choisissez l'emplacement du Dock à l'écran.",
"appearance-position-label": "Position",
"enabled-description": "Afficher ou masquer complètement le dock",
"enabled-label": "Activer le dock",
"monitors-desc": "Afficher le dock sur des écrans spécifiques. Par défaut, il s'affiche sur tous les écrans si aucun n'est sélectionné.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Futásjelzők",
"appearance-pinned-static-description": "A rögzített alkalmazásikonok mindig statikus sorrendben kerüljenek balra.",
"appearance-pinned-static-label": "Statikus rögzített alkalmazások",
"appearance-position-description": "Válaszd ki, hogy hol jelenjen meg a Dock a képernyőn.",
"appearance-position-label": "Pozíció",
"enabled-description": "A dokk teljes megjelenítése vagy elrejtése.",
"enabled-label": "Dokk engedélyezése",
"monitors-desc": "Dokk megjelenítése meghatározott monitorokon. Alapértelmezés szerint mindegyiken, ha nincs kiválasztva.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "実行インジケーター",
"appearance-pinned-static-description": "ピン留めされたアプリアイコンを常に左側に寄せて固定します。",
"appearance-pinned-static-label": "ピン留めアプリの固定配置",
"appearance-position-description": "ドックを画面上のどこに表示するかを選択してください。",
"appearance-position-label": "位置",
"enabled-description": "ドックを完全に表示または非表示にします。",
"enabled-label": "ドックの有効化",
"monitors-desc": "ドックを表示するディスプレイを選択します。未選択の場合は全てに表示されます。",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Nîşaneyên Xebatê",
"appearance-pinned-static-description": "Her gav îkonên sepanên pêvekirî bi rêza statîk ber bi çepê ve bikişîne.",
"appearance-pinned-static-label": "Serîlêdanên Sabîtkirî yên Statîk",
"appearance-position-description": "Cihê ku dock li ser ekranê xuya dike hilbijêre.",
"appearance-position-label": "Rewş",
"enabled-description": "Nîşan bide an jî bi tevahî dokê veşêre.",
"enabled-label": "Dock çalak bike",
"monitors-desc": "Nîşan bide dock li ser çavdêrên taybet. Eger tu neyê hilbijartin, ew bi awayekî xwerû li ser hemûyan e.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Lopende indicatoren",
"appearance-pinned-static-description": "Zet vastgemaakte app-pictogrammen altijd in statische volgorde aan de linkerkant.",
"appearance-pinned-static-label": "Statische vastgezette apps",
"appearance-position-description": "Kies waar het dock op het scherm verschijnt.",
"appearance-position-label": "Positie",
"enabled-description": "Dock geheel tonen of verbergen.",
"enabled-label": "Dock inschakelen",
"monitors-desc": "Dock op specifieke monitoren weergeven. Standaard op alle als er geen zijn gekozen.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Wskaźniki uruchomionych",
"appearance-pinned-static-description": "Zawsze spychaj przypięte aplikacje na lewo w stałej kolejności.",
"appearance-pinned-static-label": "Statyczne przypięte aplikacje",
"appearance-position-description": "Wybierz, gdzie dok ma się pojawiać na ekranie.",
"appearance-position-label": "Pozycja",
"enabled-description": "Pokaż lub całkowicie ukryj dok.",
"enabled-label": "Włącz dok",
"monitors-desc": "Pokaż dok na konkretnych monitorach. Domyślnie na wszystkich, jeśli żaden nie zostanie wybrany.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Indicadores de execução",
"appearance-pinned-static-description": "Sempre posicione os ícones de aplicativos fixados à esquerda em ordem estática.",
"appearance-pinned-static-label": "Aplicativos Fixados Estaticamente",
"appearance-position-description": "Escolha onde o dock aparece na tela.",
"appearance-position-label": "Posição",
"enabled-description": "Mostrar ou ocultar o dock completamente",
"enabled-label": "Ativar dock",
"monitors-desc": "Mostrar dock em monitores específicos. O padrão é todos se nenhum for escolhido.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Бегущие индикаторы",
"appearance-pinned-static-description": "Всегда перемещайте закреплённые значки приложений влево в статичном порядке.",
"appearance-pinned-static-label": "Закреплённые статические приложения",
"appearance-position-description": "Выберите, где док будет отображаться на экране.",
"appearance-position-label": "Позиция",
"enabled-description": "Показать или скрыть панель приложений целиком",
"enabled-label": "Включить панель приложений",
"monitors-desc": "Показывать панель приложений на определенных мониторах. По умолчанию на всех, если ни один не выбран.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Çalışan Göstergeler",
"appearance-pinned-static-description": "Sabit sırada, sabitlenmiş uygulama simgelerini her zaman sola itin.",
"appearance-pinned-static-label": "Sabitlenmiş Statik Uygulamalar",
"appearance-position-description": "Ekran üzerinde dock'un nerede görüneceğini seçin.",
"appearance-position-label": "Pozisyon",
"enabled-description": "Rıhtımı tamamen gösterin veya gizleyin",
"enabled-label": "Rıhtımı etkinleştir",
"monitors-desc": "Rıhtımı belirli ekranlarda gösterin. Hiçbiri seçilmezse varsayılan olarak tümünde gösterilir.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "Індикатори бігу",
"appearance-pinned-static-description": "Завжди закріплюйте значки програм ліворуч у статичному порядку.",
"appearance-pinned-static-label": "Статично закріплені програми",
"appearance-position-description": "Виберіть, де док-станція відображатиметься на екрані.",
"appearance-position-label": "Позиція",
"enabled-description": "Показати або сховати док повністю",
"enabled-label": "Увімкнути док",
"monitors-desc": "Показувати док на певних моніторах. За замовчуванням на всіх, якщо не вибрано.",
+2
View File
@@ -874,6 +874,8 @@
"appearance-inactive-indicators-label": "运行指示器",
"appearance-pinned-static-description": "始终将固定的应用图标按静态顺序推到左侧。",
"appearance-pinned-static-label": "静态固定应用",
"appearance-position-description": "选择 Dock 在屏幕上显示的位置。",
"appearance-position-label": "位置",
"enabled-description": "完全显示或隐藏停靠栏",
"enabled-label": "启用停靠栏",
"monitors-desc": "在特定显示器上显示停靠栏。如果未选择任何显示器,则默认为全部。",
+1
View File
@@ -485,6 +485,7 @@ Singleton {
// dock
property JsonObject dock: JsonObject {
property bool enabled: true
property string position: "bottom" // "top", "bottom", "left", "right"
property string displayMode: "auto_hide" // "always_visible", "auto_hide", "exclusive"
property real backgroundOpacity: 1.0
property real floatingRatio: 1.0
+62 -31
View File
@@ -77,9 +77,13 @@ Loader {
readonly property int iconSize: Math.round(12 + 24 * (Settings.data.dock.size ?? 1))
readonly property int floatingMargin: Settings.data.dock.floatingRatio * Style.marginL
// Dock position properties
readonly property string dockPosition: Settings.data.dock.position
readonly property bool isVertical: dockPosition === "left" || dockPosition === "right"
// Bar detection and positioning properties
readonly property bool hasBar: modelData && modelData.name ? (Settings.data.bar.monitors.includes(modelData.name) || (Settings.data.bar.monitors.length === 0)) : false
readonly property bool barAtBottom: hasBar && Settings.data.bar.position === "bottom"
readonly property bool barAtSameEdge: hasBar && Settings.data.bar.position === dockPosition
readonly property int barHeight: Style.barHeight
// Shared state between windows
@@ -291,7 +295,7 @@ Loader {
}
}
// PEEK WINDOW - Always visible when auto-hide is enabled
// PEEK WINDOW
Loader {
active: (barIsReady || !hasBar) && modelData && (Settings.data.dock.monitors.length === 0 || Settings.data.dock.monitors.includes(modelData.name)) && autoHide
@@ -299,15 +303,25 @@ Loader {
id: peekWindow
screen: modelData
anchors.bottom: true
anchors.left: true
anchors.right: true
// Dynamic anchors based on dock position
anchors.top: dockPosition === "top" || isVertical
anchors.bottom: dockPosition === "bottom" || isVertical
anchors.left: dockPosition === "left" || !isVertical
anchors.right: dockPosition === "right" || !isVertical
focusable: false
color: "transparent"
// When bar is at same edge, position peek window past the bar so it receives mouse events
margins.top: dockPosition === "top" && barAtSameEdge ? (Style.barHeight + (Settings.data.bar.floating ? Settings.data.bar.marginVertical : 0)) : 0
margins.bottom: dockPosition === "bottom" && barAtSameEdge ? (Style.barHeight + (Settings.data.bar.floating ? Settings.data.bar.marginVertical : 0)) : 0
margins.left: dockPosition === "left" && barAtSameEdge ? (Style.barHeight + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal : 0)) : 0
margins.right: dockPosition === "right" && barAtSameEdge ? (Style.barHeight + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal : 0)) : 0
WlrLayershell.namespace: "noctalia-dock-peek-" + (screen?.name || "unknown")
WlrLayershell.exclusionMode: ExclusionMode.Ignore
implicitHeight: peekHeight
// Larger peek area when bar is at same edge, normal 1px otherwise
implicitHeight: barAtSameEdge && !isVertical ? 3 : peekHeight
implicitWidth: barAtSameEdge && isVertical ? 3 : peekHeight
MouseArea {
id: peekArea
@@ -332,7 +346,6 @@ Loader {
}
}
// DOCK WINDOW
Loader {
id: dockWindowLoader
active: Settings.data.dock.enabled && (barIsReady || !hasBar) && modelData && (Settings.data.dock.monitors.length === 0 || Settings.data.dock.monitors.includes(modelData.name)) && dockLoaded && ToplevelManager && (dockApps.length > 0)
@@ -352,25 +365,31 @@ Loader {
implicitWidth: dockContainerWrapper.width
implicitHeight: dockContainerWrapper.height
// Position above the bar if it's at bottom
anchors.bottom: true
// Dynamic anchors based on dock position
anchors.top: dockPosition === "top"
anchors.bottom: dockPosition === "bottom"
anchors.left: dockPosition === "left"
anchors.right: dockPosition === "right"
margins.bottom: {
switch (Settings.data.bar.position) {
case "bottom":
return (Style.barHeight + Style.marginM) + (Settings.data.bar.floating ? Settings.data.bar.marginVertical + floatingMargin : floatingMargin);
default:
return floatingMargin;
}
}
// Calculate margin for the dock's edge based on bar position
margins.top: dockPosition === "top" ? (barAtSameEdge ? (Style.barHeight + Style.marginM) + (Settings.data.bar.floating ? Settings.data.bar.marginVertical + floatingMargin : floatingMargin) : floatingMargin) : 0
margins.bottom: dockPosition === "bottom" ? (barAtSameEdge ? (Style.barHeight + Style.marginM) + (Settings.data.bar.floating ? Settings.data.bar.marginVertical + floatingMargin : floatingMargin) : floatingMargin) : 0
margins.left: dockPosition === "left" ? (barAtSameEdge ? (Style.barHeight + Style.marginM) + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal + floatingMargin : floatingMargin) : floatingMargin) : 0
margins.right: dockPosition === "right" ? (barAtSameEdge ? (Style.barHeight + Style.marginM) + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal + floatingMargin : floatingMargin) : floatingMargin) : 0
// Wrapper item for scale/opacity animations
Item {
id: dockContainerWrapper
width: dockContainer.width
height: dockContainer.height
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
// Center along the non-docking axis
anchors.horizontalCenter: isVertical ? undefined : parent.horizontalCenter
anchors.verticalCenter: isVertical ? parent.verticalCenter : undefined
// Anchor to the dock's edge
anchors.top: dockPosition === "top" ? parent.top : undefined
anchors.bottom: dockPosition === "bottom" ? parent.bottom : undefined
anchors.left: dockPosition === "left" ? parent.left : undefined
anchors.right: dockPosition === "right" ? parent.right : undefined
// Apply animations to this wrapper
opacity: hidden ? 0 : 1
@@ -393,8 +412,9 @@ Loader {
Rectangle {
id: dockContainer
width: dockLayout.implicitWidth + Style.marginM * 2
height: Math.round(iconSize * 1.5)
// For vertical dock, swap width and height logic
width: isVertical ? Math.round(iconSize * 1.5) : dockLayout.implicitWidth + Style.marginM * 2
height: isVertical ? dockLayout.implicitHeight + Style.marginM * 2 : Math.round(iconSize * 1.5)
color: Qt.alpha(Color.mSurface, Settings.data.dock.backgroundOpacity)
anchors.centerIn: parent
radius: Style.radiusL
@@ -434,8 +454,9 @@ Loader {
Item {
id: dock
width: dockLayout.implicitWidth
height: parent.height - (Style.marginM * 2)
// Swap dimensions based on orientation
width: isVertical ? parent.width - (Style.marginM * 2) : dockLayout.implicitWidth
height: isVertical ? dockLayout.implicitHeight : parent.height - (Style.marginM * 2)
anchors.centerIn: parent
function getAppIcon(appData): string {
@@ -444,10 +465,13 @@ Loader {
return ThemeIcons.iconForAppId(appData.appId?.toLowerCase());
}
RowLayout {
// Use GridLayout for flexible horizontal/vertical arrangement
GridLayout {
id: dockLayout
spacing: Style.marginM
Layout.preferredHeight: parent.height
columns: isVertical ? 1 : -1
rows: isVertical ? -1 : 1
rowSpacing: Style.marginM
columnSpacing: Style.marginM
anchors.centerIn: parent
Repeater {
@@ -559,6 +583,7 @@ Loader {
// Context menu popup
DockMenu {
id: contextMenu
dockPosition: root.dockPosition // Pass dock position for menu placement
onHoveredChanged: {
// Only update menuHovered if this menu is current and visible
if (root.currentContextMenu === contextMenu && contextMenu.visible) {
@@ -708,15 +733,21 @@ Loader {
}
}
// Active indicator
// Active indicator - positions at bottom for horizontal, at side for vertical
Rectangle {
visible: Settings.data.dock.inactiveIndicators ? isRunning : isActive
width: iconSize * 0.2
height: iconSize * 0.1
// For vertical dock, swap width/height
width: isVertical ? iconSize * 0.1 : iconSize * 0.2
height: isVertical ? iconSize * 0.2 : iconSize * 0.1
color: Color.mPrimary
radius: Style.radiusXS
anchors.top: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
// For horizontal dock: bottom center
// For vertical dock: beside the icon (inside edge)
anchors.top: isVertical ? undefined : parent.bottom
anchors.horizontalCenter: isVertical ? undefined : parent.horizontalCenter
anchors.verticalCenter: isVertical ? parent.verticalCenter : undefined
anchors.left: dockPosition === "right" ? parent.left : undefined
anchors.right: dockPosition === "left" ? parent.right : undefined
}
}
}
+31 -2
View File
@@ -210,9 +210,38 @@ PopupWindow {
Settings.data.dock.pinnedApps = pinnedApps;
}
// Dock position for context menu placement
property string dockPosition: "bottom"
anchor.item: anchorItem
anchor.rect.x: anchorItem ? (anchorItem.width - implicitWidth) / 2 : 0
anchor.rect.y: anchorItem ? -implicitHeight - (Style.marginM) : 0
// Position menu on opposite side of dock with comfortable spacing
anchor.rect.x: {
if (!anchorItem)
return 0;
switch (dockPosition) {
case "left":
return anchorItem.width + Style.marginL; // Open to right of dock
case "right":
return -implicitWidth - Style.marginL; // Open to left of dock
default:
return (anchorItem.width - implicitWidth) / 2; // Center horizontally
}
}
anchor.rect.y: {
if (!anchorItem)
return 0;
switch (dockPosition) {
case "top":
return anchorItem.height + Style.marginL; // Open below dock
case "bottom":
return -implicitHeight - Style.marginL; // Open above dock (default)
case "left":
case "right":
return (anchorItem.height - implicitHeight) / 2; // Center vertically
default:
return -implicitHeight - Style.marginL;
}
}
function show(item, toplevelData) {
if (!item) {
@@ -22,6 +22,33 @@ ColumnLayout {
spacing: Style.marginL
enabled: Settings.data.dock.enabled
NComboBox {
Layout.fillWidth: true
label: I18n.tr("panels.dock.appearance-position-label")
description: I18n.tr("panels.dock.appearance-position-description")
model: [
{
"key": "top",
"name": I18n.tr("positions.top")
},
{
"key": "bottom",
"name": I18n.tr("positions.bottom")
},
{
"key": "left",
"name": I18n.tr("positions.left")
},
{
"key": "right",
"name": I18n.tr("positions.right")
}
]
currentKey: Settings.data.dock.position
defaultValue: Settings.getDefaultValue("dock.position")
onSelected: key => Settings.data.dock.position = key
}
NComboBox {
Layout.fillWidth: true
label: I18n.tr("panels.display.title")