Docking: Internal: Added helper for automation to process docking at the mouse level.

This commit is contained in:
omar 2019-04-13 19:50:30 +02:00
parent 433a7556c7
commit f70eacee8e
2 changed files with 35 additions and 11 deletions

View File

@ -10896,11 +10896,11 @@ namespace ImGui
static void DockNodeUpdateVisibleFlag(ImGuiDockNode* node); static void DockNodeUpdateVisibleFlag(ImGuiDockNode* node);
static void DockNodeStartMouseMovingWindow(ImGuiDockNode* node, ImGuiWindow* window); static void DockNodeStartMouseMovingWindow(ImGuiDockNode* node, ImGuiWindow* window);
static bool DockNodeIsDropAllowed(ImGuiWindow* host_window, ImGuiWindow* payload_window); static bool DockNodeIsDropAllowed(ImGuiWindow* host_window, ImGuiWindow* payload_window);
static bool DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, ImGuiDockPreviewData* preview_data, bool is_explicit_target, bool is_outer_docking); static void DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, ImGuiDockPreviewData* preview_data, bool is_explicit_target, bool is_outer_docking);
static void DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, const ImGuiDockPreviewData* preview_data); static void DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, const ImGuiDockPreviewData* preview_data);
static ImRect DockNodeCalcTabBarRect(const ImGuiDockNode* node); static ImRect DockNodeCalcTabBarRect(const ImGuiDockNode* node);
static void DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired); static void DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired);
static bool DockNodeCalcDropRects(const ImRect& parent, ImGuiDir dir, ImRect& out_draw, bool outer_docking); static bool DockNodeCalcDropRectsAndTestMousePos(const ImRect& parent, ImGuiDir dir, ImRect& out_draw, bool outer_docking, ImVec2* test_mouse_pos);
static const char* DockNodeGetHostWindowTitle(ImGuiDockNode* node, char* buf, int buf_size) { ImFormatString(buf, buf_size, "##DockNode_%02X", node->ID); return buf; } static const char* DockNodeGetHostWindowTitle(ImGuiDockNode* node, char* buf, int buf_size) { ImFormatString(buf, buf_size, "##DockNode_%02X", node->ID); return buf; }
static int DockNodeGetDepth(const ImGuiDockNode* node) { int depth = 0; while (node->ParentNode) { node = node->ParentNode; depth++; } return depth; } static int DockNodeGetDepth(const ImGuiDockNode* node) { int depth = 0; while (node->ParentNode) { node = node->ParentNode; depth++; } return depth; }
static int DockNodeGetTabOrder(ImGuiWindow* window); static int DockNodeGetTabOrder(ImGuiWindow* window);
@ -11439,6 +11439,25 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node)
MarkIniSettingsDirty(); MarkIniSettingsDirty();
} }
// This is mostly used for automation.
bool ImGui::DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos)
{
if (split_outer)
{
IM_ASSERT(0);
}
else
{
ImGuiDockPreviewData split_data;
DockNodePreviewDockCalc(target, target_node, payload, &split_data, false, split_outer);
if (split_data.DropRectsDraw[split_dir+1].IsInverted())
return false;
*out_pos = split_data.DropRectsDraw[split_dir+1].GetCenter();
return true;
}
return false;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Docking: ImGuiDockNode // Docking: ImGuiDockNode
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -12408,7 +12427,7 @@ void ImGui::DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& po
} }
// Retrieve the drop rectangles for a given direction or for the center + perform hit testing. // Retrieve the drop rectangles for a given direction or for the center + perform hit testing.
bool ImGui::DockNodeCalcDropRects(const ImRect& parent, ImGuiDir dir, ImRect& out_r, bool outer_docking) bool ImGui::DockNodeCalcDropRectsAndTestMousePos(const ImRect& parent, ImGuiDir dir, ImRect& out_r, bool outer_docking, ImVec2* test_mouse_pos)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -12440,12 +12459,15 @@ bool ImGui::DockNodeCalcDropRects(const ImRect& parent, ImGuiDir dir, ImRect& ou
else if (dir == ImGuiDir_Left) { out_r = ImRect(c.x - off.x - hs_h, c.y - hs_w, c.x - off.x + hs_h, c.y + hs_w); } else if (dir == ImGuiDir_Left) { out_r = ImRect(c.x - off.x - hs_h, c.y - hs_w, c.x - off.x + hs_h, c.y + hs_w); }
else if (dir == ImGuiDir_Right) { out_r = ImRect(c.x + off.x - hs_h, c.y - hs_w, c.x + off.x + hs_h, c.y + hs_w); } else if (dir == ImGuiDir_Right) { out_r = ImRect(c.x + off.x - hs_h, c.y - hs_w, c.x + off.x + hs_h, c.y + hs_w); }
if (test_mouse_pos == NULL)
return false;
ImRect hit_r = out_r; ImRect hit_r = out_r;
if (!outer_docking) if (!outer_docking)
{ {
// Custom hit testing for the 5-way selection, designed to reduce flickering when moving diagonally between sides // Custom hit testing for the 5-way selection, designed to reduce flickering when moving diagonally between sides
hit_r.Expand(ImFloor(hs_w * 0.30f)); hit_r.Expand(ImFloor(hs_w * 0.30f));
ImVec2 mouse_delta = (g.IO.MousePos - c); ImVec2 mouse_delta = (*test_mouse_pos - c);
float mouse_delta_len2 = ImLengthSqr(mouse_delta); float mouse_delta_len2 = ImLengthSqr(mouse_delta);
float r_threshold_center = hs_w * 1.4f; float r_threshold_center = hs_w * 1.4f;
float r_threshold_sides = hs_w * (1.4f + 1.2f); float r_threshold_sides = hs_w * (1.4f + 1.2f);
@ -12454,14 +12476,13 @@ bool ImGui::DockNodeCalcDropRects(const ImRect& parent, ImGuiDir dir, ImRect& ou
if (mouse_delta_len2 < r_threshold_sides * r_threshold_sides) if (mouse_delta_len2 < r_threshold_sides * r_threshold_sides)
return (dir == ImGetDirQuadrantFromDelta(mouse_delta.x, mouse_delta.y)); return (dir == ImGetDirQuadrantFromDelta(mouse_delta.x, mouse_delta.y));
} }
return hit_r.Contains(g.IO.MousePos); return hit_r.Contains(*test_mouse_pos);
} }
// host_node may be NULL if the window doesn't have a DockNode already. // host_node may be NULL if the window doesn't have a DockNode already.
static bool ImGui::DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* root_payload, ImGuiDockPreviewData* data, bool is_explicit_target, bool is_outer_docking) static void ImGui::DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* root_payload, ImGuiDockPreviewData* data, bool is_explicit_target, bool is_outer_docking)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(g.CurrentWindow == host_window); // Because we rely on font size to calculate tab sizes
// There is an edge case when docking into a dockspace which only has inactive nodes. // There is an edge case when docking into a dockspace which only has inactive nodes.
// In this case DockNodeTreeFindNodeByPos() will have selected a leaf node which is inactive. // In this case DockNodeTreeFindNodeByPos() will have selected a leaf node which is inactive.
@ -12503,7 +12524,7 @@ static bool ImGui::DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNo
continue; continue;
if (dir != ImGuiDir_None && !data->IsSidesAvailable) if (dir != ImGuiDir_None && !data->IsSidesAvailable)
continue; continue;
if (DockNodeCalcDropRects(data->FutureNode.Rect(), (ImGuiDir)dir, data->DropRectsDraw[dir+1], is_outer_docking)) if (DockNodeCalcDropRectsAndTestMousePos(data->FutureNode.Rect(), (ImGuiDir)dir, data->DropRectsDraw[dir+1], is_outer_docking, &g.IO.MousePos))
{ {
data->SplitDir = (ImGuiDir)dir; data->SplitDir = (ImGuiDir)dir;
data->IsSplitDirExplicit = true; data->IsSplitDirExplicit = true;
@ -12531,13 +12552,12 @@ static bool ImGui::DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNo
data->FutureNode.Size = size_new; data->FutureNode.Size = size_new;
data->SplitRatio = (split_dir == ImGuiDir_Right || split_dir == ImGuiDir_Down) ? (1.0f - split_ratio) : (split_ratio); data->SplitRatio = (split_dir == ImGuiDir_Right || split_dir == ImGuiDir_Down) ? (1.0f - split_ratio) : (split_ratio);
} }
return data->IsSplitDirExplicit;
} }
static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* root_payload, const ImGuiDockPreviewData* data) static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* root_payload, const ImGuiDockPreviewData* data)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(g.CurrentWindow == host_window); // Because we rely on font size to calculate tab sizes
// With this option, we only display the preview on the target viewport, and the payload viewport is made transparent. // With this option, we only display the preview on the target viewport, and the payload viewport is made transparent.
// To compensate for the single layer obstructed by the payload, we'll increase the alpha of the preview nodes. // To compensate for the single layer obstructed by the payload, we'll increase the alpha of the preview nodes.
@ -13684,8 +13704,11 @@ void ImGui::BeginAsDockableDragDropTarget(ImGuiWindow* window)
ImGuiDockPreviewData* split_data = &split_inner; ImGuiDockPreviewData* split_data = &split_inner;
if (node && (node->ParentNode || node->IsCentralNode())) if (node && (node->ParentNode || node->IsCentralNode()))
if (ImGuiDockNode* root_node = DockNodeGetRootNode(node)) if (ImGuiDockNode* root_node = DockNodeGetRootNode(node))
if (DockNodePreviewDockCalc(window, root_node, payload_window, &split_outer, is_explicit_target, true)) {
DockNodePreviewDockCalc(window, root_node, payload_window, &split_outer, is_explicit_target, true);
if (split_outer.IsSplitDirExplicit)
split_data = &split_outer; split_data = &split_outer;
}
DockNodePreviewDockCalc(window, node, payload_window, &split_inner, is_explicit_target, false); DockNodePreviewDockCalc(window, node, payload_window, &split_inner, is_explicit_target, false);
if (split_data == &split_outer) if (split_data == &split_outer)
split_inner.IsDropAllowed = false; split_inner.IsDropAllowed = false;

View File

@ -1678,6 +1678,7 @@ namespace ImGui
IMGUI_API void DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer); IMGUI_API void DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer);
IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window); IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window);
IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node); IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
IMGUI_API bool DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos);
inline ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; } inline ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; }
IMGUI_API void BeginDocked(ImGuiWindow* window, bool* p_open); IMGUI_API void BeginDocked(ImGuiWindow* window, bool* p_open);
IMGUI_API void BeginAsDockableDragDropSource(ImGuiWindow* window); IMGUI_API void BeginAsDockableDragDropSource(ImGuiWindow* window);