summaryrefslogtreecommitdiff
path: root/3rdparty/imgui-node-editor/imgui_node_editor.cpp
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2022-02-19 13:30:03 -0800
committerrtk0c <[email protected]>2022-02-19 13:30:03 -0800
commit9dcdcf68f6a60741cbdd287e7eda23b4a21a080e (patch)
treef5ff4c569607e1f63de9dd87bb7442e021b1f620 /3rdparty/imgui-node-editor/imgui_node_editor.cpp
parent2599909052ef552efd5622bf73b60913e815b498 (diff)
Fix build errors and update all dependencies to latest version
- Fixed doctest executable not compiling - Fixed class accessibility error in Workflow_Main.cpp - Fixed selection of OpenGL loader in imgui OpenGL 2 & 3 backends - All loading is handled in our code now, the imgui_*_backend.cpp files are instructed to do nothing
Diffstat (limited to '3rdparty/imgui-node-editor/imgui_node_editor.cpp')
-rw-r--r--3rdparty/imgui-node-editor/imgui_node_editor.cpp709
1 files changed, 511 insertions, 198 deletions
diff --git a/3rdparty/imgui-node-editor/imgui_node_editor.cpp b/3rdparty/imgui-node-editor/imgui_node_editor.cpp
index c1911c3..1042bed 100644
--- a/3rdparty/imgui-node-editor/imgui_node_editor.cpp
+++ b/3rdparty/imgui-node-editor/imgui_node_editor.cpp
@@ -1,4 +1,6 @@
//------------------------------------------------------------------------------
+// VERSION 0.9.1
+//
// LICENSE
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
@@ -111,7 +113,15 @@ static const float c_LinkSelectThickness = 5.0f; // canvas pixels
static const float c_NavigationZoomMargin = 0.1f; // percentage of visible bounds
static const float c_MouseZoomDuration = 0.15f; // seconds
static const float c_SelectionFadeOutDuration = 0.15f; // seconds
-static const auto c_ScrollButtonIndex = 1;
+
+static const auto c_MaxMoveOverEdgeSpeed = 10.0f;
+static const auto c_MaxMoveOverEdgeDistance = 300.0f;
+
+#if IMGUI_VERSION_NUM > 18101
+static const auto c_AllRoundCornersFlags = ImDrawFlags_RoundCornersAll;
+#else
+static const auto c_AllRoundCornersFlags = 15;
+#endif
//------------------------------------------------------------------------------
@@ -461,7 +471,7 @@ static void ImDrawList_AddBezierWithArrows(ImDrawList* drawList, const ImCubicBe
if (fill)
{
- drawList->AddBezierCurve(curve.P0, curve.P1, curve.P2, curve.P3, color, thickness);
+ drawList->AddBezierCubic(curve.P0, curve.P1, curve.P2, curve.P3, color, thickness);
if (startArrowSize > 0.0f)
{
@@ -617,7 +627,7 @@ void ed::Node::Draw(ImDrawList* drawList, DrawFlags flags)
drawList->AddRect(
m_GroupBounds.Min,
m_GroupBounds.Max,
- m_GroupBorderColor, m_GroupRounding, 15, m_GroupBorderWidth);
+ m_GroupBorderColor, m_GroupRounding, c_AllRoundCornersFlags, m_GroupBorderWidth);
}
}
@@ -668,7 +678,7 @@ void ed::Node::DrawBorder(ImDrawList* drawList, ImU32 color, float thickness)
if (thickness > 0.0f)
{
drawList->AddRect(m_Bounds.Min, m_Bounds.Max,
- color, m_Rounding, 15, thickness);
+ color, m_Rounding, c_AllRoundCornersFlags, thickness);
}
}
@@ -1009,7 +1019,9 @@ ImRect ed::Link::GetBounds() const
//------------------------------------------------------------------------------
ed::EditorContext::EditorContext(const ax::NodeEditor::Config* config)
: m_IsFirstFrame(true)
- , m_IsWindowActive(false)
+ , m_IsFocused(false)
+ , m_IsHovered(false)
+ , m_IsHoveredWithoutOverlapp(false)
, m_ShortcutsEnabled(true)
, m_Style()
, m_Nodes()
@@ -1032,6 +1044,9 @@ ed::EditorContext::EditorContext(const ax::NodeEditor::Config* config)
, m_DeleteItemsAction(this)
, m_AnimationControllers{ &m_FlowAnimationController }
, m_FlowAnimationController(this)
+ , m_HoveredNode(0)
+ , m_HoveredPin(0)
+ , m_HoveredLink(0)
, m_DoubleClickedNode(0)
, m_DoubleClickedPin(0)
, m_DoubleClickedLink(0)
@@ -1040,6 +1055,7 @@ ed::EditorContext::EditorContext(const ax::NodeEditor::Config* config)
, m_IsInitialized(false)
, m_Settings()
, m_Config(config)
+ , m_DrawList(nullptr)
, m_ExternalChannel(0)
{
}
@@ -1071,10 +1087,10 @@ void ed::EditorContext::Begin(const char* id, const ImVec2& size)
for (auto pin : m_Pins) pin->Reset();
for (auto link : m_Links) link->Reset();
- auto drawList = ImGui::GetWindowDrawList();
+ m_DrawList = ImGui::GetWindowDrawList();
- ImDrawList_SwapSplitter(drawList, m_Splitter);
- m_ExternalChannel = drawList->_Splitter._Current;
+ ImDrawList_SwapSplitter(m_DrawList, m_Splitter);
+ m_ExternalChannel = m_DrawList->_Splitter._Current;
ImGui::PushID(id);
@@ -1085,6 +1101,18 @@ void ed::EditorContext::Begin(const char* id, const ImVec2& size)
if (canvasSize.y <= 0.0f)
canvasSize.y = ImMax(4.0f, availableContentSize.y);
+ if (m_CurrentAction && m_CurrentAction->IsDragging() && m_NavigateAction.MoveOverEdge(canvasSize))
+ {
+ auto& io = ImGui::GetIO();
+ auto offset = m_NavigateAction.GetMoveScreenOffset();
+ for (int i = 0; i < 5; ++i)
+ io.MouseClickedPos[i] = io.MouseClickedPos[i] - offset;
+ }
+ else
+ m_NavigateAction.StopMoveOverEdge();
+
+ auto previousSize = m_Canvas.Rect().GetSize();
+ auto previousVisibleRect = m_Canvas.ViewRect();
m_IsCanvasVisible = m_Canvas.Begin(id, canvasSize);
//ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0));
@@ -1093,22 +1121,28 @@ void ed::EditorContext::Begin(const char* id, const ImVec2& size)
// ImGuiWindowFlags_NoScrollbar |
// ImGuiWindowFlags_NoScrollWithMouse);
- ImGui::CaptureKeyboardFromApp();
-
- m_IsWindowActive = ImGui::IsWindowFocused();
+ m_IsFocused = ImGui::IsWindowFocused();
//
- m_NavigateAction.SetWindow(m_Canvas.ViewRect().Min, m_Canvas.ViewRect().GetSize());
+ m_NavigateAction.SetWindow(m_Canvas.ViewRect().Min, m_Canvas.ViewRect().GetSize());
- if (m_CurrentAction && m_CurrentAction->IsDragging() && m_NavigateAction.MoveOverEdge())
+ // Handle canvas size change. Scale to Y axis, center on X.
+ if (!ImRect_IsEmpty(previousVisibleRect) && previousSize != canvasSize)
{
- auto& io = ImGui::GetIO();
- auto offset = m_NavigateAction.GetMoveOffset();
- for (int i = 0; i < 5; ++i)
- io.MouseClickedPos[i] = io.MouseClickedPos[i] - offset;
+ m_NavigateAction.FinishNavigation();
+
+ auto currentVisibleRect = m_Canvas.ViewRect();
+ auto currentAspectRatio = currentVisibleRect.GetHeight() ? (currentVisibleRect.GetWidth() / currentVisibleRect.GetHeight()) : 0.0f;
+
+ auto centerX = (previousVisibleRect.Max.x + previousVisibleRect.Min.x) * 0.5f;
+ auto height = previousVisibleRect.GetHeight();
+ auto width = currentAspectRatio * height;
+
+ previousVisibleRect.Min.x = centerX - 0.5f * width;
+ previousVisibleRect.Max.x = centerX + 0.5f * width;
+
+ m_NavigateAction.NavigateTo(previousVisibleRect, Detail::NavigateAction::ZoomMode::Exact, 0.0f);
}
- else
- m_NavigateAction.StopMoveOverEdge();
m_Canvas.SetView(m_NavigateAction.GetView());
@@ -1117,7 +1151,7 @@ void ed::EditorContext::Begin(const char* id, const ImVec2& size)
// clipMin.x, clipMin.y, clipMax.x - clipMin.x, clipMax.y - clipMin.y, clipMax.x, clipMax.y);
// Reserve channels for background and links
- ImDrawList_ChannelsGrow(drawList, c_NodeStartChannel);
+ ImDrawList_ChannelsGrow(m_DrawList, c_NodeStartChannel);
if (HasSelectionChanged())
++m_SelectionId;
@@ -1129,9 +1163,11 @@ void ed::EditorContext::End()
{
//auto& io = ImGui::GetIO();
auto control = BuildControl(m_CurrentAction && m_CurrentAction->IsDragging()); // NavigateAction.IsMovingOverEdge()
- auto drawList = ImGui::GetWindowDrawList();
//auto& editorStyle = GetStyle();
+ m_HoveredNode = control.HotNode && m_CurrentAction == nullptr ? control.HotNode->m_ID : 0;
+ m_HoveredPin = control.HotPin && m_CurrentAction == nullptr ? control.HotPin->m_ID : 0;
+ m_HoveredLink = control.HotLink && m_CurrentAction == nullptr ? control.HotLink->m_ID : 0;
m_DoubleClickedNode = control.DoubleClickedNode ? control.DoubleClickedNode->m_ID : 0;
m_DoubleClickedPin = control.DoubleClickedPin ? control.DoubleClickedPin->m_ID : 0;
m_DoubleClickedLink = control.DoubleClickedLink ? control.DoubleClickedLink->m_ID : 0;
@@ -1150,12 +1186,12 @@ void ed::EditorContext::End()
// Draw nodes
for (auto node : m_Nodes)
if (node->m_IsLive && node->IsVisible())
- node->Draw(drawList);
+ node->Draw(m_DrawList);
// Draw links
for (auto link : m_Links)
if (link->m_IsLive && link->IsVisible())
- link->Draw(drawList);
+ link->Draw(m_DrawList);
// Highlight selected objects
{
@@ -1165,7 +1201,7 @@ void ed::EditorContext::End()
for (auto selectedObject : *selectedObjects)
if (selectedObject->IsVisible())
- selectedObject->Draw(drawList, Object::Selected);
+ selectedObject->Draw(m_DrawList, Object::Selected);
}
if (!isSelecting)
@@ -1177,12 +1213,12 @@ void ed::EditorContext::End()
hoveredObject = sizeAction->m_SizedNode;
if (hoveredObject && !IsSelected(hoveredObject) && hoveredObject->IsVisible())
- hoveredObject->Draw(drawList, Object::Hovered);
+ hoveredObject->Draw(m_DrawList, Object::Hovered);
}
// Draw animations
for (auto controller : m_AnimationControllers)
- controller->Draw(drawList);
+ controller->Draw(m_DrawList);
if (m_CurrentAction && !m_CurrentAction->Process(control))
m_CurrentAction = nullptr;
@@ -1236,7 +1272,7 @@ void ed::EditorContext::End()
ImGui::SetMouseCursor(m_CurrentAction->GetCursor());
// Draw selection rectangle
- m_SelectAction.Draw(drawList);
+ m_SelectAction.Draw(m_DrawList);
bool sortGroups = false;
if (control.ActiveNode)
@@ -1281,6 +1317,12 @@ void ed::EditorContext::End()
});
}
+ // Apply Z order
+ std::stable_sort(m_Nodes.begin(), m_Nodes.end(), [](const auto& lhs, const auto& rhs)
+ {
+ return lhs->m_ZPosition < rhs->m_ZPosition;
+ });
+
# if 1
// Every node has few channels assigned. Grow channel list
// to hold twice as much of channels and place them in
@@ -1290,18 +1332,18 @@ void ed::EditorContext::End()
auto liveNodeCount = static_cast<int>(std::count_if(m_Nodes.begin(), m_Nodes.end(), [](Node* node) { return node->m_IsLive; }));
// Reserve two additional channels for sorted list of channels
- auto nodeChannelCount = drawList->_Splitter._Count;
- ImDrawList_ChannelsGrow(drawList, drawList->_Splitter._Count + c_ChannelsPerNode * liveNodeCount + c_LinkChannelCount);
+ auto nodeChannelCount = m_DrawList->_Splitter._Count;
+ ImDrawList_ChannelsGrow(m_DrawList, m_DrawList->_Splitter._Count + c_ChannelsPerNode * liveNodeCount + c_LinkChannelCount);
int targetChannel = nodeChannelCount;
- auto copyNode = [&targetChannel, drawList](Node* node)
+ auto copyNode = [this, &targetChannel](Node* node)
{
if (!node->m_IsLive)
return;
for (int i = 0; i < c_ChannelsPerNode; ++i)
- ImDrawList_SwapChannels(drawList, node->m_Channel + i, targetChannel + i);
+ ImDrawList_SwapChannels(m_DrawList, node->m_Channel + i, targetChannel + i);
node->m_Channel = targetChannel;
targetChannel += c_ChannelsPerNode;
@@ -1314,7 +1356,7 @@ void ed::EditorContext::End()
// Copy links
for (int i = 0; i < c_LinkChannelCount; ++i, ++targetChannel)
- ImDrawList_SwapChannels(drawList, c_LinkStartChannel + i, targetChannel);
+ ImDrawList_SwapChannels(m_DrawList, c_LinkStartChannel + i, targetChannel);
// Copy normal nodes
std::for_each(groupsItEnd, m_Nodes.end(), copyNode);
@@ -1328,7 +1370,7 @@ void ed::EditorContext::End()
{
//auto& style = ImGui::GetStyle();
- drawList->ChannelsSetCurrent(c_UserChannel_Grid);
+ m_DrawList->ChannelsSetCurrent(c_UserChannel_Grid);
ImVec2 offset = m_Canvas.ViewOrigin() * (1.0f / m_Canvas.ViewScale());
ImU32 GRID_COLOR = GetColor(StyleColor_Grid, ImClamp(m_Canvas.ViewScale() * m_Canvas.ViewScale(), 0.0f, 1.0f));
@@ -1337,12 +1379,12 @@ void ed::EditorContext::End()
ImVec2 VIEW_POS = m_Canvas.ViewRect().Min;
ImVec2 VIEW_SIZE = m_Canvas.ViewRect().GetSize();
- drawList->AddRectFilled(VIEW_POS, VIEW_POS + VIEW_SIZE, GetColor(StyleColor_Bg));
+ m_DrawList->AddRectFilled(VIEW_POS, VIEW_POS + VIEW_SIZE, GetColor(StyleColor_Bg));
for (float x = fmodf(offset.x, GRID_SX); x < VIEW_SIZE.x; x += GRID_SX)
- drawList->AddLine(ImVec2(x, 0.0f) + VIEW_POS, ImVec2(x, VIEW_SIZE.y) + VIEW_POS, GRID_COLOR);
+ m_DrawList->AddLine(ImVec2(x, 0.0f) + VIEW_POS, ImVec2(x, VIEW_SIZE.y) + VIEW_POS, GRID_COLOR);
for (float y = fmodf(offset.y, GRID_SY); y < VIEW_SIZE.y; y += GRID_SY)
- drawList->AddLine(ImVec2(0.0f, y) + VIEW_POS, ImVec2(VIEW_SIZE.x, y) + VIEW_POS, GRID_COLOR);
+ m_DrawList->AddLine(ImVec2(0.0f, y) + VIEW_POS, ImVec2(VIEW_SIZE.x, y) + VIEW_POS, GRID_COLOR);
}
# endif
@@ -1386,9 +1428,9 @@ void ed::EditorContext::End()
// These channels already have clip planes in global space, so
// we move them to clip plane. Batch transformation in canvas
// will bring them back to global space.
- auto preTransformClipRect = [this, drawList](int channelIndex)
+ auto preTransformClipRect = [this](int channelIndex)
{
- ImDrawChannel& channel = drawList->_Splitter._Channels[channelIndex];
+ ImDrawChannel& channel = m_DrawList->_Splitter._Channels[channelIndex];
for (ImDrawCmd& cmd : channel._CmdBuffer)
{
auto a = ToCanvas(ImVec2(cmd.ClipRect.x, cmd.ClipRect.y));
@@ -1397,13 +1439,13 @@ void ed::EditorContext::End()
}
};
- drawList->ChannelsSetCurrent(0);
+ m_DrawList->ChannelsSetCurrent(0);
- auto channelCount = drawList->_Splitter._Count;
- ImDrawList_ChannelsGrow(drawList, channelCount + 3);
- ImDrawList_SwapChannels(drawList, c_UserChannel_HintsBackground, channelCount + 0);
- ImDrawList_SwapChannels(drawList, c_UserChannel_Hints, channelCount + 1);
- ImDrawList_SwapChannels(drawList, c_UserChannel_Content, channelCount + 2);
+ auto channelCount = m_DrawList->_Splitter._Count;
+ ImDrawList_ChannelsGrow(m_DrawList, channelCount + 3);
+ ImDrawList_SwapChannels(m_DrawList, c_UserChannel_HintsBackground, channelCount + 0);
+ ImDrawList_SwapChannels(m_DrawList, c_UserChannel_Hints, channelCount + 1);
+ ImDrawList_SwapChannels(m_DrawList, c_UserChannel_Content, channelCount + 2);
preTransformClipRect(channelCount + 0);
preTransformClipRect(channelCount + 1);
@@ -1413,7 +1455,7 @@ void ed::EditorContext::End()
UpdateAnimations();
- drawList->ChannelsMerge();
+ m_DrawList->ChannelsMerge();
// #debug
// drawList->AddRectFilled(ImVec2(-10.0f, -10.0f), ImVec2(10.0f, 10.0f), IM_COL32(255, 0, 255, 255));
@@ -1423,17 +1465,18 @@ void ed::EditorContext::End()
if (m_IsCanvasVisible)
m_Canvas.End();
- ImDrawList_SwapSplitter(drawList, m_Splitter);
+ ImDrawList_SwapSplitter(m_DrawList, m_Splitter);
// Draw border
{
auto& style = ImGui::GetStyle();
auto borderShadoColor = style.Colors[ImGuiCol_BorderShadow];
auto borderColor = style.Colors[ImGuiCol_Border];
- drawList->AddRect(m_Canvas.Rect().Min + ImVec2(1, 1), m_Canvas.Rect().Max - ImVec2(1, 1), ImColor(borderShadoColor));
- drawList->AddRect(m_Canvas.Rect().Min, m_Canvas.Rect().Max, ImColor(borderColor));
+ m_DrawList->AddRect(m_Canvas.Rect().Min + ImVec2(1, 1), m_Canvas.Rect().Max - ImVec2(1, 1), ImColor(borderShadoColor));
+ m_DrawList->AddRect(m_Canvas.Rect().Min, m_Canvas.Rect().Max, ImColor(borderColor));
}
+ // #metrics
// ShowMetrics(control);
ImGui::PopID();
@@ -1452,6 +1495,7 @@ void ed::EditorContext::End()
if (m_Settings.m_IsDirty && !m_CurrentAction)
SaveSettings();
+ m_DrawList = nullptr;
m_IsFirstFrame = false;
}
@@ -1497,6 +1541,26 @@ void ed::EditorContext::SetNodePosition(NodeId nodeId, const ImVec2& position)
}
}
+void ed::EditorContext::SetGroupSize(NodeId nodeId, const ImVec2& size)
+{
+ auto node = FindNode(nodeId);
+ if (!node)
+ {
+ node = CreateNode(nodeId);
+ node->m_IsLive = false;
+ }
+
+ node->m_Type = NodeType::Group;
+
+ if (node->m_GroupBounds.GetSize() != size)
+ {
+ node->m_GroupBounds.Min = node->m_Bounds.Min;
+ node->m_GroupBounds.Max = node->m_Bounds.Min + size;
+ node->m_GroupBounds.Floor();
+ MakeDirty(NodeEditor::SaveReasonFlags::Size, node);
+ }
+}
+
ImVec2 ed::EditorContext::GetNodePosition(NodeId nodeId)
{
auto node = FindNode(nodeId);
@@ -1515,21 +1579,59 @@ ImVec2 ed::EditorContext::GetNodeSize(NodeId nodeId)
return node->m_Bounds.GetSize();
}
+void ed::EditorContext::SetNodeZPosition(NodeId nodeId, float z)
+{
+ auto node = FindNode(nodeId);
+ if (!node)
+ {
+ node = CreateNode(nodeId);
+ node->m_IsLive = false;
+ }
+
+ node->m_ZPosition = z;
+}
+
+float ed::EditorContext::GetNodeZPosition(NodeId nodeId)
+{
+ auto node = FindNode(nodeId);
+ if (!node)
+ return 0.0f;
+
+ return node->m_ZPosition;
+}
+
void ed::EditorContext::MarkNodeToRestoreState(Node* node)
{
node->m_RestoreState = true;
}
-void ed::EditorContext::RestoreNodeState(Node* node)
+void ed::EditorContext::UpdateNodeState(Node* node)
{
+ bool tryLoadState = node->m_RestoreState;
+
+ node->m_RestoreState = false;
+
auto settings = m_Settings.FindNode(node->m_ID);
if (!settings)
return;
- // Load state from config (if possible)
- if (!NodeSettings::Parse(m_Config.LoadNode(node->m_ID), *settings))
+ if (!tryLoadState && settings->m_WasUsed)
return;
+ if (!settings->m_WasUsed)
+ {
+ MakeDirty(SaveReasonFlags::AddNode, node);
+ settings->m_WasUsed = true;
+ }
+
+ // Load state from config (if possible)
+ if (tryLoadState)
+ {
+ NodeSettings newSettings = *settings;
+ if (NodeSettings::Parse(m_Config.LoadNode(node->m_ID), newSettings))
+ *settings = newSettings;
+ }
+
node->m_Bounds.Min = settings->m_Location;
node->m_Bounds.Max = node->m_Bounds.Min + settings->m_Size;
node->m_Bounds.Floor();
@@ -1538,6 +1640,15 @@ void ed::EditorContext::RestoreNodeState(Node* node)
node->m_GroupBounds.Floor();
}
+void ed::EditorContext::RemoveSettings(Object* object)
+{
+ if (auto node = object->AsNode())
+ {
+ m_Settings.RemoveNode(node->m_ID);
+ MakeDirty(SaveReasonFlags::RemoveNode, node);
+ }
+}
+
void ed::EditorContext::ClearSelection()
{
m_SelectedObjects.clear();
@@ -1637,6 +1748,68 @@ void ed::EditorContext::FindLinksInRect(const ImRect& r, vector<Link*>& result,
result.push_back(link);
}
+bool ed::EditorContext::HasAnyLinks(NodeId nodeId) const
+{
+ for (auto link : m_Links)
+ {
+ if (!link->m_IsLive)
+ continue;
+
+ if (link->m_StartPin->m_Node->m_ID == nodeId || link->m_EndPin->m_Node->m_ID == nodeId)
+ return true;
+ }
+
+ return false;
+}
+
+bool ed::EditorContext::HasAnyLinks(PinId pinId) const
+{
+ for (auto link : m_Links)
+ {
+ if (!link->m_IsLive)
+ continue;
+
+ if (link->m_StartPin->m_ID == pinId || link->m_EndPin->m_ID == pinId)
+ return true;
+ }
+
+ return false;
+}
+
+int ed::EditorContext::BreakLinks(NodeId nodeId)
+{
+ int result = 0;
+ for (auto link : m_Links)
+ {
+ if (!link->m_IsLive)
+ continue;
+
+ if (link->m_StartPin->m_Node->m_ID == nodeId || link->m_EndPin->m_Node->m_ID == nodeId)
+ {
+ if (GetItemDeleter().Add(link))
+ ++result;
+ }
+ }
+ return result;
+}
+
+int ed::EditorContext::BreakLinks(PinId pinId)
+{
+ int result = 0;
+ for (auto link : m_Links)
+ {
+ if (!link->m_IsLive)
+ continue;
+
+ if (link->m_StartPin->m_ID == pinId || link->m_EndPin->m_ID == pinId)
+ {
+ if (GetItemDeleter().Add(link))
+ ++result;
+ }
+ }
+ return result;
+}
+
void ed::EditorContext::FindLinksForNode(NodeId nodeId, vector<Link*>& result, bool add)
{
if (!add)
@@ -1669,24 +1842,24 @@ void ed::EditorContext::NotifyLinkDeleted(Link* link)
void ed::EditorContext::Suspend(SuspendFlags flags)
{
- auto drawList = ImGui::GetWindowDrawList();
- auto lastChannel = drawList->_Splitter._Current;
- drawList->ChannelsSetCurrent(m_ExternalChannel);
+ IM_ASSERT(m_DrawList != nullptr && "Suspend was called outiside of Begin/End.");
+ auto lastChannel = m_DrawList->_Splitter._Current;
+ m_DrawList->ChannelsSetCurrent(m_ExternalChannel);
m_Canvas.Suspend();
- drawList->ChannelsSetCurrent(lastChannel);
+ m_DrawList->ChannelsSetCurrent(lastChannel);
if ((flags & SuspendFlags::KeepSplitter) != SuspendFlags::KeepSplitter)
- ImDrawList_SwapSplitter(drawList, m_Splitter);
+ ImDrawList_SwapSplitter(m_DrawList, m_Splitter);
}
void ed::EditorContext::Resume(SuspendFlags flags)
{
- auto drawList = ImGui::GetWindowDrawList();
+ IM_ASSERT(m_DrawList != nullptr && "Reasume was called outiside of Begin/End.");
if ((flags & SuspendFlags::KeepSplitter) != SuspendFlags::KeepSplitter)
- ImDrawList_SwapSplitter(drawList, m_Splitter);
- auto lastChannel = drawList->_Splitter._Current;
- drawList->ChannelsSetCurrent(m_ExternalChannel);
+ ImDrawList_SwapSplitter(m_DrawList, m_Splitter);
+ auto lastChannel = m_DrawList->_Splitter._Current;
+ m_DrawList->ChannelsSetCurrent(m_ExternalChannel);
m_Canvas.Resume();
- drawList->ChannelsSetCurrent(lastChannel);
+ m_DrawList->ChannelsSetCurrent(lastChannel);
}
bool ed::EditorContext::IsSuspended()
@@ -1694,9 +1867,39 @@ bool ed::EditorContext::IsSuspended()
return m_Canvas.IsSuspended();
}
-bool ed::EditorContext::IsActive()
+bool ed::EditorContext::IsFocused()
+{
+ return m_IsFocused;
+}
+
+bool ed::EditorContext::IsHovered() const
+{
+ return m_IsHovered;
+}
+
+bool ed::EditorContext::IsHoveredWithoutOverlapp() const
{
- return m_IsWindowActive;
+ return m_IsHoveredWithoutOverlapp;
+}
+
+bool ed::EditorContext::CanAcceptUserInput() const
+{
+ return m_IsFocused && m_IsHovered;
+}
+
+int ed::EditorContext::CountLiveNodes() const
+{
+ return (int)std::count_if(m_Nodes.begin(), m_Nodes.end(), [](const Node* node) { return node->m_IsLive; });
+}
+
+int ed::EditorContext::CountLivePins() const
+{
+ return (int)std::count_if(m_Pins.begin(), m_Pins.end(), [](const Pin* pin) { return pin->m_IsLive; });
+}
+
+int ed::EditorContext::CountLiveLinks() const
+{
+ return (int)std::count_if(m_Links.begin(), m_Links.end(), [](const Link* link) { return link->m_IsLive; });
}
ed::Pin* ed::EditorContext::CreatePin(PinId id, PinKind kind)
@@ -1719,23 +1922,10 @@ ed::Node* ed::EditorContext::CreateNode(NodeId id)
if (!settings)
settings = m_Settings.AddNode(id);
- if (!settings->m_WasUsed)
- {
- settings->m_WasUsed = true;
- RestoreNodeState(node);
- }
-
- node->m_Bounds.Min = settings->m_Location;
- node->m_Bounds.Max = node->m_Bounds.Min;
- node->m_Bounds.Floor();
+ UpdateNodeState(node);
if (settings->m_GroupSize.x > 0 || settings->m_GroupSize.y > 0)
- {
- node->m_Type = NodeType::Group;
- node->m_GroupBounds.Min = settings->m_Location;
- node->m_GroupBounds.Max = node->m_GroupBounds.Min + settings->m_GroupSize;
- node->m_GroupBounds.Floor();
- }
+ node->m_Type = NodeType::Group;
node->m_IsLive = false;
@@ -1852,8 +2042,15 @@ void ed::EditorContext::LoadSettings()
{
ed::Settings::Parse(m_Config.Load(), m_Settings);
- m_NavigateAction.m_Scroll = m_Settings.m_ViewScroll;
- m_NavigateAction.m_Zoom = m_Settings.m_ViewZoom;
+ if (ImRect_IsEmpty(m_Settings.m_VisibleRect))
+ {
+ m_NavigateAction.m_Scroll = m_Settings.m_ViewScroll;
+ m_NavigateAction.m_Zoom = m_Settings.m_ViewZoom;
+ }
+ else
+ {
+ m_NavigateAction.NavigateTo(m_Settings.m_VisibleRect, NavigateAction::ZoomMode::Exact, 0.0f);
+ }
}
void ed::EditorContext::SaveSettings()
@@ -1879,8 +2076,9 @@ void ed::EditorContext::SaveSettings()
for (auto& object : m_SelectedObjects)
m_Settings.m_Selection.push_back(object->ID());
- m_Settings.m_ViewScroll = m_NavigateAction.m_Scroll;
- m_Settings.m_ViewZoom = m_NavigateAction.m_Zoom;
+ m_Settings.m_ViewScroll = m_NavigateAction.m_Scroll;
+ m_Settings.m_ViewZoom = m_NavigateAction.m_Zoom;
+ m_Settings.m_VisibleRect = m_NavigateAction.m_VisibleRect;
if (m_Config.Save(m_Settings.Serialize(), m_Settings.m_DirtyReason))
m_Settings.ClearDirty();
@@ -1918,6 +2116,26 @@ ImU32 ed::EditorContext::GetColor(StyleColor colorIndex, float alpha) const
return ImColor(color.x, color.y, color.z, color.w * alpha);
}
+int ed::EditorContext::GetNodeIds(NodeId* nodes, int size) const
+{
+ if (size <= 0)
+ return 0;
+
+ int result = 0;
+ for (auto node : m_Nodes)
+ {
+ if (!node->m_IsLive)
+ continue;
+
+ *nodes++ = node->m_ID;
+ ++result;
+ if (--size == 0)
+ break;
+ }
+
+ return result;
+}
+
void ed::EditorContext::RegisterAnimation(Animation* animation)
{
m_LiveAnimations.push_back(animation);
@@ -1943,9 +2161,9 @@ void ed::EditorContext::UpdateAnimations()
}
}
-void ed::EditorContext::Flow(Link* link)
+void ed::EditorContext::Flow(Link* link, FlowDirection direction)
{
- m_FlowAnimationController.Flow(link);
+ m_FlowAnimationController.Flow(link, direction);
}
void ed::EditorContext::SetUserContext(bool globalSpace)
@@ -1963,8 +2181,7 @@ void ed::EditorContext::SetUserContext(bool globalSpace)
if (!IsSuspended())
{
- auto drawList = ImGui::GetWindowDrawList();
- drawList->ChannelsSetCurrent(c_UserChannel_Content);
+ m_DrawList->ChannelsSetCurrent(c_UserChannel_Content);
}
// #debug
@@ -1983,8 +2200,14 @@ bool ed::EditorContext::AreShortcutsEnabled()
ed::Control ed::EditorContext::BuildControl(bool allowOffscreen)
{
- if (!allowOffscreen && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
- return Control(nullptr, nullptr, nullptr, nullptr, false, false, false, false);
+ m_IsHovered = false;
+ m_IsHoveredWithoutOverlapp = false;
+
+ const auto windowHovered = ImGui::IsWindowHovered();
+ const auto widgetHovered = ImGui::IsMouseHoveringRect(m_Canvas.ViewRect().Min, m_Canvas.ViewRect().Max, true);
+
+ if (!allowOffscreen && !windowHovered && !widgetHovered)
+ return Control();
const auto mousePos = ImGui::GetMousePos();
@@ -2005,8 +2228,37 @@ ed::Control ed::EditorContext::BuildControl(bool allowOffscreen)
Object* clickedObject = nullptr;
Object* doubleClickedObject = nullptr;
+ ImGuiButtonFlags extraFlags = ImGuiButtonFlags_None;
+ extraFlags |= ImGuiButtonFlags_MouseButtonLeft;
+ extraFlags |= ImGuiButtonFlags_MouseButtonRight;
+ extraFlags |= ImGuiButtonFlags_MouseButtonMiddle;
+
+ static auto invisibleButtonEx = [](const char* str_id, const ImVec2& size_arg, ImGuiButtonFlags extraFlags)
+ {
+ using namespace ImGui;
+
+ ImGuiWindow* window = GetCurrentWindow();
+ if (window->SkipItems)
+ return false;
+
+ if (size_arg.x == 0.0f || size_arg.y == 0.0f)
+ return false;
+
+ const ImGuiID id = window->GetID(str_id);
+ ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f);
+ const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
+ ItemSize(size);
+ if (!ItemAdd(bb, id))
+ return false;
+
+ bool hovered, held;
+ bool pressed = ButtonBehavior(bb, id, &hovered, &held, extraFlags);
+
+ return pressed;
+ };
+
// Emits invisible button and returns true if it is clicked.
- auto emitInteractiveArea = [](ObjectId id, const ImRect& rect)
+ auto emitInteractiveArea = [extraFlags](ObjectId id, const ImRect& rect)
{
char idString[33] = { 0 }; // itoa can output 33 bytes maximum
snprintf(idString, 32, "%p", id.AsPointer());
@@ -2015,20 +2267,20 @@ ed::Control ed::EditorContext::BuildControl(bool allowOffscreen)
// debug
//if (id < 0) return ImGui::Button(idString, to_imvec(rect.size));
- auto result = ImGui::InvisibleButton(idString, rect.GetSize());
+ auto result = invisibleButtonEx(idString, rect.GetSize(), extraFlags);
// #debug
- //ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(0, 255, 0, 64));
+ //m_DrawList->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(0, 255, 0, 64));
return result;
};
// Check input interactions over area.
- auto checkInteractionsInArea = [&emitInteractiveArea, &hotObject, &activeObject, &clickedObject, &doubleClickedObject](ObjectId id, const ImRect& rect, Object* object)
+ auto checkInteractionsInArea = [this, &emitInteractiveArea, &hotObject, &activeObject, &clickedObject, &doubleClickedObject](ObjectId id, const ImRect& rect, Object* object)
{
if (emitInteractiveArea(id, rect))
clickedObject = object;
- if (!doubleClickedObject && ImGui::IsMouseDoubleClicked(0) && ImGui::IsItemHovered())
+ if (!doubleClickedObject && ImGui::IsMouseDoubleClicked(m_Config.DragButtonIndex) && ImGui::IsItemHovered())
doubleClickedObject = object;
if (!hotObject && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
@@ -2100,7 +2352,7 @@ ed::Control ed::EditorContext::BuildControl(bool allowOffscreen)
// Check for interaction with background.
auto backgroundClicked = emitInteractiveArea(NodeId(0), editorRect);
- auto backgroundDoubleClicked = !doubleClickedObject && ImGui::IsItemHovered() ? ImGui::IsMouseDoubleClicked(0) : false;
+ auto backgroundDoubleClicked = !doubleClickedObject && ImGui::IsItemHovered() ? ImGui::IsMouseDoubleClicked(m_Config.DragButtonIndex) : false;
auto isBackgroundActive = ImGui::IsItemActive();
auto isBackgroundHot = !hotObject;
auto isDragging = ImGui::IsMouseDragging(0, 1) || ImGui::IsMouseDragging(1, 1) || ImGui::IsMouseDragging(2, 1);
@@ -2140,6 +2392,16 @@ ed::Control ed::EditorContext::BuildControl(bool allowOffscreen)
backgroundDoubleClicked = false;
}
+ m_IsHovered = ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly);
+ m_IsHoveredWithoutOverlapp = ImGui::IsItemHovered();
+ if (!allowOffscreen && !m_IsHovered)
+ return Control();
+
+# if IMGUI_VERSION_NUM >= 17909
+ if (m_IsHoveredWithoutOverlapp)
+ ImGui::SetItemUsingMouseWheel();
+# endif
+
return Control(hotObject, activeObject, clickedObject, doubleClickedObject,
isBackgroundHot, isBackgroundActive, backgroundClicked, backgroundDoubleClicked);
}
@@ -2177,9 +2439,9 @@ void ed::EditorContext::ShowMetrics(const Control& control)
return "<unknown>";
};
- auto liveNodeCount = (int)std::count_if(m_Nodes.begin(), m_Nodes.end(), [](Node* node) { return node->m_IsLive; });
- auto livePinCount = (int)std::count_if(m_Pins.begin(), m_Pins.end(), [](Pin* pin) { return pin->m_IsLive; });
- auto liveLinkCount = (int)std::count_if(m_Links.begin(), m_Links.end(), [](Link* link) { return link->m_IsLive; });
+ auto liveNodeCount = CountLiveNodes();
+ auto livePinCount = CountLivePins();
+ auto liveLinkCount = CountLiveLinks();
auto canvasRect = m_Canvas.Rect();
auto viewRect = m_Canvas.ViewRect();
@@ -2188,7 +2450,10 @@ void ed::EditorContext::ShowMetrics(const Control& control)
ImGui::SetCursorScreenPos(canvasRect.Min + ImVec2(5, 5));
ImGui::BeginGroup();
- ImGui::Text("Is Editor Active: %s", ImGui::IsWindowHovered() ? "true" : "false");
+ ImGui::Text("Is Focused: %s", m_IsFocused ? "true" : "false");
+ ImGui::Text("Is Hovered: %s", m_IsHovered ? "true" : "false");
+ ImGui::Text("Is Hovered (without overlapp): %s", m_IsHoveredWithoutOverlapp ? "true" : "false");
+ ImGui::Text("Accept Input: %s", CanAcceptUserInput() ? "true" : "false");
ImGui::Text("View Position: { x=%g y=%g }", viewRect.Min.x, viewRect.Min.y);
ImGui::Text("View Size: { w=%g h=%g }", viewRect.GetWidth(), viewRect.GetHeight());
ImGui::Text("Canvas Size: { w=%g h=%g }", canvasRect.GetWidth(), canvasRect.GetHeight());
@@ -2320,6 +2585,15 @@ ed::NodeSettings* ed::Settings::FindNode(NodeId id)
return nullptr;
}
+void ed::Settings::RemoveNode(NodeId id)
+{
+ auto node = FindNode(id);
+ if (!node)
+ return;
+
+ *node = NodeSettings(id);
+}
+
void ed::Settings::ClearDirty(Node* node)
{
if (node)
@@ -2384,6 +2658,10 @@ std::string ed::Settings::Serialize()
view["scroll"]["x"] = m_ViewScroll.x;
view["scroll"]["y"] = m_ViewScroll.y;
view["zoom"] = m_ViewZoom;
+ view["visible_rect"]["min"]["x"] = m_VisibleRect.Min.x;
+ view["visible_rect"]["min"]["y"] = m_VisibleRect.Min.y;
+ view["visible_rect"]["max"]["x"] = m_VisibleRect.Max.x;
+ view["visible_rect"]["max"]["y"] = m_VisibleRect.Max.y;
return result.dump();
}
@@ -2475,6 +2753,9 @@ bool ed::Settings::Parse(const std::string& string, Settings& settings)
result.m_ViewScroll = ImVec2(0, 0);
result.m_ViewZoom = viewZoomValue.is_number() ? static_cast<float>(viewZoomValue.get<double>()) : 1.0f;
+
+ if (!viewValue.contains("visible_rect") || !tryParseVector(viewValue["visible_rect"]["min"], result.m_VisibleRect.Min) || !tryParseVector(viewValue["visible_rect"]["max"], result.m_VisibleRect.Max))
+ result.m_VisibleRect = {};
}
settings = std::move(result);
@@ -2519,7 +2800,7 @@ void ed::Animation::Play(float duration)
Editor->RegisterAnimation(this);
if (duration == 0.0f)
- Stop();
+ Finish();
}
void ed::Animation::Stop()
@@ -2662,6 +2943,8 @@ void ed::FlowAnimation::Draw(ImDrawList* drawList)
UpdatePath();
m_Offset = fmodf(m_Offset, m_MarkerDistance);
+ if (m_Offset < 0)
+ m_Offset += m_MarkerDistance;
const auto progress = GetProgress();
@@ -2725,7 +3008,7 @@ void ed::FlowAnimation::ClearPath()
m_PathLength = 0.0f;
}
-ImVec2 ed::FlowAnimation::SamplePath(float distance)
+ImVec2 ed::FlowAnimation::SamplePath(float distance) const
{
//distance = ImMax(0.0f, std::min(distance, PathLength));
@@ -2773,7 +3056,7 @@ ed::FlowAnimationController::~FlowAnimationController()
delete animation;
}
-void ed::FlowAnimationController::Flow(Link* link)
+void ed::FlowAnimationController::Flow(Link* link, FlowDirection direction)
{
if (!link || !link->m_IsLive)
return;
@@ -2782,7 +3065,11 @@ void ed::FlowAnimationController::Flow(Link* link)
auto animation = GetOrCreate(link);
- animation->Flow(link, editorStyle.FlowMarkerDistance, editorStyle.FlowSpeed, editorStyle.FlowDuration);
+ float speedDirection = 1.0f;
+ if (direction == FlowDirection::Backward)
+ speedDirection = -1.0f;
+
+ animation->Flow(link, editorStyle.FlowMarkerDistance, editorStyle.FlowSpeed * speedDirection, editorStyle.FlowDuration);
}
void ed::FlowAnimationController::Draw(ImDrawList* drawList)
@@ -2843,6 +3130,7 @@ ed::NavigateAction::NavigateAction(EditorContext* editor, ImGuiEx::Canvas& canva
EditorAction(editor),
m_IsActive(false),
m_Zoom(1),
+ m_VisibleRect(),
m_Scroll(0, 0),
m_ScrollStart(0, 0),
m_ScrollDelta(0, 0),
@@ -2854,7 +3142,7 @@ ed::NavigateAction::NavigateAction(EditorContext* editor, ImGuiEx::Canvas& canva
m_LastSelectionId(0),
m_LastObject(nullptr),
m_MovingOverEdge(false),
- m_MoveOffset(0, 0)
+ m_MoveScreenOffset(0, 0)
{
}
@@ -2865,19 +3153,19 @@ ed::EditorAction::AcceptResult ed::NavigateAction::Accept(const Control& control
if (m_IsActive)
return False;
- if (ImGui::IsWindowHovered() /*&& !ImGui::IsAnyItemActive()*/ && ImGui::IsMouseDragging(c_ScrollButtonIndex, 0.0f))
+ if (Editor->CanAcceptUserInput() /*&& !ImGui::IsAnyItemActive()*/ && ImGui::IsMouseDragging(Editor->GetConfig().NavigateButtonIndex, 0.0f))
{
m_IsActive = true;
m_ScrollStart = m_Scroll;
- m_ScrollDelta = ImGui::GetMouseDragDelta(c_ScrollButtonIndex);
+ m_ScrollDelta = ImGui::GetMouseDragDelta(Editor->GetConfig().NavigateButtonIndex);
m_Scroll = m_ScrollStart - m_ScrollDelta * m_Zoom;
}
auto& io = ImGui::GetIO();
- if (ImGui::IsWindowFocused() && ImGui::IsKeyPressed(GetKeyIndexForF()) && Editor->AreShortcutsEnabled())
+ if (Editor->CanAcceptUserInput() && ImGui::IsKeyPressed(GetKeyIndexForF()) && Editor->AreShortcutsEnabled())
{
- const auto allowZoomIn = io.KeyShift;
+ const auto zoomMode = io.KeyShift ? NavigateAction::ZoomMode::WithMargin : NavigateAction::ZoomMode::None;
auto findHotObjectToZoom = [this, &control, &io]() -> Object*
{
@@ -2901,21 +3189,21 @@ ed::EditorAction::AcceptResult ed::NavigateAction::Accept(const Control& control
bool navigateToContent = false;
if (!Editor->GetSelectedObjects().empty())
{
- if (m_Reason != NavigationReason::Selection || m_LastSelectionId != Editor->GetSelectionId() || allowZoomIn)
+ if (m_Reason != NavigationReason::Selection || m_LastSelectionId != Editor->GetSelectionId() || (zoomMode != NavigateAction::ZoomMode::None))
{
m_LastSelectionId = Editor->GetSelectionId();
- NavigateTo(Editor->GetSelectionBounds(), allowZoomIn, -1.0f, NavigationReason::Selection);
+ NavigateTo(Editor->GetSelectionBounds(), zoomMode, -1.0f, NavigationReason::Selection);
}
else
navigateToContent = true;
}
else if(auto hotObject = findHotObjectToZoom())
{
- if (m_Reason != NavigationReason::Object || m_LastObject != hotObject || allowZoomIn)
+ if (m_Reason != NavigationReason::Object || m_LastObject != hotObject || (zoomMode != NavigateAction::ZoomMode::None))
{
m_LastObject = hotObject;
auto bounds = hotObject->GetBounds();
- NavigateTo(bounds, allowZoomIn, -1.0f, NavigationReason::Object);
+ NavigateTo(bounds, zoomMode, -1.0f, NavigationReason::Object);
}
else
navigateToContent = true;
@@ -2924,12 +3212,19 @@ ed::EditorAction::AcceptResult ed::NavigateAction::Accept(const Control& control
navigateToContent = true;
if (navigateToContent)
- NavigateTo(Editor->GetContentBounds(), true, -1.0f, NavigationReason::Content);
+ NavigateTo(Editor->GetContentBounds(), NavigateAction::ZoomMode::WithMargin, -1.0f, NavigationReason::Content);
+ }
+
+ auto visibleRect = GetViewRect();
+ if (m_VisibleRect.Min != visibleRect.Min || m_VisibleRect.Max != visibleRect.Max)
+ {
+ m_VisibleRect = visibleRect;
+ Editor->MakeDirty(SaveReasonFlags::Navigation);
}
// // #debug
- // if (auto drawList = ImGui::GetWindowDrawList())
- // drawList->AddCircleFilled(io.MousePos, 4.0f, IM_COL32(255, 0, 255, 255));
+ // if (m_DrawList)
+ // m_DrawList->AddCircleFilled(io.MousePos, 4.0f, IM_COL32(255, 0, 255, 255));
if (HandleZoom(control))
return True;
@@ -2944,11 +3239,11 @@ bool ed::NavigateAction::Process(const Control& control)
if (!m_IsActive)
return false;
- if (ImGui::IsMouseDragging(c_ScrollButtonIndex, 0.0f))
+ if (ImGui::IsMouseDragging(Editor->GetConfig().NavigateButtonIndex, 0.0f))
{
- m_ScrollDelta = ImGui::GetMouseDragDelta(c_ScrollButtonIndex);
+ m_ScrollDelta = ImGui::GetMouseDragDelta(Editor->GetConfig().NavigateButtonIndex);
m_Scroll = m_ScrollStart - m_ScrollDelta * m_Zoom;
-
+ m_VisibleRect = GetViewRect();
// if (IsActive && Animation.IsPlaying())
// Animation.Target = Animation.Target - ScrollDelta * Animation.TargetZoom;
}
@@ -2975,7 +3270,7 @@ bool ed::NavigateAction::HandleZoom(const Control& control)
auto& io = ImGui::GetIO();
- if (!io.MouseWheel || (!allowOffscreen && !ImGui::IsWindowHovered()))// && !ImGui::IsAnyItemActive())
+ if (!io.MouseWheel || (!allowOffscreen && !Editor->IsHoveredWithoutOverlapp()))// && !ImGui::IsAnyItemActive())
return false;
auto savedScroll = m_Scroll;
@@ -2997,10 +3292,13 @@ bool ed::NavigateAction::HandleZoom(const Control& control)
auto offset = (canvasPos - mousePos) * m_Zoom;
auto targetScroll = m_Scroll - offset;
- if (m_Scroll != savedScroll || m_Zoom != savedZoom)
+ auto visibleRect = GetViewRect();
+
+ if (m_Scroll != savedScroll || m_Zoom != savedZoom || m_VisibleRect.Min != visibleRect.Min || m_VisibleRect.Max != visibleRect.Max)
{
- m_Scroll = savedScroll;
- m_Zoom = savedZoom;
+ m_Scroll = savedScroll;
+ m_Zoom = savedZoom;
+ m_VisibleRect = visibleRect;
Editor->MakeDirty(SaveReasonFlags::Navigation);
}
@@ -3020,9 +3318,14 @@ void ed::NavigateAction::ShowMetrics()
ImGui::Text(" Active: %s", m_IsActive ? "yes" : "no");
ImGui::Text(" Scroll: { x=%g y=%g }", m_Scroll.x, m_Scroll.y);
ImGui::Text(" Zoom: %g", m_Zoom);
+ ImGui::Text(" Visible Rect: { l=%g t=%g, r=%g b=%g w=%g h=%g }",
+ m_VisibleRect.Min.x, m_VisibleRect.Min.y,
+ m_VisibleRect.Max.x, m_VisibleRect.Max.y,
+ m_VisibleRect.Max.x - m_VisibleRect.Min.x,
+ m_VisibleRect.Max.y - m_VisibleRect.Min.y);
}
-void ed::NavigateAction::NavigateTo(const ImRect& bounds, bool zoomIn, float duration, NavigationReason reason)
+void ed::NavigateAction::NavigateTo(const ImRect& bounds, ZoomMode zoomMode, float duration, NavigationReason reason)
{
if (ImRect_IsEmpty(bounds))
return;
@@ -3030,7 +3333,7 @@ void ed::NavigateAction::NavigateTo(const ImRect& bounds, bool zoomIn, float dur
if (duration < 0.0f)
duration = GetStyle().ScrollDuration;
- if (!zoomIn)
+ if (zoomMode == ZoomMode::None)
{
auto viewRect = m_Canvas.ViewRect();
auto viewRectCenter = viewRect.GetCenter();
@@ -3045,8 +3348,12 @@ void ed::NavigateAction::NavigateTo(const ImRect& bounds, bool zoomIn, float dur
// Grow rect by 5% to leave some reasonable margin
// from the edges of the canvas.
auto rect = bounds;
- auto extend = ImMax(rect.GetWidth(), rect.GetHeight());
- rect.Expand(extend * c_NavigationZoomMargin * 0.5f);
+
+ if (zoomMode == ZoomMode::WithMargin)
+ {
+ auto extend = ImMax(rect.GetWidth(), rect.GetHeight());
+ rect.Expand(extend * c_NavigationZoomMargin * 0.5f);
+ }
NavigateTo(rect, duration, reason);
}
@@ -3069,28 +3376,38 @@ void ed::NavigateAction::FinishNavigation()
m_Animation.Finish();
}
-bool ed::NavigateAction::MoveOverEdge()
+bool ed::NavigateAction::MoveOverEdge(const ImVec2& canvasSize)
{
// Don't interrupt non-edge animations
if (m_Animation.IsPlaying())
return false;
- auto& io = ImGui::GetIO();
- const auto screenRect = m_Canvas.ViewRect();
- const auto screenMousePos = io.MousePos;
+ auto& io = ImGui::GetIO();
+
+ const auto screenMousePos = io.MousePos;
+ const auto screenRect = ImRect(ImGui::GetCursorScreenPos(), ImGui::GetCursorScreenPos() + canvasSize);
// Mouse is over screen, do nothing
if (screenRect.Contains(screenMousePos))
return false;
- const auto screenPointOnEdge = ImRect_ClosestPoint(screenRect, screenMousePos, true);
- const auto direction = screenPointOnEdge - screenMousePos;
- const auto offset = -direction * io.DeltaTime * 10.0f;
+ // Several backend move mouse position to -FLT_MAX to indicate
+ // uninitialized/unknown state. To prevent all sorts
+ // of math problems, we just ignore such state.
+ if (screenMousePos.x <= -FLT_MAX || screenMousePos.y <= -FLT_MAX)
+ return false;
+
+ const auto minDistance = ImVec2(-c_MaxMoveOverEdgeDistance, -c_MaxMoveOverEdgeDistance);
+ const auto maxDistance = ImVec2( c_MaxMoveOverEdgeDistance, c_MaxMoveOverEdgeDistance);
- m_Scroll = m_Scroll + offset;
+ const auto screenPointOnEdge = ImRect_ClosestPoint(screenRect, screenMousePos, true);
+ const auto offset = ImMin(ImMax(screenPointOnEdge - screenMousePos, minDistance), maxDistance);
+ const auto relativeOffset = -offset * io.DeltaTime * c_MaxMoveOverEdgeSpeed;
- m_MoveOffset = offset;
- m_MovingOverEdge = true;
+ m_Scroll = m_Scroll + relativeOffset;
+
+ m_MoveScreenOffset = relativeOffset;
+ m_MovingOverEdge = true;
return true;
}
@@ -3101,8 +3418,8 @@ void ed::NavigateAction::StopMoveOverEdge()
{
Editor->MakeDirty(SaveReasonFlags::Navigation);
- m_MoveOffset = ImVec2(0, 0);
- m_MovingOverEdge = false;
+ m_MoveScreenOffset = ImVec2(0, 0);
+ m_MovingOverEdge = false;
}
}
@@ -3217,7 +3534,7 @@ ed::EditorAction::AcceptResult ed::SizeAction::Accept(const Control& control)
if (m_IsActive)
return False;
- if (control.ActiveNode && IsGroup(control.ActiveNode) && ImGui::IsMouseDragging(0, 0))
+ if (control.ActiveNode && IsGroup(control.ActiveNode) && ImGui::IsMouseDragging(Editor->GetConfig().DragButtonIndex, 0))
{
//const auto mousePos = to_point(ImGui::GetMousePos());
//const auto closestPoint = control.ActiveNode->Bounds.get_closest_point_hollow(mousePos, static_cast<int>(control.ActiveNode->Rounding));
@@ -3389,7 +3706,7 @@ ed::EditorAction::AcceptResult ed::DragAction::Accept(const Control& control)
if (m_IsActive)
return False;
- if (control.ActiveObject && ImGui::IsMouseDragging(0))
+ if (Editor->CanAcceptUserInput() && control.ActiveObject && ImGui::IsMouseDragging(Editor->GetConfig().DragButtonIndex))
{
if (!control.ActiveObject->AcceptDrag())
return False;
@@ -3457,7 +3774,7 @@ bool ed::DragAction::Process(const Control& control)
if (control.ActiveObject == m_DraggedObject)
{
- auto dragOffset = ImGui::GetMouseDragDelta(0, 0.0f);
+ auto dragOffset = ImGui::GetMouseDragDelta(Editor->GetConfig().DragButtonIndex, 0.0f);
auto draggedOrigin = m_DraggedObject->DragStartLocation();
auto alignPivot = ImVec2(0, 0);
@@ -3564,7 +3881,7 @@ ed::EditorAction::AcceptResult ed::SelectAction::Accept(const Control& control)
m_SelectedObjectsAtStart.clear();
- if (control.BackgroundActive && ImGui::IsMouseDragging(0, 1))
+ if (Editor->CanAcceptUserInput() && control.BackgroundHot && ImGui::IsMouseDragging(Editor->GetConfig().SelectButtonIndex, 1))
{
m_IsActive = true;
m_StartPoint = ImGui::GetMousePos();
@@ -3628,7 +3945,7 @@ bool ed::SelectAction::Process(const Control& control)
if (!m_IsActive)
return false;
- if (ImGui::IsMouseDragging(0, 0))
+ if (ImGui::IsMouseDragging(Editor->GetConfig().SelectButtonIndex, 0))
{
m_EndPoint = ImGui::GetMousePos();
@@ -3729,9 +4046,9 @@ ed::ContextMenuAction::ContextMenuAction(EditorContext* editor):
ed::EditorAction::AcceptResult ed::ContextMenuAction::Accept(const Control& control)
{
- const auto isPressed = ImGui::IsMouseClicked(1);
- const auto isReleased = ImGui::IsMouseReleased(1);
- const auto isDragging = ImGui::IsMouseDragging(1);
+ const auto isPressed = ImGui::IsMouseClicked(Editor->GetConfig().ContextMenuButtonIndex);
+ const auto isReleased = ImGui::IsMouseReleased(Editor->GetConfig().ContextMenuButtonIndex);
+ const auto isDragging = ImGui::IsMouseDragging(Editor->GetConfig().ContextMenuButtonIndex);
if (isPressed || isReleased || isDragging)
{
@@ -3874,7 +4191,7 @@ ed::ShortcutAction::ShortcutAction(EditorContext* editor):
ed::EditorAction::AcceptResult ed::ShortcutAction::Accept(const Control& control)
{
- if (!Editor->IsActive() || !Editor->AreShortcutsEnabled())
+ if (!Editor->IsFocused() || !Editor->AreShortcutsEnabled())
return False;
Action candidateAction = None;
@@ -4097,7 +4414,7 @@ ed::EditorAction::AcceptResult ed::CreateItemAction::Accept(const Control& contr
if (m_IsActive)
return EditorAction::False;
- if (control.ActivePin && ImGui::IsMouseDragging(0))
+ if (control.ActivePin && ImGui::IsMouseDragging(Editor->GetConfig().DragButtonIndex))
{
m_DraggedPin = control.ActivePin;
DragStart(m_DraggedPin);
@@ -4151,7 +4468,7 @@ bool ed::CreateItemAction::Process(const Control& control)
else
DropNothing();
- auto drawList = ImGui::GetWindowDrawList();
+ auto drawList = Editor->GetDrawList();
drawList->ChannelsSetCurrent(c_LinkChannel_NewLink);
candidate.UpdateEndpoints();
@@ -4159,7 +4476,7 @@ bool ed::CreateItemAction::Process(const Control& control)
}
else if (m_CurrentStage == Possible || !control.ActivePin)
{
- if (!ImGui::IsWindowHovered())
+ if (!Editor->CanAcceptUserInput())
{
m_DraggedPin = nullptr;
DropNothing();
@@ -4234,7 +4551,7 @@ bool ed::CreateItemAction::Begin()
if (m_CurrentStage == None)
return false;
- m_LastChannel = ImGui::GetWindowDrawList()->_Splitter._Current;
+ m_LastChannel = Editor->GetDrawList()->_Splitter._Current;
return true;
}
@@ -4248,9 +4565,9 @@ void ed::CreateItemAction::End()
ImGui::PopClipRect();
Editor->Resume(SuspendFlags::KeepSplitter);
- auto currentChannel = ImGui::GetWindowDrawList()->_Splitter._Current;
+ auto currentChannel = Editor->GetDrawList()->_Splitter._Current;
if (currentChannel != m_LastChannel)
- ImGui::GetWindowDrawList()->ChannelsSetCurrent(m_LastChannel);
+ Editor->GetDrawList()->ChannelsSetCurrent(m_LastChannel);
m_IsInGlobalSpace = false;
}
@@ -4408,6 +4725,20 @@ ed::DeleteItemsAction::DeleteItemsAction(EditorContext* editor):
{
}
+void ed::DeleteItemsAction::DeleteDeadLinks(NodeId nodeId)
+{
+ vector<ed::Link*> links;
+ Editor->FindLinksForNode(nodeId, links, true);
+ for (auto link : links)
+ {
+ auto it = std::find(m_CandidateObjects.begin(), m_CandidateObjects.end(), link);
+ if (it != m_CandidateObjects.end())
+ continue;
+
+ m_CandidateObjects.push_back(link);
+ }
+}
+
ed::EditorAction::AcceptResult ed::DeleteItemsAction::Accept(const Control& control)
{
IM_ASSERT(!m_IsActive);
@@ -4415,33 +4746,13 @@ ed::EditorAction::AcceptResult ed::DeleteItemsAction::Accept(const Control& cont
if (m_IsActive)
return False;
- auto addDeadLinks = [this]()
- {
- vector<ed::Link*> links;
- for (auto object : m_CandidateObjects)
- {
- auto node = object->AsNode();
- if (!node)
- continue;
-
- Editor->FindLinksForNode(node->m_ID, links, true);
- }
- if (!links.empty())
- {
- std::sort(links.begin(), links.end());
- links.erase(std::unique(links.begin(), links.end()), links.end());
- m_CandidateObjects.insert(m_CandidateObjects.end(), links.begin(), links.end());
- }
- };
-
auto& io = ImGui::GetIO();
- if (ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)) && Editor->AreShortcutsEnabled())
+ if (Editor->CanAcceptUserInput() && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)) && Editor->AreShortcutsEnabled())
{
auto& selection = Editor->GetSelectedObjects();
if (!selection.empty())
{
m_CandidateObjects = selection;
- addDeadLinks();
m_IsActive = true;
return True;
}
@@ -4458,7 +4769,6 @@ ed::EditorAction::AcceptResult ed::DeleteItemsAction::Accept(const Control& cont
{
m_CandidateObjects = m_ManuallyDeletedObjects;
m_ManuallyDeletedObjects.clear();
- addDeadLinks();
m_IsActive = true;
return True;
}
@@ -4612,14 +4922,14 @@ bool ed::DeleteItemsAction::QueryItem(ObjectId* itemId, IteratorType itemType)
return false;
}
-bool ed::DeleteItemsAction::AcceptItem()
+bool ed::DeleteItemsAction::AcceptItem(bool deleteDependencies)
{
if (!m_InInteraction)
return false;
m_UserAction = Accepted;
- RemoveItem();
+ RemoveItem(deleteDependencies);
return true;
}
@@ -4631,16 +4941,21 @@ void ed::DeleteItemsAction::RejectItem()
m_UserAction = Rejected;
- RemoveItem();
+ RemoveItem(false);
}
-void ed::DeleteItemsAction::RemoveItem()
+void ed::DeleteItemsAction::RemoveItem(bool deleteDependencies)
{
auto item = m_CandidateObjects[m_CandidateItemIndex];
m_CandidateObjects.erase(m_CandidateObjects.begin() + m_CandidateItemIndex);
Editor->DeselectObject(item);
+ Editor->RemoveSettings(item);
+
+ if (deleteDependencies && m_CurrentItemType == Node)
+ DeleteDeadLinks(item->ID().AsNodeId());
+
if (m_CurrentItemType == Link)
Editor->NotifyLinkDeleted(item->AsLink());
}
@@ -4672,11 +4987,7 @@ void ed::NodeBuilder::Begin(NodeId nodeId)
m_CurrentNode = Editor->GetNode(nodeId);
- if (m_CurrentNode->m_RestoreState)
- {
- Editor->RestoreNodeState(m_CurrentNode);
- m_CurrentNode->m_RestoreState = false;
- }
+ Editor->UpdateNodeState(m_CurrentNode);
if (m_CurrentNode->m_CenterOnScreen)
{
@@ -4730,7 +5041,7 @@ void ed::NodeBuilder::Begin(NodeId nodeId)
m_IsGroup = false;
// Grow channel list and select user channel
- if (auto drawList = ImGui::GetWindowDrawList())
+ if (auto drawList = Editor->GetDrawList())
{
m_CurrentNode->m_Channel = drawList->_Splitter._Count;
ImDrawList_ChannelsGrow(drawList, drawList->_Splitter._Count + c_ChannelsPerNode);
@@ -4755,7 +5066,7 @@ void ed::NodeBuilder::End()
{
IM_ASSERT(nullptr != m_CurrentNode);
- if (auto drawList = ImGui::GetWindowDrawList())
+ if (auto drawList = Editor->GetDrawList())
{
IM_ASSERT(drawList->_Splitter._Count == 1); // Did you forgot to call drawList->ChannelsMerge()?
ImDrawList_SwapSplitter(drawList, m_Splitter);
@@ -4768,7 +5079,9 @@ void ed::NodeBuilder::End()
{
ImGui::EndGroup();
ImGui::SameLine(0, editorStyle.NodePadding.z);
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
ImGui::Dummy(ImVec2(0, 0));
+ ImGui::PopStyleVar();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + editorStyle.NodePadding.w);
}
@@ -4832,7 +5145,7 @@ void ed::NodeBuilder::BeginPin(PinId pinId, PinKind kind)
m_ResolvePinRect = true;
m_ResolvePivot = true;
- if (auto drawList = ImGui::GetWindowDrawList())
+ if (auto drawList = Editor->GetDrawList())
{
m_PinSplitter.Clear();
ImDrawList_SwapSplitter(drawList, m_PinSplitter);
@@ -4845,7 +5158,7 @@ void ed::NodeBuilder::EndPin()
{
IM_ASSERT(nullptr != m_CurrentPin);
- if (auto drawList = ImGui::GetWindowDrawList())
+ if (auto drawList = Editor->GetDrawList())
{
IM_ASSERT(drawList->_Splitter._Count == 1); // Did you forgot to call drawList->ChannelsMerge()?
ImDrawList_SwapSplitter(drawList, m_PinSplitter);
@@ -4870,10 +5183,10 @@ void ed::NodeBuilder::EndPin()
}
// #debug: Draw pin bounds
- //ImGui::GetWindowDrawList()->AddRect(m_CurrentPin->m_Bounds.Min, m_CurrentPin->m_Bounds.Max, IM_COL32(255, 255, 0, 255));
+ //Editor->GetDrawList()->AddRect(m_CurrentPin->m_Bounds.Min, m_CurrentPin->m_Bounds.Max, IM_COL32(255, 255, 0, 255));
// #debug: Draw pin pivot rectangle
- //ImGui::GetWindowDrawList()->AddRect(m_CurrentPin->m_Pivot.Min, m_CurrentPin->m_Pivot.Max, IM_COL32(255, 0, 255, 255));
+ //Editor->GetDrawList()->AddRect(m_CurrentPin->m_Pivot.Min, m_CurrentPin->m_Pivot.Max, IM_COL32(255, 0, 255, 255));
m_CurrentPin = nullptr;
}
@@ -4945,7 +5258,7 @@ ImDrawList* ed::NodeBuilder::GetUserBackgroundDrawList(Node* node) const
{
if (node && node->m_IsLive)
{
- auto drawList = ImGui::GetWindowDrawList();
+ auto drawList = Editor->GetDrawList();
drawList->ChannelsSetCurrent(node->m_Channel + c_NodeUserBackgroundChannel);
return drawList;
}
@@ -4987,16 +5300,16 @@ bool ed::HintBuilder::Begin(NodeId nodeId)
m_CurrentNode = node;
- m_LastChannel = ImGui::GetWindowDrawList()->_Splitter._Current;
+ m_LastChannel = Editor->GetDrawList()->_Splitter._Current;
Editor->Suspend(SuspendFlags::KeepSplitter);
const auto alpha = ImMax(0.0f, std::min(1.0f, (view.Scale - c_min_zoom) / (c_max_zoom - c_min_zoom)));
- ImGui::GetWindowDrawList()->ChannelsSetCurrent(c_UserChannel_HintsBackground);
+ Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_HintsBackground);
ImGui::PushClipRect(rect.Min + ImVec2(1, 1), rect.Max - ImVec2(1, 1), false);
- ImGui::GetWindowDrawList()->ChannelsSetCurrent(c_UserChannel_Hints);
+ Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_Hints);
ImGui::PushClipRect(rect.Min + ImVec2(1, 1), rect.Max - ImVec2(1, 1), false);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
@@ -5013,13 +5326,13 @@ void ed::HintBuilder::End()
ImGui::PopStyleVar();
- ImGui::GetWindowDrawList()->ChannelsSetCurrent(c_UserChannel_Hints);
+ Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_Hints);
ImGui::PopClipRect();
- ImGui::GetWindowDrawList()->ChannelsSetCurrent(c_UserChannel_HintsBackground);
+ Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_HintsBackground);
ImGui::PopClipRect();
- ImGui::GetWindowDrawList()->ChannelsSetCurrent(m_LastChannel);
+ Editor->GetDrawList()->ChannelsSetCurrent(m_LastChannel);
Editor->Resume(SuspendFlags::KeepSplitter);
@@ -5045,7 +5358,7 @@ ImDrawList* ed::HintBuilder::GetForegroundDrawList()
{
IM_ASSERT(nullptr != m_CurrentNode);
- auto drawList = ImGui::GetWindowDrawList();
+ auto drawList = Editor->GetDrawList();
drawList->ChannelsSetCurrent(c_UserChannel_Hints);
@@ -5056,7 +5369,7 @@ ImDrawList* ed::HintBuilder::GetBackgroundDrawList()
{
IM_ASSERT(nullptr != m_CurrentNode);
- auto drawList = ImGui::GetWindowDrawList();
+ auto drawList = Editor->GetDrawList();
drawList->ChannelsSetCurrent(c_UserChannel_HintsBackground);