feat(dock): implement application launcher icon with configurable position

This commit is contained in:
tibssy
2026-02-19 03:33:38 +00:00
parent ceda3dfd43
commit 6c555770cd
5 changed files with 148 additions and 0 deletions
+4
View File
@@ -1041,6 +1041,10 @@
"appearance-colorize-icons-label": "Colorize icons",
"appearance-show-launcher-icon-description": "Show the application launcher icon in the dock.",
"appearance-show-launcher-icon-label": "Show App Launcher",
"appearance-launcher-position-description": "Choose where the launcher icon appears in the dock.",
"appearance-launcher-position-label": "Launcher position",
"appearance-launcher-position-start": "Start",
"appearance-launcher-position-end": "End",
"appearance-dead-opacity-description": "Adjust the opacity of app icons that are not running.",
"appearance-dead-opacity-label": "Dead opacity",
"appearance-desc": "Customize the dock's behavior and appearance.",
+1
View File
@@ -332,6 +332,7 @@
"pinnedApps": [],
"colorizeIcons": false,
"showLauncherIcon": false,
"launcherPosition": "end",
"pinnedStatic": false,
"inactiveIndicators": false,
"deadOpacity": 0.6,
+1
View File
@@ -533,6 +533,7 @@ Singleton {
property list<string> pinnedApps: [] // Desktop entry IDs pinned to the dock (e.g., "org.kde.konsole", "firefox.desktop")
property bool colorizeIcons: false
property bool showLauncherIcon: false
property string launcherPosition: "end" // "start", "end"
property bool pinnedStatic: false
property bool inactiveIndicators: false
+122
View File
@@ -132,6 +132,113 @@ Item {
width: implicitWidth
height: implicitHeight
Component {
id: launcherButtonComponent
Item {
id: launcherButton
anchors.fill: parent
readonly property string screenName: dockRoot.modelData ? dockRoot.modelData.name : (dockRoot.screen ? dockRoot.screen.name : "")
readonly property var launcherWidgetSettings: {
const widgetsBySection = screenName ? Settings.getBarWidgetsForScreen(screenName) : Settings.data.bar.widgets;
if (!widgetsBySection)
return {};
const sections = ["left", "center", "right"];
for (let i = 0; i < sections.length; i++) {
const sectionWidgets = widgetsBySection[sections[i]] || [];
for (let j = 0; j < sectionWidgets.length; j++) {
const widget = sectionWidgets[j];
if (widget && widget.id === "Launcher")
return widget;
}
}
return {};
}
readonly property var launcherMetadata: BarWidgetRegistry.widgetMetadata["Launcher"]
readonly property string launcherIcon: launcherWidgetSettings.icon || (launcherMetadata && launcherMetadata.icon ? launcherMetadata.icon : "search")
readonly property string launcherIconColorKey: launcherWidgetSettings.iconColor !== undefined
? launcherWidgetSettings.iconColor
: (launcherMetadata && launcherMetadata.iconColor !== undefined ? launcherMetadata.iconColor : "none")
Item {
id: launcherIconContainer
width: dockRoot.iconSize
height: dockRoot.iconSize
anchors.centerIn: parent
scale: launcherMouseArea.containsMouse ? 1.15 : 1.0
Behavior on scale {
NumberAnimation {
duration: Style.animationNormal
easing.type: Easing.OutBack
easing.overshoot: 1.2
}
}
NIcon {
anchors.centerIn: parent
icon: launcherButton.launcherIcon
pointSize: dockRoot.iconSize * 0.7
color: Color.resolveColorKey(launcherButton.launcherIconColorKey)
}
}
MouseArea {
id: launcherMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
onEntered: {
dockRoot.anyAppHovered = true;
TooltipService.show(launcherButton, I18n.tr("actions.open-launcher"), "top");
if (dockRoot.autoHide) {
dockRoot.showTimer.stop();
dockRoot.hideTimer.stop();
dockRoot.unloadTimer.stop();
dockRoot.hidden = false;
}
}
onExited: {
dockRoot.anyAppHovered = false;
TooltipService.hide();
if (dockRoot.autoHide && !dockRoot.dockHovered && !dockRoot.peekHovered && !dockRoot.menuHovered && dockRoot.dragSourceIndex === -1) {
dockRoot.hideTimer.restart();
}
}
onClicked: mouse => {
if (mouse.button !== Qt.LeftButton && mouse.button !== Qt.MiddleButton) {
return;
}
const targetScreen = dockRoot.modelData || dockRoot.screen || null;
if (!targetScreen) {
return;
}
dockRoot.closeAllContextMenus();
PanelService.toggleLauncher(targetScreen);
}
}
}
}
Loader {
id: launcherButtonStart
active: Settings.data.dock.showLauncherIcon && Settings.data.dock.launcherPosition === "start"
visible: active
sourceComponent: launcherButtonComponent
readonly property real indicatorMargin: Math.max(3, Math.round(dockRoot.iconSize * 0.18))
Layout.preferredWidth: active ? (dockRoot.isVertical ? dockRoot.iconSize + indicatorMargin * 2 : dockRoot.iconSize) : 0
Layout.preferredHeight: active ? (dockRoot.isVertical ? dockRoot.iconSize : dockRoot.iconSize + indicatorMargin * 2) : 0
Layout.minimumWidth: active ? Layout.preferredWidth : 0
Layout.minimumHeight: active ? Layout.preferredHeight : 0
Layout.maximumWidth: active ? Layout.preferredWidth : 0
Layout.maximumHeight: active ? Layout.preferredHeight : 0
Layout.alignment: Qt.AlignCenter
}
Repeater {
model: dockRoot.dockApps
@@ -521,6 +628,21 @@ Item {
}
}
}
Loader {
id: launcherButtonEnd
active: Settings.data.dock.showLauncherIcon && Settings.data.dock.launcherPosition === "end"
visible: active
sourceComponent: launcherButtonComponent
readonly property real indicatorMargin: Math.max(3, Math.round(dockRoot.iconSize * 0.18))
Layout.preferredWidth: active ? (dockRoot.isVertical ? dockRoot.iconSize + indicatorMargin * 2 : dockRoot.iconSize) : 0
Layout.preferredHeight: active ? (dockRoot.isVertical ? dockRoot.iconSize : dockRoot.iconSize + indicatorMargin * 2) : 0
Layout.minimumWidth: active ? Layout.preferredWidth : 0
Layout.minimumHeight: active ? Layout.preferredHeight : 0
Layout.maximumWidth: active ? Layout.preferredWidth : 0
Layout.maximumHeight: active ? Layout.preferredHeight : 0
Layout.alignment: Qt.AlignCenter
}
}
}
}
@@ -227,5 +227,25 @@ ColumnLayout {
defaultValue: Settings.getDefaultValue("dock.showLauncherIcon")
onToggled: checked => Settings.data.dock.showLauncherIcon = checked
}
NComboBox {
Layout.fillWidth: true
visible: Settings.data.dock.showLauncherIcon
label: I18n.tr("panels.dock.appearance-launcher-position-label")
description: I18n.tr("panels.dock.appearance-launcher-position-description")
model: [
{
"key": "start",
"name": I18n.tr("panels.dock.appearance-launcher-position-start")
},
{
"key": "end",
"name": I18n.tr("panels.dock.appearance-launcher-position-end")
}
]
currentKey: Settings.data.dock.launcherPosition
defaultValue: Settings.getDefaultValue("dock.launcherPosition")
onSelected: key => Settings.data.dock.launcherPosition = key
}
}
}