Skip to content

Commit

Permalink
Zoom follows mouse position
Browse files Browse the repository at this point in the history
  • Loading branch information
Fattorino committed Feb 7, 2024
1 parent 7290527 commit fc8b6ec
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 39 deletions.
26 changes: 13 additions & 13 deletions include/ImNodeFlow.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <functional>
#include <imgui.h>
#include "../src/imgui_bezier_math.h"
#include "../src/viewport_wrapper.h"
#include "../src/context_wrapper.h"

// TODO: [POLISH] Collision solver to bring first node on foreground to avoid clipping
// TODO: [EXTRA] Custom renderers for Pins (with lambdas I think)
Expand Down Expand Up @@ -197,8 +197,8 @@ namespace ImFlow
{
m_name = "FlowGrid" + std::to_string(m_instances);
m_instances++;
m_viewport.config().extra_window_wrapper = true;
m_viewport.config().color = m_style.colors.background;
m_context.config().extra_window_wrapper = true;
m_context.config().color = m_style.colors.background;
}

/**
Expand All @@ -209,8 +209,8 @@ namespace ImFlow
explicit ImNodeFlow(std::string name) :m_name(std::move(name))
{
m_instances++;
m_viewport.config().extra_window_wrapper = true;
m_viewport.config().color = m_style.colors.background;
m_context.config().extra_window_wrapper = true;
m_context.config().color = m_style.colors.background;
}

/**
Expand All @@ -221,8 +221,8 @@ namespace ImFlow
explicit ImNodeFlow(const char* name) :m_name(name)
{
m_instances++;
m_viewport.config().extra_window_wrapper = true;
m_viewport.config().color = m_style.colors.background;
m_context.config().extra_window_wrapper = true;
m_context.config().color = m_style.colors.background;
}

/**
Expand Down Expand Up @@ -304,14 +304,14 @@ namespace ImFlow
* @brief Get editor's position
* @return Const reference to editor's position in screen coordinates
*/
const ImVec2& pos() { return m_viewport.origin(); }
const ImVec2& pos() { return m_context.origin(); }

/**
* @brief Get editor's grid scroll
* @details Scroll is the offset from the origin of the grid, changes while navigating the grid with the middle mouse.
* @return Const reference to editor's grid scroll
*/
const ImVec2& scroll() { return m_viewport.scroll(); }
const ImVec2& scroll() { return m_context.scroll(); }

/**
* @brief Get editor's list of nodes
Expand All @@ -329,7 +329,7 @@ namespace ImFlow
* @brief Get zooming viewport
* @return Const reference to editor's internal viewport for zoom support
*/
const ViewPort& viewport() { return m_viewport; }
const ContainedContext& viewport() { return m_context; }

/**
* @brief Get dragging status
Expand Down Expand Up @@ -398,8 +398,7 @@ namespace ImFlow
InfStyler& style() { return m_style; }
private:
std::string m_name;
// ImVec2 m_pos;
ViewPort m_viewport;
ContainedContext m_context;

bool m_singleUseClick = false;

Expand Down Expand Up @@ -439,6 +438,7 @@ namespace ImFlow
{
m_paddingTL = {m_inf->style().node_padding.x, m_inf->style().node_padding.y};
m_paddingBR = {m_inf->style().node_padding.z, m_inf->style().node_padding.w};
m_posTarget = m_pos;
}

/**
Expand Down Expand Up @@ -551,7 +551,7 @@ namespace ImFlow
void updatePublicStatus() { m_selected = m_selectedNext; }
private:
std::string m_name;
ImVec2 m_pos, m_posOld = m_pos;
ImVec2 m_pos, m_posTarget;
ImVec2 m_size;
ImNodeFlow* m_inf;
bool m_selected = false, m_selectedNext = false;
Expand Down
35 changes: 18 additions & 17 deletions src/ImNodeFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ namespace ImFlow
ImGui::BeginGroup();
for(auto& p : m_ins)
{
p->pos(ImGui::GetCursorPos() + ImGui::GetWindowPos());
p->pos(ImGui::GetCursorPos());
p->update();
}
ImGui::EndGroup();
Expand Down Expand Up @@ -129,21 +129,20 @@ namespace ImFlow
m_inf->consumeSingleUseClick();
m_dragged = true;
m_inf->draggingNode(true);
m_posOld = m_pos;
}
if(m_dragged || (m_selected && m_inf->draggingNode()))
{
float step = m_inf->style().grid_size / m_inf->style().grid_subdivisions;
ImVec2 wantedPos = m_posOld + ImGui::GetMouseDragDelta(ImGuiMouseButton_Left, 0.f);
m_posTarget += ImGui::GetIO().MouseDelta;
// "Slam" The position
m_pos.x = step * (int)(wantedPos.x / step);
m_pos.y = step * (int)(wantedPos.y / step);
m_pos.x = round(m_posTarget.x / step) * step;
m_pos.y = round(m_posTarget.y / step) * step;

if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
m_dragged = false;
m_inf->draggingNode(false);
m_posOld = m_pos;
m_posTarget = m_pos;
}
}
ImGui::PopID();
Expand All @@ -170,22 +169,22 @@ namespace ImFlow

ImVec2 ImNodeFlow::content2canvas(const ImVec2& p)
{
return p + m_viewport.scroll() + ImGui::GetWindowPos();
return p + m_context.scroll() + ImGui::GetWindowPos();
}

ImVec2 ImNodeFlow::canvas2screen(const ImVec2 &p)
{
return (p + m_viewport.scroll()) * m_viewport.scale() + m_viewport.origin();
return (p + m_context.scroll()) * m_context.scale() + m_context.origin();
}

ImVec2 ImNodeFlow::screen2content(const ImVec2 &p)
{
return p - m_viewport.scroll();
return p - m_context.scroll();
}

ImVec2 ImNodeFlow::screen2canvas(const ImVec2 &p)
{
return p - pos() - m_viewport.scroll();
return p - pos() - m_context.scroll();
}

void ImNodeFlow::addLink(std::shared_ptr<Link>& link)
Expand All @@ -201,21 +200,23 @@ namespace ImFlow
m_singleUseClick = ImGui::IsMouseClicked(ImGuiMouseButton_Left);

// Create child canvas
m_viewport.begin();
m_context.begin();

ImVec2 offset = ImGui::GetCursorScreenPos() + m_viewport.scroll();
ImVec2 offset = ImGui::GetCursorScreenPos() + m_context.scroll();
ImDrawList* draw_list = ImGui::GetWindowDrawList();

draw_list->AddCircleFilled(ImVec2(0,0) + m_context.scroll(), 5.f, IM_COL32_WHITE);

// Display grid
ImVec2 win_pos = ImGui::GetCursorScreenPos();
ImVec2 canvas_sz = ImGui::GetWindowSize();
for (float x = fmodf(m_viewport.scroll().x, m_style.grid_size); x < canvas_sz.x; x += m_style.grid_size)
for (float x = fmodf(m_context.scroll().x, m_style.grid_size); x < canvas_sz.x; x += m_style.grid_size)
draw_list->AddLine(ImVec2(x, 0.0f) + win_pos, ImVec2(x, canvas_sz.y) + win_pos, m_style.colors.grid);
for (float y = fmodf(m_viewport.scroll().y, m_style.grid_size); y < canvas_sz.y; y += m_style.grid_size)
for (float y = fmodf(m_context.scroll().y, m_style.grid_size); y < canvas_sz.y; y += m_style.grid_size)
draw_list->AddLine(ImVec2(0.0f, y) + win_pos, ImVec2(canvas_sz.x, y) + win_pos, m_style.colors.grid);
for (float x = fmodf(m_viewport.scroll().x, m_style.grid_size / m_style.grid_subdivisions); x < canvas_sz.x; x += m_style.grid_size / m_style.grid_subdivisions)
for (float x = fmodf(m_context.scroll().x, m_style.grid_size / m_style.grid_subdivisions); x < canvas_sz.x; x += m_style.grid_size / m_style.grid_subdivisions)
draw_list->AddLine(ImVec2(x, 0.0f) + win_pos, ImVec2(x, canvas_sz.y) + win_pos, m_style.colors.subGrid);
for (float y = fmodf(m_viewport.scroll().y, m_style.grid_size / m_style.grid_subdivisions); y < canvas_sz.y; y += m_style.grid_size / m_style.grid_subdivisions)
for (float y = fmodf(m_context.scroll().y, m_style.grid_size / m_style.grid_subdivisions); y < canvas_sz.y; y += m_style.grid_size / m_style.grid_subdivisions)
draw_list->AddLine(ImVec2(0.0f, y) + win_pos, ImVec2(canvas_sz.x, y) + win_pos, m_style.colors.subGrid);

// Update and draw nodes
Expand Down Expand Up @@ -289,6 +290,6 @@ namespace ImFlow
m_links.erase(std::remove_if(m_links.begin(), m_links.end(),
[](const std::weak_ptr<Link>& l) { return l.expired(); }), m_links.end());

m_viewport.end();
m_context.end();
}
}
32 changes: 23 additions & 9 deletions src/viewport_wrapper.h → src/context_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ inline static void AppendDrawData(ImDrawList* src, ImVec2 origin, float scale)
}
for (auto cmd : src->CmdBuffer) {
cmd.IdxOffset += idx_start;
//ASSERT(cmd.VtxOffset == 0)
IM_ASSERT(cmd.VtxOffset == 0);
cmd.ClipRect.x = cmd.ClipRect.x * scale + origin.x;
cmd.ClipRect.y = cmd.ClipRect.y * scale + origin.y;
cmd.ClipRect.z = cmd.ClipRect.z * scale + origin.x;
Expand All @@ -62,10 +62,10 @@ struct ViewPortConfig
ImGuiMouseButton scroll_button = ImGuiMouseButton_Middle;
};

class ViewPort
class ContainedContext
{
public:
~ViewPort();
~ContainedContext();
ViewPortConfig& config() { return m_config; }
void begin();
void end();
Expand All @@ -77,6 +77,7 @@ class ViewPort
ViewPortConfig m_config;

ImVec2 m_origin;
ImVec2 m_pos, m_size;
ImGuiContext* m_ctx = nullptr;
ImGuiContext* m_original_ctx = nullptr;

Expand All @@ -85,20 +86,22 @@ class ViewPort
bool m_hovered = false;

float m_scale = m_config.default_zoom, m_scaleTarget = m_config.default_zoom;
ImVec2 m_scroll = {0.f, 0.f};
ImVec2 m_scroll = {0.f, 0.f}, m_scrollTarget = {0.f, 0.f};
};

inline ViewPort::~ViewPort()
inline ContainedContext::~ContainedContext()
{
if (m_ctx) ImGui::DestroyContext(m_ctx);
}

inline void ViewPort::begin()
inline void ContainedContext::begin()
{
ImGui::PushID(this);
ImGui::PushStyleColor(ImGuiCol_ChildBg, m_config.color);
ImGui::BeginChild("view_port", m_config.size, 0, ImGuiWindowFlags_NoMove);
ImGui::PopStyleColor();
m_size = ImGui::GetWindowSize();
m_pos = ImGui::GetWindowPos();

ImVec2 size = ImGui::GetContentRegionAvail();
m_origin = ImGui::GetCursorScreenPos();
Expand All @@ -125,7 +128,7 @@ inline void ViewPort::begin()
ImGui::PopStyleVar();
}

inline void ViewPort::end()
inline void ContainedContext::end()
{
m_anyWindowHovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow);
if (m_config.extra_window_wrapper && ImGui::IsWindowHovered())
Expand Down Expand Up @@ -154,16 +157,24 @@ inline void ViewPort::end()
m_scaleTarget += ImGui::GetIO().MouseWheel / 16;
m_scaleTarget = m_scaleTarget < 0.3f ? 0.3f : m_scaleTarget;
m_scaleTarget = m_scaleTarget > 2.f ? 2.f : m_scaleTarget;

if (m_config.zoom_smoothness == 0.f)
{
m_scroll += (ImGui::GetMousePos() - m_pos) / m_scaleTarget - (ImGui::GetMousePos() - m_pos) / m_scale;
m_scale = m_scaleTarget;
}
}
if (abs(m_scaleTarget - m_scale) >= 0.015f / m_config.zoom_smoothness)
{
float cs = (m_scaleTarget - m_scale) / m_config.zoom_smoothness;
m_scroll += (ImGui::GetMousePos() - m_pos) / (m_scale + cs) - (ImGui::GetMousePos() - m_pos) / m_scale;
m_scale += (m_scaleTarget - m_scale) / m_config.zoom_smoothness;
if (abs(m_scaleTarget - m_scale) < 0.02f)

if (abs(m_scaleTarget - m_scale) < 0.015f)
{
m_scroll += (ImGui::GetMousePos() - m_pos) / m_scaleTarget - (ImGui::GetMousePos() - m_pos) / m_scale;
m_scale = m_scaleTarget;
}
}

// Zoom reset
Expand All @@ -172,7 +183,10 @@ inline void ViewPort::end()

// Scrolling
if (m_hovered && !m_anyItemActive && ImGui::IsMouseDragging(m_config.scroll_button, 0.f))
m_scroll = m_scroll + ImGui::GetIO().MouseDelta / m_scale;
{
m_scroll += ImGui::GetIO().MouseDelta / m_scale;
m_scrollTarget = m_scroll;
}

ImGui::EndChild();
ImGui::PopID();
Expand Down

0 comments on commit fc8b6ec

Please sign in to comment.