fix(new_editor/tab-drag): keep floating window under cursor
This commit is contained in:
@@ -3,8 +3,34 @@
|
||||
#include "State/EditorContext.h"
|
||||
#include "EditorWindow.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr LONG kFallbackDragHotspotX = 40;
|
||||
constexpr LONG kFallbackDragHotspotY = 12;
|
||||
|
||||
POINT BuildFallbackGlobalTabDragHotspot() {
|
||||
POINT hotspot = {};
|
||||
hotspot.x = kFallbackDragHotspotX;
|
||||
hotspot.y = kFallbackDragHotspotY;
|
||||
return hotspot;
|
||||
}
|
||||
|
||||
float ResolveWindowDpiScale(HWND hwnd) {
|
||||
if (hwnd == nullptr) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
const UINT dpi = GetDpiForWindow(hwnd);
|
||||
return dpi == 0u ? 1.0f : static_cast<float>(dpi) / 96.0f;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool EditorWindowManager::IsGlobalTabDragActive() const {
|
||||
return m_globalTabDragSession.active;
|
||||
}
|
||||
@@ -18,12 +44,94 @@ void EditorWindowManager::BeginGlobalTabDragSession(
|
||||
std::string_view panelWindowId,
|
||||
std::string_view sourceNodeId,
|
||||
std::string_view panelId,
|
||||
const POINT& screenPoint) {
|
||||
const POINT& screenPoint,
|
||||
const POINT& dragHotspot) {
|
||||
m_globalTabDragSession.active = true;
|
||||
m_globalTabDragSession.panelWindowId = std::string(panelWindowId);
|
||||
m_globalTabDragSession.sourceNodeId = std::string(sourceNodeId);
|
||||
m_globalTabDragSession.panelId = std::string(panelId);
|
||||
m_globalTabDragSession.screenPoint = screenPoint;
|
||||
m_globalTabDragSession.dragHotspot = dragHotspot;
|
||||
}
|
||||
|
||||
bool EditorWindowManager::TryResolveGlobalTabDragHotspot(
|
||||
const EditorWindow& sourceWindow,
|
||||
std::string_view nodeId,
|
||||
std::string_view panelId,
|
||||
const POINT& screenPoint,
|
||||
POINT& outDragHotspot) const {
|
||||
const HWND hwnd = sourceWindow.GetHwnd();
|
||||
if (hwnd == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& layout =
|
||||
sourceWindow.GetShellFrame().workspaceInteractionFrame.dockHostFrame.layout;
|
||||
for (const Widgets::UIEditorDockHostTabStackLayout& tabStack : layout.tabStacks) {
|
||||
if (tabStack.nodeId != nodeId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::size_t tabCount =
|
||||
(std::min)(tabStack.items.size(), tabStack.tabStripLayout.tabHeaderRects.size());
|
||||
for (std::size_t index = 0u; index < tabCount; ++index) {
|
||||
if (tabStack.items[index].panelId != panelId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ::XCEngine::UI::UIPoint clientPointDips =
|
||||
sourceWindow.ConvertScreenPixelsToClientDips(screenPoint);
|
||||
const ::XCEngine::UI::UIRect& tabRect =
|
||||
tabStack.tabStripLayout.tabHeaderRects[index];
|
||||
const float dpiScale = ResolveWindowDpiScale(hwnd);
|
||||
const float localOffsetXDips = (std::clamp)(
|
||||
clientPointDips.x - tabRect.x,
|
||||
0.0f,
|
||||
(std::max)(tabRect.width, 0.0f));
|
||||
const float localOffsetYDips = (std::clamp)(
|
||||
clientPointDips.y - tabRect.y,
|
||||
0.0f,
|
||||
(std::max)(tabRect.height, 0.0f));
|
||||
outDragHotspot.x = static_cast<LONG>(std::lround(localOffsetXDips * dpiScale));
|
||||
outDragHotspot.y = static_cast<LONG>(std::lround(localOffsetYDips * dpiScale));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditorWindowManager::UpdateGlobalTabDragOwnerWindowPosition() {
|
||||
if (!m_globalTabDragSession.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
EditorWindow* ownerWindow = FindWindow(m_globalTabDragSession.panelWindowId);
|
||||
if (ownerWindow == nullptr || ownerWindow->GetHwnd() == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
RECT windowRect = {};
|
||||
if (!GetWindowRect(ownerWindow->GetHwnd(), &windowRect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const LONG targetLeft =
|
||||
m_globalTabDragSession.screenPoint.x - m_globalTabDragSession.dragHotspot.x;
|
||||
const LONG targetTop =
|
||||
m_globalTabDragSession.screenPoint.y - m_globalTabDragSession.dragHotspot.y;
|
||||
if (windowRect.left == targetLeft && windowRect.top == targetTop) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetWindowPos(
|
||||
ownerWindow->GetHwnd(),
|
||||
nullptr,
|
||||
targetLeft,
|
||||
targetTop,
|
||||
0,
|
||||
0,
|
||||
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
void EditorWindowManager::EndGlobalTabDragSession() {
|
||||
@@ -55,6 +163,7 @@ bool EditorWindowManager::HandleGlobalTabDragPointerMove(HWND hwnd) {
|
||||
POINT screenPoint = {};
|
||||
if (GetCursorPos(&screenPoint)) {
|
||||
m_globalTabDragSession.screenPoint = screenPoint;
|
||||
UpdateGlobalTabDragOwnerWindowPosition();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -82,6 +191,14 @@ bool EditorWindowManager::TryStartGlobalTabDrag(EditorWindow& sourceWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
POINT dragHotspot = BuildFallbackGlobalTabDragHotspot();
|
||||
TryResolveGlobalTabDragHotspot(
|
||||
sourceWindow,
|
||||
pending->nodeId,
|
||||
pending->panelId,
|
||||
pending->screenPoint,
|
||||
dragHotspot);
|
||||
|
||||
if (sourceWindow.IsPrimary()) {
|
||||
UIEditorWindowWorkspaceController windowWorkspaceController =
|
||||
BuildLiveWindowWorkspaceController(sourceWindow.GetWindowId());
|
||||
@@ -115,7 +232,9 @@ bool EditorWindowManager::TryStartGlobalTabDrag(EditorWindow& sourceWindow) {
|
||||
detachedWindow->GetWindowId(),
|
||||
detachedWindow->GetWorkspaceController().GetWorkspace().root.nodeId,
|
||||
pending->panelId,
|
||||
pending->screenPoint);
|
||||
pending->screenPoint,
|
||||
dragHotspot);
|
||||
UpdateGlobalTabDragOwnerWindowPosition();
|
||||
SetCapture(detachedWindow->GetHwnd());
|
||||
SetForegroundWindow(detachedWindow->GetHwnd());
|
||||
LogRuntimeTrace(
|
||||
@@ -130,7 +249,9 @@ bool EditorWindowManager::TryStartGlobalTabDrag(EditorWindow& sourceWindow) {
|
||||
sourceWindow.GetWindowId(),
|
||||
pending->nodeId,
|
||||
pending->panelId,
|
||||
pending->screenPoint);
|
||||
pending->screenPoint,
|
||||
dragHotspot);
|
||||
UpdateGlobalTabDragOwnerWindowPosition();
|
||||
if (sourceWindow.GetHwnd() != nullptr) {
|
||||
SetCapture(sourceWindow.GetHwnd());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user