From 8bd1b34f464c043566c1325bdc6be8b695067ab5 Mon Sep 17 00:00:00 2001 From: hstyi Date: Thu, 6 Feb 2025 09:51:45 +0800 Subject: [PATCH] feat: support drag and drop to other windows (#145) --- src/main/kotlin/app/termora/MyTabbedPane.kt | 90 ++++++++++++++++--- src/main/kotlin/app/termora/TermoraFrame.kt | 1 + .../app/termora/actions/DataProviders.kt | 1 + 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/app/termora/MyTabbedPane.kt b/src/main/kotlin/app/termora/MyTabbedPane.kt index 4b8e580..a83ba5b 100644 --- a/src/main/kotlin/app/termora/MyTabbedPane.kt +++ b/src/main/kotlin/app/termora/MyTabbedPane.kt @@ -136,19 +136,18 @@ class MyTabbedPane : FlatTabbedPane() { return } - val tab = this.terminalTab - val terminalTabbedManager = terminalTabbedManager - - if (tab != null && terminalTabbedManager != null) { - // 如果是手动取消 - if (cancelled) { - terminalTabbedManager.addTerminalTab(tabIndex, tab) - } else if (lastVisitTabIndex > 0) { - terminalTabbedManager.addTerminalTab(lastVisitTabIndex, tab) - } else if (lastVisitTabIndex == 0) { - terminalTabbedManager.addTerminalTab(1, tab) - } else { - terminalTabbedManager.addTerminalTab(tab) + val c = getTopMostWindowUnderMouse() + if (c != owner && c is TermoraFrame) { + dragToAnotherWindow(c) + } else { + val tab = this.terminalTab + val terminalTabbedManager = terminalTabbedManager + if (tab != null && terminalTabbedManager != null) { + moveTab( + terminalTabbedManager, + tab, + lastVisitTabIndex + ) } } @@ -184,6 +183,71 @@ class MyTabbedPane : FlatTabbedPane() { } return false } + + private fun getTopMostWindowUnderMouse(): Window? { + val mouseLocation = MouseInfo.getPointerInfo().location + val owner = owner + if (owner.isVisible && owner.bounds.contains(mouseLocation)) { + return owner + } + + val windows = Window.getWindows() + // 倒序遍历,最上层的窗口优先匹配 + for (i in windows.indices.reversed()) { + val window = windows[i] + if (window !is TermoraFrame) { + continue + } + if (window.isVisible && window.bounds.contains(mouseLocation)) { + val topComponent = SwingUtilities.getDeepestComponentAt( + window, + mouseLocation.x - window.x, mouseLocation.y - window.y + ) + if (topComponent != null) { + return SwingUtilities.getWindowAncestor(topComponent) + } + } + } + return null + } + + + private fun dragToAnotherWindow(frame: TermoraFrame) { + val tab = this.terminalTab ?: return + val tabbedManager = frame.getData(DataProviders.TerminalTabbed) ?: return + val tabbedPane = frame.getData(DataProviders.TabbedPane) ?: return + val location = Point(MouseInfo.getPointerInfo().location) + SwingUtilities.convertPointFromScreen(location, tabbedPane) + val index = tabbedPane.indexAtLocation(location.x, location.y) + + moveTab( + tabbedManager, + tab, + index + ) + + if (frame.hasFocus()) { + return + } + + SwingUtilities.invokeLater { + frame.requestFocus() + tabbedPane.selectedComponent?.requestFocusInWindow() + } + } + + private fun moveTab(terminalTabbedManager: TerminalTabbedManager, tab: TerminalTab, lastVisitTabIndex: Int) { + // 如果是手动取消 + if (cancelled) { + terminalTabbedManager.addTerminalTab(tabIndex, tab) + } else if (lastVisitTabIndex > 0) { + terminalTabbedManager.addTerminalTab(lastVisitTabIndex, tab) + } else if (lastVisitTabIndex == 0) { + terminalTabbedManager.addTerminalTab(1, tab) + } else { + terminalTabbedManager.addTerminalTab(tab) + } + } } diff --git a/src/main/kotlin/app/termora/TermoraFrame.kt b/src/main/kotlin/app/termora/TermoraFrame.kt index 6528f20..28e628a 100644 --- a/src/main/kotlin/app/termora/TermoraFrame.kt +++ b/src/main/kotlin/app/termora/TermoraFrame.kt @@ -116,6 +116,7 @@ class TermoraFrame : JFrame(), DataProvider { Disposer.register(windowScope, terminalTabbed) add(terminalTabbed) + dataProviderSupport.addData(DataProviders.TabbedPane, tabbedPane) dataProviderSupport.addData(DataProviders.TermoraFrame, this) dataProviderSupport.addData(DataProviders.WindowScope, windowScope) } diff --git a/src/main/kotlin/app/termora/actions/DataProviders.kt b/src/main/kotlin/app/termora/actions/DataProviders.kt index e384f8a..131ac77 100644 --- a/src/main/kotlin/app/termora/actions/DataProviders.kt +++ b/src/main/kotlin/app/termora/actions/DataProviders.kt @@ -7,6 +7,7 @@ object DataProviders { val Terminal = DataKey(app.termora.terminal.Terminal::class) val PtyConnector = DataKey(app.termora.terminal.PtyConnector::class) + val TabbedPane = DataKey(app.termora.MyTabbedPane::class) val TerminalTabbed = DataKey(app.termora.TerminalTabbed::class) val TerminalTab = DataKey(app.termora.TerminalTab::class) val TerminalTabbedManager = DataKey(app.termora.TerminalTabbedManager::class)