Milan Jurkulak 3 місяців тому
батько
коміт
a16d09c969

+ 1 - 6
ai-todo.txt

@@ -8,17 +8,12 @@
 * update dependencies from report in reports folder, on every updated library check
   that builds run and or ommit/revert update if impossible
 
-- bottom desktop panel have  invalid x coordinate, bad computation when in nested,
-  when it should be shown, by moving mouse pointer down to screen, and or, it have bad height,
-  but usualy is shown out of nested window, may be nested window position is not starting 0,0 and
-  that breaks computation?
-
 - handles that are on sliding windows 12dp please, there is 9dp i think yet.
 
 - in log, when building, there is a lot of warnings and errors, i want to have
   clean log  if possible.
 
-  - iso se negeneruje do releases na githubu
+- iso se negeneruje do releases na githubu
 
 # unimportant changes if possible:
 # control center, when shown should hide menu and bottom bar if it is visible

BIN
fix-it/20260615_150257.jpg


BIN
fix-it/Snímek obrazovky z 2026-06-14 22-01-09.png


BIN
ideas/Deepin-control-center.jpg


BIN
ideas/Deepin_23.webp


BIN
ideas/image.webp


+ 1 - 1
shared/src/commonMain/kotlin/org/mjdev/desktop/components/desktoppanel/DesktopPanel.kt

@@ -173,7 +173,7 @@ fun DesktopPanel(
                                         ).padding(
                                             start = 4.dp,
                                             end = 4.dp,
-                                            bottom = 4.dp,
+                                            bottom = 0.dp,
                                         ),
                             ) {
                                 Box(

+ 3 - 1
shared/src/commonMain/kotlin/org/mjdev/desktop/context/DesktopContextScope.kt

@@ -8,8 +8,8 @@ import androidx.compose.ui.unit.dp
 import coil3.ImageLoader
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.CoroutineStart
-import kotlinx.coroutines.Dispatchers
 import org.mjdev.desktop.data.Category
+import org.mjdev.desktop.data.PanelLocation
 import org.mjdev.desktop.interfaces.IApp
 import org.mjdev.desktop.interfaces.ILocale
 import org.mjdev.desktop.interfaces.ITheme
@@ -132,6 +132,8 @@ open class DesktopContextScope(
         get() = context.theme.panelHideDelay > 0L
     val panelDividerWidth: Dp
         get() = context.theme.panelDividerWidth
+    val panelLocation : PanelLocation
+        get() = context.theme.panelLocation
 
     val controlPanelHideDelay: Long
         get() = context.theme.controlPanelHideDelay

+ 194 - 0
shared/src/desktopMain/kotlin/org/mjdev/desktop/components/dockbar/DockBarWindow.kt

@@ -0,0 +1,194 @@
+package org.mjdev.desktop.components.dockbar
+
+import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.DpOffset
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import org.mjdev.desktop.components.desktoppanel.DesktopPanel
+import org.mjdev.desktop.context.DesktopContextScope
+import org.mjdev.desktop.context.DesktopContextScope.Companion.withDesktopContext
+import org.mjdev.desktop.extensions.Compose.preview
+import org.mjdev.desktop.extensions.LaunchedEffect.runAsync
+import org.mjdev.desktop.extensions.MutableStateExt.rememberCalculated
+import org.mjdev.desktop.extensions.MutableStateExt.rememberComputed
+import org.mjdev.desktop.extensions.PaddingValues.height
+import org.mjdev.desktop.helpers.mouseevents.MouseRange
+import org.mjdev.desktop.interfaces.IApp
+import org.mjdev.desktop.windows.ChromeWindow
+import org.mjdev.desktop.windows.ChromeWindowState
+import org.mjdev.desktop.windows.ChromeWindowState.Companion.rememberChromeWindowState
+
+/**
+ * Dock bar window — a separate copy of
+ * [org.mjdev.desktop.components.desktoppanel.DesktopPanelWindow] so the fragile original stays
+ * untouched. It keeps the original's proven mechanics 1:1 (slide, hotspot, menu coupling) and
+ * changes only the horizontal anchor.
+ *
+ * Why x = containerSize.width: [ChromeWindowState.size] pins the bottom-right corner on resize via
+ * moveBy. The original started at x = 9.dp, so the first 0 -> width grow ran moveBy(width, ..) and
+ * dragged the bar to 9 - width (≈ -1271) off-screen left. Starting at x = containerSize.width makes
+ * that same moveBy land at width - width = 0 (left edge) — exactly mirroring how y = containerSize.height
+ * lands at containerH - height (bottom edge), which already worked.
+ *
+ * For now this is bottom-only (full width, anchored to the bottom edge); per-edge docking via
+ * panelLocation is a later step.
+ */
+@Suppress("FunctionName")
+@Composable
+fun DockBarWindow(
+    iconSize: DpSize = DpSize(48.dp, 48.dp),
+    iconPadding: PaddingValues = PaddingValues(4.dp),
+    iconOuterPadding: PaddingValues = PaddingValues(2.dp),
+    showMenuIcon: Boolean = true,
+    panelState: ChromeWindowState = rememberChromeWindowState(),
+    menuState: ChromeWindowState = rememberChromeWindowState(),
+    onMenuIconClicked: () -> Unit = {
+        runAsync {
+            menuState.showOrFocus()
+        }
+    },
+    onMenuIconContextMenuClicked: () -> Unit = {},
+    onFocusChange: ChromeWindowState.(Boolean) -> Unit = {},
+    onAppClick: DesktopContextScope.(IApp) -> Unit = { app ->
+        runAsync {
+            app.start()
+        }
+    },
+    onAppContextMenuClick: (IApp) -> Unit = {},
+    onLanguageClick: () -> Unit = {},
+    onTooltip: (item: Any?) -> Unit = {},
+) = withDesktopContext {
+    val panelHeight: (visible: Boolean) -> Dp = { visible ->
+        if (visible) {
+            iconSize.height +
+                iconPadding.height.times(2) +
+                iconOuterPadding.height.times(2) +
+                theme.panelContentPadding.times(2)
+        } else {
+            panelDividerWidth
+        }
+    }
+    val size by rememberComputed(
+        panelState.isVisible,
+        panelState.enabled,
+        containerSize.width,
+        containerSize.height,
+    ) {
+        DpSize(
+            containerSize.width,
+            panelHeight(
+                if (panelState.enabled) {
+                    panelState.isVisible
+                } else {
+                    true
+                },
+            ),
+        )
+    }
+    val position by rememberComputed(size) {
+        // Bottom anchor that survives the bottom-right moveBy in ChromeWindowState.size:
+        // start at (containerW, containerH); the first 0 -> size grow's moveBy lands it at
+        // (containerW - width, containerH - height) = (0, containerH - height).
+        DpOffset(
+            containerSize.width,
+            containerSize.height,
+        )
+    }
+    val mouseRange by rememberCalculated(
+        containerSize,
+        size,
+        position,
+    ) {
+        MouseRange(
+            x = 0.dp,
+            y = containerSize.height - controlCenterDividerWidth,
+            width = containerSize.width,
+            height = size.height,
+        )
+    }
+    ChromeWindow(
+        name = "DockBar",
+        visible = true,
+        position = position,
+        size = size,
+        onFocusChange = onFocusChange,
+        windowState = panelState,
+        onCreated = {
+            panelState.position = position
+            panelState.size = size
+        },
+        isGlobalKeyHandlerEnabled = {
+            panelState.isVisible && panelState.enabled
+        },
+        onGlobalKey = {
+            onEscape {
+                runAsync {
+                    menuState.hide()
+                    panelState.hide()
+                }
+                true
+            }
+            onMenuKey {
+                runAsync {
+                    panelState.showOrFocus()
+                    menuState.showOrFocus()
+                }
+                true
+            }
+        },
+        isGlobalMouseHandlerEnabled = {
+            isUserLoggedIn && panelState.enabled
+        },
+        onGlobalMouse = {
+            onPointerEnter(mouseRange) {
+                runAsync {
+                    if (menuState.isNotVisible) {
+                        panelState.showOrFocus()
+                    }
+                }
+            }
+        },
+    ) {
+        DesktopPanel(
+            iconSize = iconSize,
+            iconPadding = iconPadding,
+            iconOuterPadding = iconOuterPadding,
+            showMenuIcon = showMenuIcon,
+            panelState = panelState,
+            onMenuIconClicked = {
+                onMenuIconClicked()
+            },
+            onMenuIconContextMenuClicked = onMenuIconContextMenuClicked,
+            onAppClick = onAppClick,
+            onAppContextMenuClick = onAppContextMenuClick,
+            onLanguageClick = onLanguageClick,
+            onTooltip = onTooltip,
+            onFocusChange = { focused ->
+                if (focused) {
+                    runAsync {
+                        panelState.show()
+                        if (menuState.isVisible) {
+                            menuState.focus()
+                        }
+                    }
+                }
+            },
+        )
+    }
+    LaunchedEffect(size, position) {
+        panelState.size = size
+    }
+}
+
+// todo
+@Preview
+@Composable
+fun PreviewDockBarWindow() =
+    preview {
+        DockBarWindow()
+    }

+ 31 - 2
shared/src/desktopMain/kotlin/org/mjdev/desktop/components/main/MainWindow.kt

@@ -17,6 +17,7 @@ import org.mjdev.desktop.components.controlcenter.ControlCenterWindow
 import org.mjdev.desktop.components.desktop.Desktop
 import org.mjdev.desktop.components.desktop.widgets.MemoryChart
 import org.mjdev.desktop.components.desktoppanel.DesktopPanelWindow
+import org.mjdev.desktop.components.dockbar.DockBarWindow
 import org.mjdev.desktop.components.greeter.GreeterWindow
 import org.mjdev.desktop.components.info.InfoWindow
 import org.mjdev.desktop.components.installer.InstallerWindow
@@ -71,6 +72,19 @@ fun MainWindow() =
 //        println("Tooltip: $item")
             tooltipState.show(item)
         }
+        // When the control center opens it covers the desktop, so the dock bar and any open menu
+        // step aside (this also frees focus so the control center can actually take it).
+        LaunchedEffect(controlCenterState.isVisible) {
+            if (controlCenterState.isVisible) {
+                panelState.hide()
+                if (menuState.isVisible) {
+                    menuState.hide()
+                }
+                if (appsMenuState.isVisible) {
+                    appsMenuState.hide()
+                }
+            }
+        }
         DesktopWindow(
             panelState = panelState,
             controlCenterState = controlCenterState,
@@ -109,12 +123,27 @@ fun MainWindow() =
                 },
             )
         }
-        DesktopPanelWindow(
+//        DesktopPanelWindow(
+//            onTooltip = onTooltip,
+//            panelState = panelState,
+//            menuState = menuState,
+//            onFocusChange = { focused ->
+////            Log.d("panel focus : $focused")
+//                val menuIsVisible = appsMenuState.isVisible || menuState.isVisible
+//                if (panelState.enabled) {
+//                    if (!menuIsVisible && !focused) {
+//                        runAsync {
+//                            panelState.hide()
+//                        }
+//                    }
+//                }
+//            },
+//        )
+        DockBarWindow(
             onTooltip = onTooltip,
             panelState = panelState,
             menuState = menuState,
             onFocusChange = { focused ->
-//            Log.d("panel focus : $focused")
                 val menuIsVisible = appsMenuState.isVisible || menuState.isVisible
                 if (panelState.enabled) {
                     if (!menuIsVisible && !focused) {