aboutsummaryrefslogtreecommitdiff
path: root/3rdparty/imgui-node-editor
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/imgui-node-editor')
-rw-r--r--3rdparty/imgui-node-editor/CMakeLists.txt13
-rw-r--r--3rdparty/imgui-node-editor/crude_json.cpp890
-rw-r--r--3rdparty/imgui-node-editor/crude_json.h250
-rw-r--r--3rdparty/imgui-node-editor/imgui_bezier_math.h144
-rw-r--r--3rdparty/imgui-node-editor/imgui_bezier_math.inl675
-rw-r--r--3rdparty/imgui-node-editor/imgui_canvas.cpp550
-rw-r--r--3rdparty/imgui-node-editor/imgui_canvas.h268
-rw-r--r--3rdparty/imgui-node-editor/imgui_extra_math.h73
-rw-r--r--3rdparty/imgui-node-editor/imgui_extra_math.inl189
-rw-r--r--3rdparty/imgui-node-editor/imgui_node_editor.cpp5629
-rw-r--r--3rdparty/imgui-node-editor/imgui_node_editor.h481
-rw-r--r--3rdparty/imgui-node-editor/imgui_node_editor_api.cpp734
-rw-r--r--3rdparty/imgui-node-editor/imgui_node_editor_internal.h1536
-rw-r--r--3rdparty/imgui-node-editor/imgui_node_editor_internal.inl57
-rw-r--r--3rdparty/imgui-node-editor/thedmd-imgui-node-editor.LICENSE.txt21
-rw-r--r--3rdparty/imgui-node-editor/thedmd-imgui-node-editor.stamp2
16 files changed, 0 insertions, 11512 deletions
diff --git a/3rdparty/imgui-node-editor/CMakeLists.txt b/3rdparty/imgui-node-editor/CMakeLists.txt
deleted file mode 100644
index 614b7e9..0000000
--- a/3rdparty/imgui-node-editor/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-file(GLOB IMGUI_NODE_EDITOR_SOURCES *.cpp)
-
-add_library(imgui-node-editor ${IMGUI_NODE_EDITOR_SOURCES})
-set_target_properties(imgui-node-editor PROPERTIES UNITY_BUILD OFF)
-target_include_directories(imgui-node-editor PRIVATE
- ${CMAKE_SOURCE_DIR}/3rdparty/imgui-node-editor
- ${CMAKE_SOURCE_DIR}/3rdparty/imgui
-)
-
-set_target_properties(imgui-node-editor
-PROPERTIES
- UNITY_BUILD OFF
-)
diff --git a/3rdparty/imgui-node-editor/crude_json.cpp b/3rdparty/imgui-node-editor/crude_json.cpp
deleted file mode 100644
index a9f7c70..0000000
--- a/3rdparty/imgui-node-editor/crude_json.cpp
+++ /dev/null
@@ -1,890 +0,0 @@
-// Crude implementation of JSON value object and parser.
-//
-// VERSION 0.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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-# include "crude_json.h"
-# include <iomanip>
-# include <limits>
-# include <cstdlib>
-# include <clocale>
-# include <cmath>
-# include <cstring>
-# if CRUDE_JSON_IO
-# include <stdio.h>
-# include <memory>
-# endif
-
-namespace crude_json {
-
-value::value(value&& other)
- : m_Type(other.m_Type)
-{
- switch (m_Type)
- {
- case type_t::object: construct(m_Storage, std::move( *object_ptr(other.m_Storage))); break;
- case type_t::array: construct(m_Storage, std::move( *array_ptr(other.m_Storage))); break;
- case type_t::string: construct(m_Storage, std::move( *string_ptr(other.m_Storage))); break;
- case type_t::boolean: construct(m_Storage, std::move(*boolean_ptr(other.m_Storage))); break;
- case type_t::number: construct(m_Storage, std::move( *number_ptr(other.m_Storage))); break;
- default: break;
- }
- destruct(other.m_Storage, other.m_Type);
- other.m_Type = type_t::null;
-}
-
-value::value(const value& other)
- : m_Type(other.m_Type)
-{
- switch (m_Type)
- {
- case type_t::object: construct(m_Storage, *object_ptr(other.m_Storage)); break;
- case type_t::array: construct(m_Storage, *array_ptr(other.m_Storage)); break;
- case type_t::string: construct(m_Storage, *string_ptr(other.m_Storage)); break;
- case type_t::boolean: construct(m_Storage, *boolean_ptr(other.m_Storage)); break;
- case type_t::number: construct(m_Storage, *number_ptr(other.m_Storage)); break;
- default: break;
- }
-}
-
-value& value::operator[](size_t index)
-{
- if (is_null())
- m_Type = construct(m_Storage, type_t::array);
-
- if (is_array())
- {
- auto& v = *array_ptr(m_Storage);
- if (index >= v.size())
- v.insert(v.end(), index - v.size() + 1, value());
-
- return v[index];
- }
-
- CRUDE_ASSERT(false && "operator[] on unsupported type");
- std::terminate();
-}
-
-const value& value::operator[](size_t index) const
-{
- if (is_array())
- return (*array_ptr(m_Storage))[index];
-
- CRUDE_ASSERT(false && "operator[] on unsupported type");
- std::terminate();
-}
-
-value& value::operator[](const string& key)
-{
- if (is_null())
- m_Type = construct(m_Storage, type_t::object);
-
- if (is_object())
- return (*object_ptr(m_Storage))[key];
-
- CRUDE_ASSERT(false && "operator[] on unsupported type");
- std::terminate();
-}
-
-const value& value::operator[](const string& key) const
-{
- if (is_object())
- {
- auto& o = *object_ptr(m_Storage);
- auto it = o.find(key);
- CRUDE_ASSERT(it != o.end());
- return it->second;
- }
-
- CRUDE_ASSERT(false && "operator[] on unsupported type");
- std::terminate();
-}
-
-bool value::contains(const string& key) const
-{
- if (is_object())
- {
- auto& o = *object_ptr(m_Storage);
- auto it = o.find(key);
- return it != o.end();
- }
-
- return false;
-}
-
-void value::push_back(const value& value)
-{
- if (is_null())
- m_Type = construct(m_Storage, type_t::array);
-
- if (is_array())
- {
- auto& v = *array_ptr(m_Storage);
- v.push_back(value);
- }
- else
- {
- CRUDE_ASSERT(false && "operator[] on unsupported type");
- std::terminate();
- }
-}
-
-void value::push_back(value&& value)
-{
- if (is_null())
- m_Type = construct(m_Storage, type_t::array);
-
- if (is_array())
- {
- auto& v = *array_ptr(m_Storage);
- v.push_back(std::move(value));
- }
- else
- {
- CRUDE_ASSERT(false && "operator[] on unsupported type");
- std::terminate();
- }
-}
-
-size_t value::erase(const string& key)
-{
- if (!is_object())
- return 0;
-
- auto& o = *object_ptr(m_Storage);
- auto it = o.find(key);
-
- if (it == o.end())
- return 0;
-
- o.erase(it);
-
- return 1;
-}
-
-void value::swap(value& other)
-{
- using std::swap;
-
- if (m_Type == other.m_Type)
- {
- switch (m_Type)
- {
- case type_t::object: swap(*object_ptr(m_Storage), *object_ptr(other.m_Storage)); break;
- case type_t::array: swap(*array_ptr(m_Storage), *array_ptr(other.m_Storage)); break;
- case type_t::string: swap(*string_ptr(m_Storage), *string_ptr(other.m_Storage)); break;
- case type_t::boolean: swap(*boolean_ptr(m_Storage), *boolean_ptr(other.m_Storage)); break;
- case type_t::number: swap(*number_ptr(m_Storage), *number_ptr(other.m_Storage)); break;
- default: break;
- }
- }
- else
- {
- value tmp(std::move(other));
- other.~value();
- new (&other) value(std::move(*this));
- this->~value();
- new (this) value(std::move(tmp));
- }
-}
-
-string value::dump(const int indent, const char indent_char) const
-{
- dump_context_t context(indent, indent_char);
-
- context.out.precision(std::numeric_limits<double>::max_digits10 + 1);
- context.out << std::defaultfloat;
-
- dump(context, 0);
- return context.out.str();
-}
-
-void value::dump_context_t::write_indent(int level)
-{
- if (indent <= 0 || level == 0)
- return;
-
- out.fill(indent_char);
- out.width(indent * level);
- out << indent_char;
- out.width(0);
-}
-
-void value::dump_context_t::write_separator()
-{
- if (indent < 0)
- return;
-
- out.put(' ');
-}
-
-void value::dump_context_t::write_newline()
-{
- if (indent < 0)
- return;
-
- out.put('\n');
-}
-
-void value::dump(dump_context_t& context, int level) const
-{
- context.write_indent(level);
-
- switch (m_Type)
- {
- case type_t::null:
- context.out << "null";
- break;
-
- case type_t::object:
- context.out << '{';
- {
- context.write_newline();
- bool first = true;
- for (auto& entry : *object_ptr(m_Storage))
- {
- if (!first) { context.out << ','; context.write_newline(); } else first = false;
- context.write_indent(level + 1);
- context.out << '\"' << entry.first << "\":";
- if (!entry.second.is_structured())
- {
- context.write_separator();
- entry.second.dump(context, 0);
- }
- else
- {
- context.write_newline();
- entry.second.dump(context, level + 1);
- }
- }
- if (!first)
- context.write_newline();
- }
- context.write_indent(level);
- context.out << '}';
- break;
-
- case type_t::array:
- context.out << '[';
- {
- context.write_newline();
- bool first = true;
- for (auto& entry : *array_ptr(m_Storage))
- {
- if (!first) { context.out << ','; context.write_newline(); } else first = false;
- if (!entry.is_structured())
- {
- context.write_indent(level + 1);
- entry.dump(context, 0);
- }
- else
- {
- entry.dump(context, level + 1);
- }
- }
- if (!first)
- context.write_newline();
- }
- context.write_indent(level);
- context.out << ']';
- break;
-
- case type_t::string:
- context.out << '\"';
-
- if (string_ptr(m_Storage)->find_first_of("\"\\/\b\f\n\r") != string::npos || string_ptr(m_Storage)->find('\0') != string::npos)
- {
- for (auto c : *string_ptr(m_Storage))
- {
- if (c == '\"') context.out << "\\\"";
- else if (c == '\\') context.out << "\\\\";
- else if (c == '/') context.out << "\\/";
- else if (c == '\b') context.out << "\\b";
- else if (c == '\f') context.out << "\\f";
- else if (c == '\n') context.out << "\\n";
- else if (c == '\r') context.out << "\\r";
- else if (c == '\t') context.out << "\\t";
- else if (c == 0) context.out << "\\u0000";
- else context.out << c;
- }
- }
- else
- context.out << *string_ptr(m_Storage);
- context.out << '\"';
- break;
-
-
- case type_t::boolean:
- if (*boolean_ptr(m_Storage))
- context.out << "true";
- else
- context.out << "false";
- break;
-
- case type_t::number:
- context.out << *number_ptr(m_Storage);
- break;
-
- default:
- break;
- }
-}
-
-struct value::parser
-{
- parser(const char* begin, const char* end)
- : m_Cursor(begin)
- , m_End(end)
- {
- }
-
- value parse()
- {
- value v;
-
- // Switch to C locale to make strtod and strtol work as expected
- auto previous_locale = std::setlocale(LC_NUMERIC, "C");
-
- // Accept single value only when end of the stream is reached.
- if (!accept_element(v) || !eof())
- v = value(type_t::discarded);
-
- if (previous_locale && strcmp(previous_locale, "C") != 0)
- std::setlocale(LC_NUMERIC, previous_locale);
-
- return v;
- }
-
-private:
- struct cursor_state
- {
- cursor_state(parser* p)
- : m_Owner(p)
- , m_LastCursor(p->m_Cursor)
- {
- }
-
- void reset()
- {
- m_Owner->m_Cursor = m_LastCursor;
- }
-
- bool operator()(bool accept)
- {
- if (!accept)
- reset();
- else
- m_LastCursor = m_Owner->m_Cursor;
- return accept;
- }
-
- private:
- parser* m_Owner;
- const char* m_LastCursor;
- };
-
- cursor_state state()
- {
- return cursor_state(this);
- }
-
- bool accept_value(value& result)
- {
- return accept_object(result)
- || accept_array(result)
- || accept_string(result)
- || accept_number(result)
- || accept_boolean(result)
- || accept_null(result);
- }
-
- bool accept_object(value& result)
- {
- auto s = state();
-
- object o;
- if (s(accept('{') && accept_ws() && accept('}')))
- {
- result = o;
- return true;
- }
- else if (s(accept('{') && accept_members(o) && accept('}')))
- {
- result = std::move(o);
- return true;
- }
-
- return false;
- }
-
- bool accept_members(object& o)
- {
- if (!accept_member(o))
- return false;
-
- while (true)
- {
- auto s = state();
- if (!s(accept(',') && accept_member(o)))
- break;
- }
-
- return true;
- }
-
- bool accept_member(object& o)
- {
- auto s = state();
-
- value key;
- value v;
- if (s(accept_ws() && accept_string(key) && accept_ws() && accept(':') && accept_element(v)))
- {
- o.emplace(std::move(key.get<string>()), std::move(v));
- return true;
- }
-
- return false;
- }
-
- bool accept_array(value& result)
- {
- auto s = state();
-
- if (s(accept('[') && accept_ws() && accept(']')))
- {
- result = array();
- return true;
- }
-
- array a;
- if (s(accept('[') && accept_elements(a) && accept(']')))
- {
- result = std::move(a);
- return true;
- }
-
- return false;
- }
-
- bool accept_elements(array& a)
- {
- value v;
- if (!accept_element(v))
- return false;
-
- a.emplace_back(std::move(v));
- while (true)
- {
- auto s = state();
- v = nullptr;
- if (!s(accept(',') && accept_element(v)))
- break;
- a.emplace_back(std::move(v));
- }
-
- return true;
- }
-
- bool accept_element(value& result)
- {
- auto s = state();
- return s(accept_ws() && accept_value(result) && accept_ws());
- }
-
- bool accept_string(value& result)
- {
- auto s = state();
-
- string v;
- if (s(accept('\"') && accept_characters(v) && accept('\"')))
- {
- result = std::move(v);
- return true;
- }
- else
- return false;
- }
-
- bool accept_characters(string& result)
- {
- int c;
- while (accept_character(c))
- {
- CRUDE_ASSERT(c < 128); // #todo: convert characters > 127 to UTF-8
- result.push_back(static_cast<char>(c));
- }
-
- return true;
- }
-
- bool accept_character(int& c)
- {
- auto s = state();
-
- if (accept('\\'))
- {
- return accept_escape(c);
- }
- else if (expect('\"'))
- return false;
-
- // #todo: Handle UTF-8 sequences.
- return s((c = peek()) >= 0) && advance();
- }
-
- bool accept_escape(int& c)
- {
- if (accept('\"')) { c = '\"'; return true; }
- if (accept('\\')) { c = '\\'; return true; }
- if (accept('/')) { c = '/'; return true; }
- if (accept('b')) { c = '\b'; return true; }
- if (accept('f')) { c = '\f'; return true; }
- if (accept('n')) { c = '\n'; return true; }
- if (accept('r')) { c = '\r'; return true; }
- if (accept('t')) { c = '\t'; return true; }
-
- auto s = state();
-
- string hex;
- hex.reserve(4);
- if (s(accept('u') && accept_hex(hex) && accept_hex(hex) && accept_hex(hex) && accept_hex(hex)))
- {
- char* end = nullptr;
- auto v = std::strtol(hex.c_str(), &end, 16);
- if (end != hex.c_str() + hex.size())
- return false;
-
- c = v;
- return true;
- }
-
- return false;
- }
-
- bool accept_hex(string& result)
- {
- if (accept_digit(result))
- return true;
-
- auto c = peek();
- if ((c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
- {
- advance();
- result.push_back(static_cast<char>(c));
- return true;
- }
-
- return false;
- }
-
- bool accept_number(value& result)
- {
- auto s = state();
-
- string n;
- if (s(accept_int(n) && accept_frac(n) && accept_exp(n)))
- {
- char* end = nullptr;
- auto v = std::strtod(n.c_str(), &end);
- if (end != n.c_str() + n.size())
- return false;
-
- if (v != 0 && !std::isnormal(v))
- return false;
-
- result = v;
- return true;
- }
-
- return false;
- }
-
- bool accept_int(string& result)
- {
- auto s = state();
-
- string part;
- if (s(accept_onenine(part) && accept_digits(part)))
- {
- result += std::move(part);
- return true;
- }
-
- part.resize(0);
- if (accept_digit(part))
- {
- result += std::move(part);
- return true;
- }
-
- part.resize(0);
- if (s(accept('-') && accept_onenine(part) && accept_digits(part)))
- {
- result += '-';
- result += std::move(part);
- return true;
- }
-
- part.resize(0);
- if (s(accept('-') && accept_digit(part)))
- {
- result += '-';
- result += std::move(part);
- return true;
- }
-
- return false;
- }
-
- bool accept_digits(string& result)
- {
- string part;
- if (!accept_digit(part))
- return false;
-
- while (accept_digit(part))
- ;
-
- result += std::move(part);
-
- return true;
- }
-
- bool accept_digit(string& result)
- {
- if (accept('0'))
- {
- result.push_back('0');
- return true;
- }
- else if (accept_onenine(result))
- return true;
-
- return false;
- }
-
- bool accept_onenine(string& result)
- {
- auto c = peek();
- if (c >= '1' && c <= '9')
- {
- result.push_back(static_cast<char>(c));
- return advance();
- }
-
- return false;
- }
-
- bool accept_frac(string& result)
- {
- auto s = state();
-
- string part;
- if (s(accept('.') && accept_digits(part)))
- {
- result += '.';
- result += std::move(part);
- }
-
- return true;
- }
-
- bool accept_exp(string& result)
- {
- auto s = state();
-
- string part;
- if (s(accept('e') && accept_sign(part) && accept_digits(part)))
- {
- result += 'e';
- result += std::move(part);
- return true;
- }
- part.resize(0);
- if (s(accept('E') && accept_sign(part) && accept_digits(part)))
- {
- result += 'E';
- result += std::move(part);
- }
-
- return true;
- }
-
- bool accept_sign(string& result)
- {
- if (accept('+'))
- result.push_back('+');
- else if (accept('-'))
- result.push_back('-');
-
- return true;
- }
-
- bool accept_ws()
- {
- while (expect('\x09') || expect('\x0A') || expect('\x0D') || expect('\x20'))
- advance();
- return true;
- }
-
- bool accept_boolean(value& result)
- {
- if (accept("true"))
- {
- result = true;
- return true;
- }
- else if (accept("false"))
- {
- result = false;
- return true;
- }
-
- return false;
- }
-
- bool accept_null(value& result)
- {
- if (accept("null"))
- {
- result = nullptr;
- return true;
- }
-
- return false;
- }
-
- bool accept(char c)
- {
- if (expect(c))
- return advance();
- else
- return false;
- }
-
- bool accept(const char* str)
- {
- auto last = m_Cursor;
-
- while (*str)
- {
- if (eof() || *str != *m_Cursor)
- {
- m_Cursor = last;
- return false;
- }
-
- advance();
- ++str;
- }
-
- return true;
- }
-
- int peek() const
- {
- if (!eof())
- return *m_Cursor;
- else
- return -1;
- }
-
- bool expect(char c)
- {
- return peek() == c;
- }
-
- bool advance(int count = 1)
- {
- if (m_Cursor + count > m_End)
- {
- m_Cursor = m_End;
- return false;
- }
-
- m_Cursor += count;
-
- return true;
- }
-
- bool eof() const
- {
- return m_Cursor == m_End;
- }
-
- const char* m_Cursor;
- const char* m_End;
-};
-
-value value::parse(const string& data)
-{
- auto p = parser(data.c_str(), data.c_str() + data.size());
-
- auto v = p.parse();
-
- return v;
-}
-
-# if CRUDE_JSON_IO
-std::pair<value, bool> value::load(const string& path)
-{
- // Modern C++, so beautiful...
- std::unique_ptr<FILE, void(*)(FILE*)> file{nullptr, [](FILE* file) { if (file) fclose(file); }};
-# if defined(_MSC_VER) || (defined(__STDC_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__)
- FILE* handle = nullptr;
- if (fopen_s(&handle, path.c_str(), "rb") != 0)
- return {value{}, false};
- file.reset(handle);
-# else
- file.reset(fopen(path.c_str(), "rb"));
-# endif
-
- if (!file)
- return {value{}, false};
-
- fseek(file.get(), 0, SEEK_END);
- auto size = static_cast<size_t>(ftell(file.get()));
- fseek(file.get(), 0, SEEK_SET);
-
- string data;
- data.resize(size);
- if (fread(const_cast<char*>(data.data()), size, 1, file.get()) != 1)
- return {value{}, false};
-
- return {parse(data), true};
-}
-
-bool value::save(const string& path, const int indent, const char indent_char) const
-{
- // Modern C++, so beautiful...
- std::unique_ptr<FILE, void(*)(FILE*)> file{nullptr, [](FILE* file) { if (file) fclose(file); }};
-# if defined(_MSC_VER) || (defined(__STDC_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__)
- FILE* handle = nullptr;
- if (fopen_s(&handle, path.c_str(), "wb") != 0)
- return false;
- file.reset(handle);
-# else
- file.reset(fopen(path.c_str(), "wb"));
-# endif
-
- if (!file)
- return false;
-
- auto data = dump(indent, indent_char);
-
- if (fwrite(data.data(), data.size(), 1, file.get()) != 1)
- return false;
-
- return true;
-}
-
-# endif
-
-} // namespace crude_json
diff --git a/3rdparty/imgui-node-editor/crude_json.h b/3rdparty/imgui-node-editor/crude_json.h
deleted file mode 100644
index f1eff29..0000000
--- a/3rdparty/imgui-node-editor/crude_json.h
+++ /dev/null
@@ -1,250 +0,0 @@
-// Crude implementation of JSON value object and parser.
-//
-// VERSION 0.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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-# ifndef __CRUDE_JSON_H__
-# define __CRUDE_JSON_H__
-# pragma once
-
-# include <type_traits>
-# include <string>
-# include <vector>
-# include <map>
-# include <cstddef>
-# include <algorithm>
-# include <sstream>
-
-# ifndef CRUDE_ASSERT
-# include <cassert>
-# define CRUDE_ASSERT(expr) assert(expr)
-# endif
-
-# ifndef CRUDE_JSON_IO
-# define CRUDE_JSON_IO 1
-# endif
-
-namespace crude_json {
-
-struct value;
-
-using string = std::string;
-using object = std::map<string, value>;
-using array = std::vector<value>;
-using number = double;
-using boolean = bool;
-using null = std::nullptr_t;
-
-enum class type_t
-{
- null,
- object,
- array,
- string,
- boolean,
- number,
- discarded
-};
-
-struct value
-{
- value(type_t type = type_t::null): m_Type(construct(m_Storage, type)) {}
- value(value&& other);
- value(const value& other);
-
- value( null) : m_Type(construct(m_Storage, null())) {}
- value( object&& v): m_Type(construct(m_Storage, std::move(v))) {}
- value(const object& v): m_Type(construct(m_Storage, v)) {}
- value( array&& v): m_Type(construct(m_Storage, std::move(v))) {}
- value(const array& v): m_Type(construct(m_Storage, v)) {}
- value( string&& v): m_Type(construct(m_Storage, std::move(v))) {}
- value(const string& v): m_Type(construct(m_Storage, v)) {}
- value(const char* v): m_Type(construct(m_Storage, v)) {}
- value( boolean v): m_Type(construct(m_Storage, v)) {}
- value( number v): m_Type(construct(m_Storage, v)) {}
- ~value() { destruct(m_Storage, m_Type); }
-
- value& operator=(value&& other) { if (this != &other) { value(std::move(other)).swap(*this); } return *this; }
- value& operator=(const value& other) { if (this != &other) { value( other).swap(*this); } return *this; }
-
- value& operator=( null) { auto other = value( ); swap(other); return *this; }
- value& operator=( object&& v) { auto other = value(std::move(v)); swap(other); return *this; }
- value& operator=(const object& v) { auto other = value( v); swap(other); return *this; }
- value& operator=( array&& v) { auto other = value(std::move(v)); swap(other); return *this; }
- value& operator=(const array& v) { auto other = value( v); swap(other); return *this; }
- value& operator=( string&& v) { auto other = value(std::move(v)); swap(other); return *this; }
- value& operator=(const string& v) { auto other = value( v); swap(other); return *this; }
- value& operator=(const char* v) { auto other = value( v); swap(other); return *this; }
- value& operator=( boolean v) { auto other = value( v); swap(other); return *this; }
- value& operator=( number v) { auto other = value( v); swap(other); return *this; }
-
- type_t type() const { return m_Type; }
-
- operator type_t() const { return m_Type; }
-
- value& operator[](size_t index);
- const value& operator[](size_t index) const;
- value& operator[](const string& key);
- const value& operator[](const string& key) const;
-
- bool contains(const string& key) const;
-
- void push_back(const value& value);
- void push_back(value&& value);
-
- size_t erase(const string& key);
-
- bool is_primitive() const { return is_string() || is_number() || is_boolean() || is_null(); }
- bool is_structured() const { return is_object() || is_array(); }
- bool is_null() const { return m_Type == type_t::null; }
- bool is_object() const { return m_Type == type_t::object; }
- bool is_array() const { return m_Type == type_t::array; }
- bool is_string() const { return m_Type == type_t::string; }
- bool is_boolean() const { return m_Type == type_t::boolean; }
- bool is_number() const { return m_Type == type_t::number; }
- bool is_discarded() const { return m_Type == type_t::discarded; }
-
- template <typename T> const T& get() const;
- template <typename T> T& get();
-
- template <typename T> const T* get_ptr() const;
- template <typename T> T* get_ptr();
-
- string dump(const int indent = -1, const char indent_char = ' ') const;
-
- void swap(value& other);
-
- inline friend void swap(value& lhs, value& rhs) { lhs.swap(rhs); }
-
- // Returns discarded value for invalid inputs.
- static value parse(const string& data);
-
-# if CRUDE_JSON_IO
- static std::pair<value, bool> load(const string& path);
- bool save(const string& path, const int indent = -1, const char indent_char = ' ') const;
-# endif
-
-private:
- struct parser;
-
- // VS2015: std::max() is not constexpr yet.
-# define CRUDE_MAX2(a, b) ((a) < (b) ? (b) : (a))
-# define CRUDE_MAX3(a, b, c) CRUDE_MAX2(CRUDE_MAX2(a, b), c)
-# define CRUDE_MAX4(a, b, c, d) CRUDE_MAX2(CRUDE_MAX3(a, b, c), d)
-# define CRUDE_MAX5(a, b, c, d, e) CRUDE_MAX2(CRUDE_MAX4(a, b, c, d), e)
- enum
- {
- max_size = CRUDE_MAX5( sizeof(string), sizeof(object), sizeof(array), sizeof(number), sizeof(boolean)),
- max_align = CRUDE_MAX5(alignof(string), alignof(object), alignof(array), alignof(number), alignof(boolean))
- };
-# undef CRUDE_MAX5
-# undef CRUDE_MAX4
-# undef CRUDE_MAX3
-# undef CRUDE_MAX2
- using storage_t = std::aligned_storage<max_size, max_align>::type;
-
- static object* object_ptr( storage_t& storage) { return reinterpret_cast< object*>(&storage); }
- static const object* object_ptr(const storage_t& storage) { return reinterpret_cast<const object*>(&storage); }
- static array* array_ptr( storage_t& storage) { return reinterpret_cast< array*>(&storage); }
- static const array* array_ptr(const storage_t& storage) { return reinterpret_cast<const array*>(&storage); }
- static string* string_ptr( storage_t& storage) { return reinterpret_cast< string*>(&storage); }
- static const string* string_ptr(const storage_t& storage) { return reinterpret_cast<const string*>(&storage); }
- static boolean* boolean_ptr( storage_t& storage) { return reinterpret_cast< boolean*>(&storage); }
- static const boolean* boolean_ptr(const storage_t& storage) { return reinterpret_cast<const boolean*>(&storage); }
- static number* number_ptr( storage_t& storage) { return reinterpret_cast< number*>(&storage); }
- static const number* number_ptr(const storage_t& storage) { return reinterpret_cast<const number*>(&storage); }
-
- static type_t construct(storage_t& storage, type_t type)
- {
- switch (type)
- {
- case type_t::object: new (&storage) object(); break;
- case type_t::array: new (&storage) array(); break;
- case type_t::string: new (&storage) string(); break;
- case type_t::boolean: new (&storage) boolean(); break;
- case type_t::number: new (&storage) number(); break;
- default: break;
- }
-
- return type;
- }
-
- static type_t construct(storage_t& storage, null) { (void)storage; return type_t::null; }
- static type_t construct(storage_t& storage, object&& value) { new (&storage) object(std::forward<object>(value)); return type_t::object; }
- static type_t construct(storage_t& storage, const object& value) { new (&storage) object(value); return type_t::object; }
- static type_t construct(storage_t& storage, array&& value) { new (&storage) array(std::forward<array>(value)); return type_t::array; }
- static type_t construct(storage_t& storage, const array& value) { new (&storage) array(value); return type_t::array; }
- static type_t construct(storage_t& storage, string&& value) { new (&storage) string(std::forward<string>(value)); return type_t::string; }
- static type_t construct(storage_t& storage, const string& value) { new (&storage) string(value); return type_t::string; }
- static type_t construct(storage_t& storage, const char* value) { new (&storage) string(value); return type_t::string; }
- static type_t construct(storage_t& storage, boolean value) { new (&storage) boolean(value); return type_t::boolean; }
- static type_t construct(storage_t& storage, number value) { new (&storage) number(value); return type_t::number; }
-
- static void destruct(storage_t& storage, type_t type)
- {
- switch (type)
- {
- case type_t::object: object_ptr(storage)->~object(); break;
- case type_t::array: array_ptr(storage)->~array(); break;
- case type_t::string: string_ptr(storage)->~string(); break;
- default: break;
- }
- }
-
- struct dump_context_t
- {
- std::ostringstream out;
- const int indent = -1;
- const char indent_char = ' ';
-
- // VS2015: Aggregate initialization isn't a thing yet.
- dump_context_t(const int indent, const char indent_char)
- : indent(indent)
- , indent_char(indent_char)
- {
- }
-
- void write_indent(int level);
- void write_separator();
- void write_newline();
- };
-
- void dump(dump_context_t& context, int level) const;
-
- storage_t m_Storage;
- type_t m_Type;
-};
-
-template <> inline const object& value::get<object>() const { CRUDE_ASSERT(m_Type == type_t::object); return *object_ptr(m_Storage); }
-template <> inline const array& value::get<array>() const { CRUDE_ASSERT(m_Type == type_t::array); return *array_ptr(m_Storage); }
-template <> inline const string& value::get<string>() const { CRUDE_ASSERT(m_Type == type_t::string); return *string_ptr(m_Storage); }
-template <> inline const boolean& value::get<boolean>() const { CRUDE_ASSERT(m_Type == type_t::boolean); return *boolean_ptr(m_Storage); }
-template <> inline const number& value::get<number>() const { CRUDE_ASSERT(m_Type == type_t::number); return *number_ptr(m_Storage); }
-
-template <> inline object& value::get<object>() { CRUDE_ASSERT(m_Type == type_t::object); return *object_ptr(m_Storage); }
-template <> inline array& value::get<array>() { CRUDE_ASSERT(m_Type == type_t::array); return *array_ptr(m_Storage); }
-template <> inline string& value::get<string>() { CRUDE_ASSERT(m_Type == type_t::string); return *string_ptr(m_Storage); }
-template <> inline boolean& value::get<boolean>() { CRUDE_ASSERT(m_Type == type_t::boolean); return *boolean_ptr(m_Storage); }
-template <> inline number& value::get<number>() { CRUDE_ASSERT(m_Type == type_t::number); return *number_ptr(m_Storage); }
-
-template <> inline const object* value::get_ptr<object>() const { if (m_Type == type_t::object) return object_ptr(m_Storage); else return nullptr; }
-template <> inline const array* value::get_ptr<array>() const { if (m_Type == type_t::array) return array_ptr(m_Storage); else return nullptr; }
-template <> inline const string* value::get_ptr<string>() const { if (m_Type == type_t::string) return string_ptr(m_Storage); else return nullptr; }
-template <> inline const boolean* value::get_ptr<boolean>() const { if (m_Type == type_t::boolean) return boolean_ptr(m_Storage); else return nullptr; }
-template <> inline const number* value::get_ptr<number>() const { if (m_Type == type_t::number) return number_ptr(m_Storage); else return nullptr; }
-
-template <> inline object* value::get_ptr<object>() { if (m_Type == type_t::object) return object_ptr(m_Storage); else return nullptr; }
-template <> inline array* value::get_ptr<array>() { if (m_Type == type_t::array) return array_ptr(m_Storage); else return nullptr; }
-template <> inline string* value::get_ptr<string>() { if (m_Type == type_t::string) return string_ptr(m_Storage); else return nullptr; }
-template <> inline boolean* value::get_ptr<boolean>() { if (m_Type == type_t::boolean) return boolean_ptr(m_Storage); else return nullptr; }
-template <> inline number* value::get_ptr<number>() { if (m_Type == type_t::number) return number_ptr(m_Storage); else return nullptr; }
-
-} // namespace crude_json
-
-# endif // __CRUDE_JSON_H__ \ No newline at end of file
diff --git a/3rdparty/imgui-node-editor/imgui_bezier_math.h b/3rdparty/imgui-node-editor/imgui_bezier_math.h
deleted file mode 100644
index 85ead39..0000000
--- a/3rdparty/imgui-node-editor/imgui_bezier_math.h
+++ /dev/null
@@ -1,144 +0,0 @@
-//------------------------------------------------------------------------------
-// VERSION 0.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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-//------------------------------------------------------------------------------
-# ifndef __IMGUI_BEZIER_MATH_H__
-# define __IMGUI_BEZIER_MATH_H__
-# pragma once
-
-
-//------------------------------------------------------------------------------
-# include "imgui_extra_math.h"
-
-
-//------------------------------------------------------------------------------
-template <typename T>
-struct ImCubicBezierPointsT
-{
- T P0;
- T P1;
- T P2;
- T P3;
-};
-using ImCubicBezierPoints = ImCubicBezierPointsT<ImVec2>;
-
-
-//------------------------------------------------------------------------------
-// Low-level Bezier curve sampling.
-template <typename T> inline T ImLinearBezier(const T& p0, const T& p1, float t);
-template <typename T> inline T ImLinearBezierDt(const T& p0, const T& p1, float t);
-template <typename T> inline T ImQuadraticBezier(const T& p0, const T& p1, const T& p2, float t);
-template <typename T> inline T ImQuadraticBezierDt(const T& p0, const T& p1, const T& p2, float t);
-template <typename T> inline T ImCubicBezier(const T& p0, const T& p1, const T& p2, const T& p3, float t);
-template <typename T> inline T ImCubicBezierDt(const T& p0, const T& p1, const T& p2, const T& p3, float t);
-
-
-// High-level Bezier sampling, automatically collapse to lower level Bezier curves if control points overlap.
-template <typename T> inline T ImCubicBezierSample(const T& p0, const T& p1, const T& p2, const T& p3, float t);
-template <typename T> inline T ImCubicBezierSample(const ImCubicBezierPointsT<T>& curve, float t);
-template <typename T> inline T ImCubicBezierTangent(const T& p0, const T& p1, const T& p2, const T& p3, float t);
-template <typename T> inline T ImCubicBezierTangent(const ImCubicBezierPointsT<T>& curve, float t);
-
-
-// Calculate approximate length of Cubic Bezier curve.
-template <typename T> inline float ImCubicBezierLength(const T& p0, const T& p1, const T& p2, const T& p3);
-template <typename T> inline float ImCubicBezierLength(const ImCubicBezierPointsT<T>& curve);
-
-
-// Splits Cubic Bezier curve into two curves.
-template <typename T>
-struct ImCubicBezierSplitResultT
-{
- ImCubicBezierPointsT<T> Left;
- ImCubicBezierPointsT<T> Right;
-};
-using ImCubicBezierSplitResult = ImCubicBezierSplitResultT<ImVec2>;
-
-template <typename T> inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const T& p0, const T& p1, const T& p2, const T& p3, float t);
-template <typename T> inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const ImCubicBezierPointsT<T>& curve, float t);
-
-
-// Returns bounding rectangle of Cubic Bezier curve.
-inline ImRect ImCubicBezierBoundingRect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3);
-inline ImRect ImCubicBezierBoundingRect(const ImCubicBezierPoints& curve);
-
-
-// Project point on Cubic Bezier curve.
-struct ImProjectResult
-{
- ImVec2 Point; // Point on curve
- float Time; // [0 - 1]
- float Distance; // Distance to curve
-};
-
-inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const int subdivisions = 100);
-inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImCubicBezierPoints& curve, const int subdivisions = 100);
-
-
-// Calculate intersection between line and a Cubic Bezier curve.
-struct ImCubicBezierIntersectResult
-{
- int Count;
- ImVec2 Points[3];
-};
-
-inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& a0, const ImVec2& a1);
-inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImCubicBezierPoints& curve, const ImLine& line);
-
-
-// Adaptive Cubic Bezier subdivision.
-enum ImCubicBezierSubdivideFlags
-{
- ImCubicBezierSubdivide_None = 0,
- ImCubicBezierSubdivide_SkipFirst = 1
-};
-
-struct ImCubicBezierSubdivideSample
-{
- ImVec2 Point;
- ImVec2 Tangent;
-};
-
-using ImCubicBezierSubdivideCallback = void (*)(const ImCubicBezierSubdivideSample& p, void* user_pointer);
-
-inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
-inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
-
-
-// F has signature void(const ImCubicBezierSubdivideSample& p)
-template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
-template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImCubicBezierPoints& curve, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
-
-// Fixed step Cubic Bezier subdivision.
-struct ImCubicBezierFixedStepSample
-{
- float T;
- float Length;
- ImVec2 Point;
- bool BreakSearch;
-};
-
-using ImCubicBezierFixedStepCallback = void (*)(ImCubicBezierFixedStepSample& sample, void* user_pointer);
-
-inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
-inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
-
-
-// F has signature void(const ImCubicBezierFixedStepSample& p)
-template <typename F> inline void ImCubicBezierFixedStep(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
-template <typename F> inline void ImCubicBezierFixedStep(F& callback, const ImCubicBezierPoints& curve, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
-
-
-//------------------------------------------------------------------------------
-# include "imgui_bezier_math.inl"
-
-
-//------------------------------------------------------------------------------
-# endif // __IMGUI_BEZIER_MATH_H__
diff --git a/3rdparty/imgui-node-editor/imgui_bezier_math.inl b/3rdparty/imgui-node-editor/imgui_bezier_math.inl
deleted file mode 100644
index 3020bdb..0000000
--- a/3rdparty/imgui-node-editor/imgui_bezier_math.inl
+++ /dev/null
@@ -1,675 +0,0 @@
-//------------------------------------------------------------------------------
-// VERSION 0.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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-//------------------------------------------------------------------------------
-# ifndef __IMGUI_BEZIER_MATH_INL__
-# define __IMGUI_BEZIER_MATH_INL__
-# pragma once
-
-
-//------------------------------------------------------------------------------
-# include "imgui_bezier_math.h"
-# include <map> // used in ImCubicBezierFixedStep
-
-
-//------------------------------------------------------------------------------
-template <typename T>
-inline T ImLinearBezier(const T& p0, const T& p1, float t)
-{
- return p0 + t * (p1 - p0);
-}
-
-template <typename T>
-inline T ImLinearBezierDt(const T& p0, const T& p1, float t)
-{
- IM_UNUSED(t);
-
- return p1 - p0;
-}
-
-template <typename T>
-inline T ImQuadraticBezier(const T& p0, const T& p1, const T& p2, float t)
-{
- const auto a = 1 - t;
-
- return a * a * p0 + 2 * t * a * p1 + t * t * p2;
-}
-
-template <typename T>
-inline T ImQuadraticBezierDt(const T& p0, const T& p1, const T& p2, float t)
-{
- return 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1);
-}
-
-template <typename T>
-inline T ImCubicBezier(const T& p0, const T& p1, const T& p2, const T& p3, float t)
-{
- const auto a = 1 - t;
- const auto b = a * a * a;
- const auto c = t * t * t;
-
- return b * p0 + 3 * t * a * a * p1 + 3 * t * t * a * p2 + c * p3;
-}
-
-template <typename T>
-inline T ImCubicBezierDt(const T& p0, const T& p1, const T& p2, const T& p3, float t)
-{
- const auto a = 1 - t;
- const auto b = a * a;
- const auto c = t * t;
- const auto d = 2 * t * a;
-
- return -3 * p0 * b + 3 * p1 * (b - d) + 3 * p2 * (d - c) + 3 * p3 * c;
-}
-
-template <typename T>
-inline T ImCubicBezierSample(const T& p0, const T& p1, const T& p2, const T& p3, float t)
-{
- const auto cp0_zero = ImLengthSqr(p1 - p0) < 1e-5f;
- const auto cp1_zero = ImLengthSqr(p3 - p2) < 1e-5f;
-
- if (cp0_zero && cp1_zero)
- return ImLinearBezier(p0, p3, t);
- else if (cp0_zero)
- return ImQuadraticBezier(p0, p2, p3, t);
- else if (cp1_zero)
- return ImQuadraticBezier(p0, p1, p3, t);
- else
- return ImCubicBezier(p0, p1, p2, p3, t);
-}
-
-template <typename T>
-inline T ImCubicBezierSample(const ImCubicBezierPointsT<T>& curve, float t)
-{
- return ImCubicBezierSample(curve.P0, curve.P1, curve.P2, curve.P3, t);
-}
-
-template <typename T>
-inline T ImCubicBezierTangent(const T& p0, const T& p1, const T& p2, const T& p3, float t)
-{
- const auto cp0_zero = ImLengthSqr(p1 - p0) < 1e-5f;
- const auto cp1_zero = ImLengthSqr(p3 - p2) < 1e-5f;
-
- if (cp0_zero && cp1_zero)
- return ImLinearBezierDt(p0, p3, t);
- else if (cp0_zero)
- return ImQuadraticBezierDt(p0, p2, p3, t);
- else if (cp1_zero)
- return ImQuadraticBezierDt(p0, p1, p3, t);
- else
- return ImCubicBezierDt(p0, p1, p2, p3, t);
-}
-
-template <typename T>
-inline T ImCubicBezierTangent(const ImCubicBezierPointsT<T>& curve, float t)
-{
- return ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, t);
-}
-
-template <typename T>
-inline float ImCubicBezierLength(const T& p0, const T& p1, const T& p2, const T& p3)
-{
- // Legendre-Gauss abscissae with n=24 (x_i values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x))
- static const float t_values[] =
- {
- -0.0640568928626056260850430826247450385909f,
- 0.0640568928626056260850430826247450385909f,
- -0.1911188674736163091586398207570696318404f,
- 0.1911188674736163091586398207570696318404f,
- -0.3150426796961633743867932913198102407864f,
- 0.3150426796961633743867932913198102407864f,
- -0.4337935076260451384870842319133497124524f,
- 0.4337935076260451384870842319133497124524f,
- -0.5454214713888395356583756172183723700107f,
- 0.5454214713888395356583756172183723700107f,
- -0.6480936519369755692524957869107476266696f,
- 0.6480936519369755692524957869107476266696f,
- -0.7401241915785543642438281030999784255232f,
- 0.7401241915785543642438281030999784255232f,
- -0.8200019859739029219539498726697452080761f,
- 0.8200019859739029219539498726697452080761f,
- -0.8864155270044010342131543419821967550873f,
- 0.8864155270044010342131543419821967550873f,
- -0.9382745520027327585236490017087214496548f,
- 0.9382745520027327585236490017087214496548f,
- -0.9747285559713094981983919930081690617411f,
- 0.9747285559713094981983919930081690617411f,
- -0.9951872199970213601799974097007368118745f,
- 0.9951872199970213601799974097007368118745f
- };
-
- // Legendre-Gauss weights with n=24 (w_i values, defined by a function linked to in the Bezier primer article)
- static const float c_values[] =
- {
- 0.1279381953467521569740561652246953718517f,
- 0.1279381953467521569740561652246953718517f,
- 0.1258374563468282961213753825111836887264f,
- 0.1258374563468282961213753825111836887264f,
- 0.1216704729278033912044631534762624256070f,
- 0.1216704729278033912044631534762624256070f,
- 0.1155056680537256013533444839067835598622f,
- 0.1155056680537256013533444839067835598622f,
- 0.1074442701159656347825773424466062227946f,
- 0.1074442701159656347825773424466062227946f,
- 0.0976186521041138882698806644642471544279f,
- 0.0976186521041138882698806644642471544279f,
- 0.0861901615319532759171852029837426671850f,
- 0.0861901615319532759171852029837426671850f,
- 0.0733464814110803057340336152531165181193f,
- 0.0733464814110803057340336152531165181193f,
- 0.0592985849154367807463677585001085845412f,
- 0.0592985849154367807463677585001085845412f,
- 0.0442774388174198061686027482113382288593f,
- 0.0442774388174198061686027482113382288593f,
- 0.0285313886289336631813078159518782864491f,
- 0.0285313886289336631813078159518782864491f,
- 0.0123412297999871995468056670700372915759f,
- 0.0123412297999871995468056670700372915759f
- };
-
- static_assert(sizeof(t_values) / sizeof(*t_values) == sizeof(c_values) / sizeof(*c_values), "");
-
- auto arc = [p0, p1, p2, p3](float t)
- {
- const auto p = ImCubicBezierDt(p0, p1, p2, p3, t);
- const auto l = ImLength(p);
- return l;
- };
-
- const auto z = 0.5f;
- const auto n = sizeof(t_values) / sizeof(*t_values);
-
- auto accumulator = 0.0f;
- for (size_t i = 0; i < n; ++i)
- {
- const auto t = z * t_values[i] + z;
- accumulator += c_values[i] * arc(t);
- }
-
- return z * accumulator;
-}
-
-template <typename T>
-inline float ImCubicBezierLength(const ImCubicBezierPointsT<T>& curve)
-{
- return ImCubicBezierLength(curve.P0, curve.P1, curve.P2, curve.P3);
-}
-
-template <typename T>
-inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const T& p0, const T& p1, const T& p2, const T& p3, float t)
-{
- const auto z1 = t;
- const auto z2 = z1 * z1;
- const auto z3 = z1 * z1 * z1;
- const auto s1 = z1 - 1;
- const auto s2 = s1 * s1;
- const auto s3 = s1 * s1 * s1;
-
- return ImCubicBezierSplitResultT<T>
- {
- ImCubicBezierPointsT<T>
- {
- p0,
- z1 * p1 - s1 * p0,
- z2 * p2 - 2 * z1 * s1 * p1 + s2 * p0,
- z3 * p3 - 3 * z2 * s1 * p2 + 3 * z1 * s2 * p1 - s3 * p0
- },
- ImCubicBezierPointsT<T>
- {
- z3 * p0 - 3 * z2 * s1 * p1 + 3 * z1 * s2 * p2 - s3 * p3,
- z2 * p1 - 2 * z1 * s1 * p2 + s2 * p3,
- z1 * p2 - s1 * p3,
- p3,
- }
- };
-}
-
-template <typename T>
-inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const ImCubicBezierPointsT<T>& curve, float t)
-{
- return ImCubicBezierSplit(curve.P0, curve.P1, curve.P2, curve.P3, t);
-}
-
-inline ImRect ImCubicBezierBoundingRect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3)
-{
- auto a = 3 * p3 - 9 * p2 + 9 * p1 - 3 * p0;
- auto b = 6 * p0 - 12 * p1 + 6 * p2;
- auto c = 3 * p1 - 3 * p0;
- auto delta_squared = ImMul(b, b) - 4 * ImMul(a, c);
-
- auto tl = ImMin(p0, p3);
- auto rb = ImMax(p0, p3);
-
-# define IM_VEC2_INDEX(v, i) *(&v.x + i)
-
- for (int i = 0; i < 2; ++i)
- {
- if (IM_VEC2_INDEX(a, i) == 0.0f)
- continue;
-
- if (IM_VEC2_INDEX(delta_squared, i) >= 0)
- {
- auto delta = ImSqrt(IM_VEC2_INDEX(delta_squared, i));
-
- auto t0 = (-IM_VEC2_INDEX(b, i) + delta) / (2 * IM_VEC2_INDEX(a, i));
- if (t0 > 0 && t0 < 1)
- {
- auto p = ImCubicBezier(IM_VEC2_INDEX(p0, i), IM_VEC2_INDEX(p1, i), IM_VEC2_INDEX(p2, i), IM_VEC2_INDEX(p3, i), t0);
- IM_VEC2_INDEX(tl, i) = ImMin(IM_VEC2_INDEX(tl, i), p);
- IM_VEC2_INDEX(rb, i) = ImMax(IM_VEC2_INDEX(rb, i), p);
- }
-
- auto t1 = (-IM_VEC2_INDEX(b, i) - delta) / (2 * IM_VEC2_INDEX(a, i));
- if (t1 > 0 && t1 < 1)
- {
- auto p = ImCubicBezier(IM_VEC2_INDEX(p0, i), IM_VEC2_INDEX(p1, i), IM_VEC2_INDEX(p2, i), IM_VEC2_INDEX(p3, i), t1);
- IM_VEC2_INDEX(tl, i) = ImMin(IM_VEC2_INDEX(tl, i), p);
- IM_VEC2_INDEX(rb, i) = ImMax(IM_VEC2_INDEX(rb, i), p);
- }
- }
- }
-
-# undef IM_VEC2_INDEX
-
- return ImRect(tl, rb);
-}
-
-inline ImRect ImCubicBezierBoundingRect(const ImCubicBezierPoints& curve)
-{
- return ImCubicBezierBoundingRect(curve.P0, curve.P1, curve.P2, curve.P3);
-}
-
-inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& point, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const int subdivisions)
-{
- // http://pomax.github.io/bezierinfo/#projections
-
- const float epsilon = 1e-5f;
- const float fixed_step = 1.0f / static_cast<float>(subdivisions - 1);
-
- ImProjectResult result;
- result.Point = point;
- result.Time = 0.0f;
- result.Distance = FLT_MAX;
-
- // Step 1: Coarse check
- for (int i = 0; i < subdivisions; ++i)
- {
- auto t = i * fixed_step;
- auto p = ImCubicBezier(p0, p1, p2, p3, t);
- auto s = point - p;
- auto d = ImDot(s, s);
-
- if (d < result.Distance)
- {
- result.Point = p;
- result.Time = t;
- result.Distance = d;
- }
- }
-
- if (result.Time == 0.0f || ImFabs(result.Time - 1.0f) <= epsilon)
- {
- result.Distance = ImSqrt(result.Distance);
- return result;
- }
-
- // Step 2: Fine check
- auto left = result.Time - fixed_step;
- auto right = result.Time + fixed_step;
- auto step = fixed_step * 0.1f;
-
- for (auto t = left; t < right + step; t += step)
- {
- auto p = ImCubicBezier(p0, p1, p2, p3, t);
- auto s = point - p;
- auto d = ImDot(s, s);
-
- if (d < result.Distance)
- {
- result.Point = p;
- result.Time = t;
- result.Distance = d;
- }
- }
-
- result.Distance = ImSqrt(result.Distance);
-
- return result;
-}
-
-inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImCubicBezierPoints& curve, const int subdivisions)
-{
- return ImProjectOnCubicBezier(p, curve.P0, curve.P1, curve.P2, curve.P3, subdivisions);
-}
-
-inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& a0, const ImVec2& a1)
-{
- auto cubic_roots = [](float a, float b, float c, float d, float* roots) -> int
- {
- int count = 0;
-
- auto sign = [](float x) -> float { return x < 0 ? -1.0f : 1.0f; };
-
- auto A = b / a;
- auto B = c / a;
- auto C = d / a;
-
- auto Q = (3 * B - ImPow(A, 2)) / 9;
- auto R = (9 * A * B - 27 * C - 2 * ImPow(A, 3)) / 54;
- auto D = ImPow(Q, 3) + ImPow(R, 2); // polynomial discriminant
-
- if (D >= 0) // complex or duplicate roots
- {
- auto S = sign(R + ImSqrt(D)) * ImPow(ImFabs(R + ImSqrt(D)), (1.0f / 3.0f));
- auto T = sign(R - ImSqrt(D)) * ImPow(ImFabs(R - ImSqrt(D)), (1.0f / 3.0f));
-
- roots[0] = -A / 3 + (S + T); // real root
- roots[1] = -A / 3 - (S + T) / 2; // real part of complex root
- roots[2] = -A / 3 - (S + T) / 2; // real part of complex root
- auto Im = ImFabs(ImSqrt(3) * (S - T) / 2); // complex part of root pair
-
- // discard complex roots
- if (Im != 0)
- count = 1;
- else
- count = 3;
- }
- else // distinct real roots
- {
- auto th = ImAcos(R / ImSqrt(-ImPow(Q, 3)));
-
- roots[0] = 2 * ImSqrt(-Q) * ImCos(th / 3) - A / 3;
- roots[1] = 2 * ImSqrt(-Q) * ImCos((th + 2 * IM_PI) / 3) - A / 3;
- roots[2] = 2 * ImSqrt(-Q) * ImCos((th + 4 * IM_PI) / 3) - A / 3;
-
- count = 3;
- }
-
- return count;
- };
-
- // https://github.com/kaishiqi/Geometric-Bezier/blob/master/GeometricBezier/src/kaishiqi/geometric/intersection/Intersection.as
- //
- // Start with Bezier using Bernstein polynomials for weighting functions:
- // (1-t^3)P0 + 3t(1-t)^2P1 + 3t^2(1-t)P2 + t^3P3
- //
- // Expand and collect terms to form linear combinations of original Bezier
- // controls. This ends up with a vector cubic in t:
- // (-P0+3P1-3P2+P3)t^3 + (3P0-6P1+3P2)t^2 + (-3P0+3P1)t + P0
- // /\ /\ /\ /\
- // || || || ||
- // c3 c2 c1 c0
-
- // Calculate the coefficients
- auto c3 = -p0 + 3 * p1 - 3 * p2 + p3;
- auto c2 = 3 * p0 - 6 * p1 + 3 * p2;
- auto c1 = -3 * p0 + 3 * p1;
- auto c0 = p0;
-
- // Convert line to normal form: ax + by + c = 0
- auto a = a1.y - a0.y;
- auto b = a0.x - a1.x;
- auto c = a0.x * (a0.y - a1.y) + a0.y * (a1.x - a0.x);
-
- // Rotate each cubic coefficient using line for new coordinate system?
- // Find roots of rotated cubic
- float roots[3];
- auto rootCount = cubic_roots(
- a * c3.x + b * c3.y,
- a * c2.x + b * c2.y,
- a * c1.x + b * c1.y,
- a * c0.x + b * c0.y + c,
- roots);
-
- // Any roots in closed interval [0,1] are intersections on Bezier, but
- // might not be on the line segment.
- // Find intersections and calculate point coordinates
-
- auto min = ImMin(a0, a1);
- auto max = ImMax(a0, a1);
-
- ImCubicBezierIntersectResult result;
- auto points = result.Points;
-
- for (int i = 0; i < rootCount; ++i)
- {
- auto root = roots[i];
-
- if (0 <= root && root <= 1)
- {
- // We're within the Bezier curve
- // Find point on Bezier
- auto p = ImCubicBezier(p0, p1, p2, p3, root);
-
- // See if point is on line segment
- // Had to make special cases for vertical and horizontal lines due
- // to slight errors in calculation of p00
- if (a0.x == a1.x)
- {
- if (min.y <= p.y && p.y <= max.y)
- *points++ = p;
- }
- else if (a0.y == a1.y)
- {
- if (min.x <= p.x && p.x <= max.x)
- *points++ = p;
- }
- else if (p.x >= min.x && p.y >= min.y && p.x <= max.x && p.y <= max.y)
- {
- *points++ = p;
- }
- }
- }
-
- result.Count = static_cast<int>(points - result.Points);
-
- return result;
-}
-
-inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImCubicBezierPoints& curve, const ImLine& line)
-{
- return ImCubicBezierLineIntersect(curve.P0, curve.P1, curve.P2, curve.P3, line.A, line.B);
-}
-
-inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol, ImCubicBezierSubdivideFlags flags)
-{
- return ImCubicBezierSubdivide(callback, user_pointer, ImCubicBezierPoints{ p0, p1, p2, p3 }, tess_tol, flags);
-}
-
-inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float tess_tol, ImCubicBezierSubdivideFlags flags)
-{
- struct Tesselator
- {
- ImCubicBezierSubdivideCallback Callback;
- void* UserPointer;
- float TesselationTollerance;
- ImCubicBezierSubdivideFlags Flags;
-
- void Commit(const ImVec2& p, const ImVec2& t)
- {
- ImCubicBezierSubdivideSample sample;
- sample.Point = p;
- sample.Tangent = t;
- Callback(sample, UserPointer);
- }
-
- void Subdivide(const ImCubicBezierPoints& curve, int level = 0)
- {
- float dx = curve.P3.x - curve.P0.x;
- float dy = curve.P3.y - curve.P0.y;
- float d2 = ((curve.P1.x - curve.P3.x) * dy - (curve.P1.y - curve.P3.y) * dx);
- float d3 = ((curve.P2.x - curve.P3.x) * dy - (curve.P2.y - curve.P3.y) * dx);
- d2 = (d2 >= 0) ? d2 : -d2;
- d3 = (d3 >= 0) ? d3 : -d3;
- if ((d2 + d3) * (d2 + d3) < TesselationTollerance * (dx * dx + dy * dy))
- {
- Commit(curve.P3, ImCubicBezierTangent(curve, 1.0f));
- }
- else if (level < 10)
- {
- const auto p12 = (curve.P0 + curve.P1) * 0.5f;
- const auto p23 = (curve.P1 + curve.P2) * 0.5f;
- const auto p34 = (curve.P2 + curve.P3) * 0.5f;
- const auto p123 = (p12 + p23) * 0.5f;
- const auto p234 = (p23 + p34) * 0.5f;
- const auto p1234 = (p123 + p234) * 0.5f;
-
- Subdivide(ImCubicBezierPoints { curve.P0, p12, p123, p1234 }, level + 1);
- Subdivide(ImCubicBezierPoints { p1234, p234, p34, curve.P3 }, level + 1);
- }
- }
- };
-
- if (tess_tol < 0)
- tess_tol = 1.118f; // sqrtf(1.25f)
-
- Tesselator tesselator;
- tesselator.Callback = callback;
- tesselator.UserPointer = user_pointer;
- tesselator.TesselationTollerance = tess_tol * tess_tol;
- tesselator.Flags = flags;
-
- if (!(tesselator.Flags & ImCubicBezierSubdivide_SkipFirst))
- tesselator.Commit(curve.P0, ImCubicBezierTangent(curve, 0.0f));
-
- tesselator.Subdivide(curve, 0);
-}
-
-template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol, ImCubicBezierSubdivideFlags flags)
-{
- auto handler = [](const ImCubicBezierSubdivideSample& p, void* user_pointer)
- {
- auto& callback = *reinterpret_cast<F*>(user_pointer);
- callback(p);
- };
-
- ImCubicBezierSubdivide(handler, &callback, ImCubicBezierPoints{ p0, p1, p2, p3 }, tess_tol, flags);
-}
-
-template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImCubicBezierPoints& curve, float tess_tol, ImCubicBezierSubdivideFlags flags)
-{
- auto handler = [](const ImCubicBezierSubdivideSample& p, void* user_pointer)
- {
- auto& callback = *reinterpret_cast<F*>(user_pointer);
- callback(p);
- };
-
- ImCubicBezierSubdivide(handler, &callback, curve, tess_tol, flags);
-}
-
-inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot, float max_value_error, float max_t_error)
-{
- if (step <= 0.0f || !callback || max_value_error <= 0 || max_t_error <= 0)
- return;
-
- ImCubicBezierFixedStepSample sample;
- sample.T = 0.0f;
- sample.Length = 0.0f;
- sample.Point = p0;
- sample.BreakSearch = false;
-
- callback(sample, user_pointer);
- if (sample.BreakSearch)
- return;
-
- const auto total_length = ImCubicBezierLength(p0, p1, p2, p3);
- const auto point_count = static_cast<int>(total_length / step) + (overshoot ? 2 : 1);
- const auto t_min = 0.0f;
- const auto t_max = step * point_count / total_length;
- const auto t_0 = (t_min + t_max) * 0.5f;
-
- // #todo: replace map with ImVector + binary search
- std::map<float, float> cache;
- for (int point_index = 1; point_index < point_count; ++point_index)
- {
- const auto targetLength = point_index * step;
-
- float t_start = t_min;
- float t_end = t_max;
- float t = t_0;
-
- float t_best = t;
- float error_best = total_length;
-
- while (true)
- {
- auto cacheIt = cache.find(t);
- if (cacheIt == cache.end())
- {
- const auto front = ImCubicBezierSplit(p0, p1, p2, p3, t).Left;
- const auto split_length = ImCubicBezierLength(front);
-
- cacheIt = cache.emplace(t, split_length).first;
- }
-
- const auto length = cacheIt->second;
- const auto error = targetLength - length;
-
- if (error < error_best)
- {
- error_best = error;
- t_best = t;
- }
-
- if (ImFabs(error) <= max_value_error || ImFabs(t_start - t_end) <= max_t_error)
- {
- sample.T = t;
- sample.Length = length;
- sample.Point = ImCubicBezier(p0, p1, p2, p3, t);
-
- callback(sample, user_pointer);
- if (sample.BreakSearch)
- return;
-
- break;
- }
- else if (error < 0.0f)
- t_end = t;
- else // if (error > 0.0f)
- t_start = t;
-
- t = (t_start + t_end) * 0.5f;
- }
- }
-}
-
-inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float step, bool overshoot, float max_value_error, float max_t_error)
-{
- ImCubicBezierFixedStep(callback, user_pointer, curve.P0, curve.P1, curve.P2, curve.P3, step, overshoot, max_value_error, max_t_error);
-}
-
-// F has signature void(const ImCubicBezierFixedStepSample& p)
-template <typename F>
-inline void ImCubicBezierFixedStep(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot, float max_value_error, float max_t_error)
-{
- auto handler = [](ImCubicBezierFixedStepSample& sample, void* user_pointer)
- {
- auto& callback = *reinterpret_cast<F*>(user_pointer);
- callback(sample);
- };
-
- ImCubicBezierFixedStep(handler, &callback, p0, p1, p2, p3, step, overshoot, max_value_error, max_t_error);
-}
-
-template <typename F>
-inline void ImCubicBezierFixedStep(F& callback, const ImCubicBezierPoints& curve, float step, bool overshoot, float max_value_error, float max_t_error)
-{
- auto handler = [](ImCubicBezierFixedStepSample& sample, void* user_pointer)
- {
- auto& callback = *reinterpret_cast<F*>(user_pointer);
- callback(sample);
- };
-
- ImCubicBezierFixedStep(handler, &callback, curve.P0, curve.P1, curve.P2, curve.P3, step, overshoot, max_value_error, max_t_error);
-}
-
-
-//------------------------------------------------------------------------------
-# endif // __IMGUI_BEZIER_MATH_INL__
diff --git a/3rdparty/imgui-node-editor/imgui_canvas.cpp b/3rdparty/imgui-node-editor/imgui_canvas.cpp
deleted file mode 100644
index c71a413..0000000
--- a/3rdparty/imgui-node-editor/imgui_canvas.cpp
+++ /dev/null
@@ -1,550 +0,0 @@
-# define IMGUI_DEFINE_MATH_OPERATORS
-# include "imgui_canvas.h"
-# include <type_traits>
-
-// https://stackoverflow.com/a/36079786
-# define DECLARE_HAS_MEMBER(__trait_name__, __member_name__) \
- \
- template <typename __boost_has_member_T__> \
- class __trait_name__ \
- { \
- using check_type = ::std::remove_const_t<__boost_has_member_T__>; \
- struct no_type {char x[2];}; \
- using yes_type = char; \
- \
- struct base { void __member_name__() {}}; \
- struct mixin : public base, public check_type {}; \
- \
- template <void (base::*)()> struct aux {}; \
- \
- template <typename U> static no_type test(aux<&U::__member_name__>*); \
- template <typename U> static yes_type test(...); \
- \
- public: \
- \
- static constexpr bool value = (sizeof(yes_type) == sizeof(test<mixin>(0))); \
- }
-
-namespace ImCanvasDetails {
-
-DECLARE_HAS_MEMBER(HasFringeScale, _FringeScale);
-
-struct FringeScaleRef
-{
- // Overload is present when ImDrawList does have _FringeScale member variable.
- template <typename T>
- static float& Get(typename std::enable_if<HasFringeScale<T>::value, T>::type* drawList)
- {
- return drawList->_FringeScale;
- }
-
- // Overload is present when ImDrawList does not have _FringeScale member variable.
- template <typename T>
- static float& Get(typename std::enable_if<!HasFringeScale<T>::value, T>::type*)
- {
- static float placeholder = 1.0f;
- return placeholder;
- }
-};
-
-DECLARE_HAS_MEMBER(HasVtxCurrentOffset, _VtxCurrentOffset);
-
-struct VtxCurrentOffsetRef
-{
- // Overload is present when ImDrawList does have _FringeScale member variable.
- template <typename T>
- static unsigned int& Get(typename std::enable_if<HasVtxCurrentOffset<T>::value, T>::type* drawList)
- {
- return drawList->_VtxCurrentOffset;
- }
-
- // Overload is present when ImDrawList does not have _FringeScale member variable.
- template <typename T>
- static unsigned int& Get(typename std::enable_if<!HasVtxCurrentOffset<T>::value, T>::type* drawList)
- {
- return drawList->_CmdHeader.VtxOffset;
- }
-};
-
-} // namespace ImCanvasDetails
-
-// Returns a reference to _FringeScale extension to ImDrawList
-//
-// If ImDrawList does not have _FringeScale a placeholder is returned.
-static inline float& ImFringeScaleRef(ImDrawList* drawList)
-{
- using namespace ImCanvasDetails;
- return FringeScaleRef::Get<ImDrawList>(drawList);
-}
-
-static inline unsigned int& ImVtxOffsetRef(ImDrawList* drawList)
-{
- using namespace ImCanvasDetails;
- return VtxCurrentOffsetRef::Get<ImDrawList>(drawList);
-}
-
-static inline ImVec2 ImSelectPositive(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x > 0.0f ? lhs.x : rhs.x, lhs.y > 0.0f ? lhs.y : rhs.y); }
-
-bool ImGuiEx::Canvas::Begin(const char* id, const ImVec2& size)
-{
- return Begin(ImGui::GetID(id), size);
-}
-
-bool ImGuiEx::Canvas::Begin(ImGuiID id, const ImVec2& size)
-{
- IM_ASSERT(m_InBeginEnd == false);
-
- m_WidgetPosition = ImGui::GetCursorScreenPos();
- m_WidgetSize = ImSelectPositive(size, ImGui::GetContentRegionAvail());
- m_WidgetRect = ImRect(m_WidgetPosition, m_WidgetPosition + m_WidgetSize);
- m_DrawList = ImGui::GetWindowDrawList();
-
- UpdateViewTransformPosition();
-
-# if IMGUI_VERSION_NUM > 18415
- if (ImGui::IsClippedEx(m_WidgetRect, id))
- return false;
-# else
- if (ImGui::IsClippedEx(m_WidgetRect, id, false))
- return false;
-# endif
-
- // Save current channel, so we can assert when user
- // call canvas API with different one.
- m_ExpectedChannel = m_DrawList->_Splitter._Current;
-
- // #debug: Canvas content.
- //m_DrawList->AddRectFilled(m_StartPos, m_StartPos + m_CurrentSize, IM_COL32(0, 0, 0, 64));
- //m_DrawList->AddRect(m_WidgetRect.Min, m_WidgetRect.Max, IM_COL32(255, 0, 255, 64));
-
- ImGui::SetCursorScreenPos(ImVec2(0.0f, 0.0f));
-
-# if IMGUI_EX_CANVAS_DEFERED()
- m_Ranges.resize(0);
-# endif
-
- SaveInputState();
- SaveViewportState();
-
- // Record cursor max to prevent scrollbars from appearing.
- m_WindowCursorMaxBackup = ImGui::GetCurrentWindow()->DC.CursorMaxPos;
-
- EnterLocalSpace();
-
- // Emit dummy widget matching bounds of the canvas.
- ImGui::SetCursorScreenPos(m_ViewRect.Min);
- ImGui::Dummy(m_ViewRect.GetSize());
-
- ImGui::SetCursorScreenPos(ImVec2(0.0f, 0.0f));
-
- m_InBeginEnd = true;
-
- return true;
-}
-
-void ImGuiEx::Canvas::End()
-{
- // If you're here your call to Begin() returned false,
- // or Begin() wasn't called at all.
- IM_ASSERT(m_InBeginEnd == true);
-
- // If you're here, please make sure you do not interleave
- // channel splitter with canvas.
- // Always call canvas function with using same channel.
- IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel);
-
- //auto& io = ImGui::GetIO();
-
- // Check: Unmatched calls to Suspend() / Resume(). Please check your code.
- IM_ASSERT(m_SuspendCounter == 0);
-
- LeaveLocalSpace();
-
- ImGui::GetCurrentWindow()->DC.CursorMaxPos = m_WindowCursorMaxBackup;
-
- ImGui::SetItemAllowOverlap();
-
- // Emit dummy widget matching bounds of the canvas.
- ImGui::SetCursorScreenPos(m_WidgetPosition);
- ImGui::Dummy(m_WidgetSize);
-
- // #debug: Rect around canvas. Content should be inside these bounds.
- //m_DrawList->AddRect(m_WidgetPosition - ImVec2(1.0f, 1.0f), m_WidgetPosition + m_WidgetSize + ImVec2(1.0f, 1.0f), IM_COL32(196, 0, 0, 255));
-
- m_InBeginEnd = false;
-}
-
-void ImGuiEx::Canvas::SetView(const ImVec2& origin, float scale)
-{
- SetView(CanvasView(origin, scale));
-}
-
-void ImGuiEx::Canvas::SetView(const CanvasView& view)
-{
- if (m_InBeginEnd)
- LeaveLocalSpace();
-
- if (m_View.Origin.x != view.Origin.x || m_View.Origin.y != view.Origin.y)
- {
- m_View.Origin = view.Origin;
-
- UpdateViewTransformPosition();
- }
-
- if (m_View.Scale != view.Scale)
- {
- m_View.Scale = view.Scale;
- m_View.InvScale = view.InvScale;
- }
-
- if (m_InBeginEnd)
- EnterLocalSpace();
-}
-
-void ImGuiEx::Canvas::CenterView(const ImVec2& canvasPoint)
-{
- auto view = CalcCenterView(canvasPoint);
- SetView(view);
-}
-
-ImGuiEx::CanvasView ImGuiEx::Canvas::CalcCenterView(const ImVec2& canvasPoint) const
-{
- auto localCenter = ToLocal(m_WidgetPosition + m_WidgetSize * 0.5f);
- auto localOffset = canvasPoint - localCenter;
- auto offset = FromLocalV(localOffset);
-
- return CanvasView{ m_View.Origin - offset, m_View.Scale };
-}
-
-void ImGuiEx::Canvas::CenterView(const ImRect& canvasRect)
-{
- auto view = CalcCenterView(canvasRect);
-
- SetView(view);
-}
-
-ImGuiEx::CanvasView ImGuiEx::Canvas::CalcCenterView(const ImRect& canvasRect) const
-{
- auto canvasRectSize = canvasRect.GetSize();
-
- if (canvasRectSize.x <= 0.0f || canvasRectSize.y <= 0.0f)
- return View();
-
- auto widgetAspectRatio = m_WidgetSize.y > 0.0f ? m_WidgetSize.x / m_WidgetSize.y : 0.0f;
- auto canvasRectAspectRatio = canvasRectSize.y > 0.0f ? canvasRectSize.x / canvasRectSize.y : 0.0f;
-
- if (widgetAspectRatio <= 0.0f || canvasRectAspectRatio <= 0.0f)
- return View();
-
- auto newOrigin = m_View.Origin;
- auto newScale = m_View.Scale;
- if (canvasRectAspectRatio > widgetAspectRatio)
- {
- // width span across view
- newScale = m_WidgetSize.x / canvasRectSize.x;
- newOrigin = canvasRect.Min * -newScale;
- newOrigin.y += (m_WidgetSize.y - canvasRectSize.y * newScale) * 0.5f;
- }
- else
- {
- // height span across view
- newScale = m_WidgetSize.y / canvasRectSize.y;
- newOrigin = canvasRect.Min * -newScale;
- newOrigin.x += (m_WidgetSize.x - canvasRectSize.x * newScale) * 0.5f;
- }
-
- return CanvasView{ newOrigin, newScale };
-}
-
-void ImGuiEx::Canvas::Suspend()
-{
- // If you're here, please make sure you do not interleave
- // channel splitter with canvas.
- // Always call canvas function with using same channel.
- IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel);
-
- if (m_SuspendCounter == 0)
- LeaveLocalSpace();
-
- ++m_SuspendCounter;
-}
-
-void ImGuiEx::Canvas::Resume()
-{
- // If you're here, please make sure you do not interleave
- // channel splitter with canvas.
- // Always call canvas function with using same channel.
- IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel);
-
- // Check: Number of calls to Resume() do not match calls to Suspend(). Please check your code.
- IM_ASSERT(m_SuspendCounter > 0);
- if (--m_SuspendCounter == 0)
- EnterLocalSpace();
-}
-
-ImVec2 ImGuiEx::Canvas::FromLocal(const ImVec2& point) const
-{
- return point * m_View.Scale + m_ViewTransformPosition;
-}
-
-ImVec2 ImGuiEx::Canvas::FromLocal(const ImVec2& point, const CanvasView& view) const
-{
- return point * view.Scale + view.Origin + m_WidgetPosition;
-}
-
-ImVec2 ImGuiEx::Canvas::FromLocalV(const ImVec2& vector) const
-{
- return vector * m_View.Scale;
-}
-
-ImVec2 ImGuiEx::Canvas::FromLocalV(const ImVec2& vector, const CanvasView& view) const
-{
- return vector * view.Scale;
-}
-
-ImVec2 ImGuiEx::Canvas::ToLocal(const ImVec2& point) const
-{
- return (point - m_ViewTransformPosition) * m_View.InvScale;
-}
-
-ImVec2 ImGuiEx::Canvas::ToLocal(const ImVec2& point, const CanvasView& view) const
-{
- return (point - view.Origin - m_WidgetPosition) * view.InvScale;
-}
-
-ImVec2 ImGuiEx::Canvas::ToLocalV(const ImVec2& vector) const
-{
- return vector * m_View.InvScale;
-}
-
-ImVec2 ImGuiEx::Canvas::ToLocalV(const ImVec2& vector, const CanvasView& view) const
-{
- return vector * view.InvScale;
-}
-
-ImRect ImGuiEx::Canvas::CalcViewRect(const CanvasView& view) const
-{
- ImRect result;
- result.Min = ImVec2(-view.Origin.x, -view.Origin.y) * view.InvScale;
- result.Max = (m_WidgetSize - view.Origin) * view.InvScale;
- return result;
-}
-
-void ImGuiEx::Canvas::UpdateViewTransformPosition()
-{
- m_ViewTransformPosition = m_View.Origin + m_WidgetPosition;
-}
-
-void ImGuiEx::Canvas::SaveInputState()
-{
- auto& io = ImGui::GetIO();
- m_MousePosBackup = io.MousePos;
- m_MousePosPrevBackup = io.MousePosPrev;
- for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i)
- m_MouseClickedPosBackup[i] = io.MouseClickedPos[i];
-}
-
-void ImGuiEx::Canvas::RestoreInputState()
-{
- auto& io = ImGui::GetIO();
- io.MousePos = m_MousePosBackup;
- io.MousePosPrev = m_MousePosPrevBackup;
- for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i)
- io.MouseClickedPos[i] = m_MouseClickedPosBackup[i];
-}
-
-void ImGuiEx::Canvas::SaveViewportState()
-{
-# if defined(IMGUI_HAS_VIEWPORT)
- auto window = ImGui::GetCurrentWindow();
- auto viewport = ImGui::GetWindowViewport();
-
- m_WindowPosBackup = window->Pos;
- m_ViewportPosBackup = viewport->Pos;
- m_ViewportSizeBackup = viewport->Size;
-# if IMGUI_VERSION_NUM > 18002
- m_ViewportWorkPosBackup = viewport->WorkPos;
- m_ViewportWorkSizeBackup = viewport->WorkSize;
-# else
- m_ViewportWorkOffsetMinBackup = viewport->WorkOffsetMin;
- m_ViewportWorkOffsetMaxBackup = viewport->WorkOffsetMax;
-# endif
-# endif
-}
-
-void ImGuiEx::Canvas::RestoreViewportState()
-{
-# if defined(IMGUI_HAS_VIEWPORT)
- auto window = ImGui::GetCurrentWindow();
- auto viewport = ImGui::GetWindowViewport();
-
- window->Pos = m_WindowPosBackup;
- viewport->Pos = m_ViewportPosBackup;
- viewport->Size = m_ViewportSizeBackup;
-# if IMGUI_VERSION_NUM > 18002
- viewport->WorkPos = m_ViewportWorkPosBackup;
- viewport->WorkSize = m_ViewportWorkSizeBackup;
-# else
- viewport->WorkOffsetMin = m_ViewportWorkOffsetMinBackup;
- viewport->WorkOffsetMax = m_ViewportWorkOffsetMaxBackup;
-# endif
-# endif
-}
-
-void ImGuiEx::Canvas::EnterLocalSpace()
-{
- // Prepare ImDrawList for drawing in local coordinate system:
- // - determine visible part of the canvas
- // - start unique draw command
- // - add clip rect matching canvas size
- // - record current command index
- // - record current vertex write index
-
- // Determine visible part of the canvas. Make it before
- // adding new command, to avoid round rip where command
- // is removed in PopClipRect() and added again next PushClipRect().
- ImGui::PushClipRect(m_WidgetPosition, m_WidgetPosition + m_WidgetSize, true);
- auto clipped_clip_rect = m_DrawList->_ClipRectStack.back();
- ImGui::PopClipRect();
-
- // Make sure we do not share draw command with anyone. We don't want to mess
- // with someones clip rectangle.
-
- // #FIXME:
- // This condition is not enough to avoid when user choose
- // to use channel splitter.
- //
- // To deal with Suspend()/Resume() calls empty draw command
- // is always added then splitter is active. Otherwise
- // channel merger will collapse our draw command one with
- // different clip rectangle.
- //
- // More investigation is needed. To get to the bottom of this.
- if ((!m_DrawList->CmdBuffer.empty() && m_DrawList->CmdBuffer.back().ElemCount > 0) || m_DrawList->_Splitter._Count > 1)
- m_DrawList->AddDrawCmd();
-
-# if IMGUI_EX_CANVAS_DEFERED()
- m_Ranges.resize(m_Ranges.Size + 1);
- m_CurrentRange = &m_Ranges.back();
- m_CurrentRange->BeginComandIndex = ImMax(m_DrawList->CmdBuffer.Size - 1, 0);
- m_CurrentRange->BeginVertexIndex = m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList);
-# endif
- m_DrawListCommadBufferSize = ImMax(m_DrawList->CmdBuffer.Size - 1, 0);
- m_DrawListStartVertexIndex = m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList);
-
-# if defined(IMGUI_HAS_VIEWPORT)
- auto window = ImGui::GetCurrentWindow();
- window->Pos = ImVec2(0.0f, 0.0f);
-
- auto viewport_min = m_ViewportPosBackup;
- auto viewport_max = m_ViewportPosBackup + m_ViewportSizeBackup;
-
- viewport_min.x = (viewport_min.x - m_ViewTransformPosition.x) * m_View.InvScale;
- viewport_min.y = (viewport_min.y - m_ViewTransformPosition.y) * m_View.InvScale;
- viewport_max.x = (viewport_max.x - m_ViewTransformPosition.x) * m_View.InvScale;
- viewport_max.y = (viewport_max.y - m_ViewTransformPosition.y) * m_View.InvScale;
-
- auto viewport = ImGui::GetWindowViewport();
- viewport->Pos = viewport_min;
- viewport->Size = viewport_max - viewport_min;
-
-# if IMGUI_VERSION_NUM > 18002
- viewport->WorkPos = m_ViewportWorkPosBackup * m_View.InvScale;
- viewport->WorkSize = m_ViewportWorkSizeBackup * m_View.InvScale;
-# else
- viewport->WorkOffsetMin = m_ViewportWorkOffsetMinBackup * m_View.InvScale;
- viewport->WorkOffsetMax = m_ViewportWorkOffsetMaxBackup * m_View.InvScale;
-# endif
-# endif
-
- // Clip rectangle in parent canvas space and move it to local space.
- clipped_clip_rect.x = (clipped_clip_rect.x - m_ViewTransformPosition.x) * m_View.InvScale;
- clipped_clip_rect.y = (clipped_clip_rect.y - m_ViewTransformPosition.y) * m_View.InvScale;
- clipped_clip_rect.z = (clipped_clip_rect.z - m_ViewTransformPosition.x) * m_View.InvScale;
- clipped_clip_rect.w = (clipped_clip_rect.w - m_ViewTransformPosition.y) * m_View.InvScale;
- ImGui::PushClipRect(ImVec2(clipped_clip_rect.x, clipped_clip_rect.y), ImVec2(clipped_clip_rect.z, clipped_clip_rect.w), false);
-
- // Transform mouse position to local space.
- auto& io = ImGui::GetIO();
- io.MousePos = (m_MousePosBackup - m_ViewTransformPosition) * m_View.InvScale;
- io.MousePosPrev = (m_MousePosPrevBackup - m_ViewTransformPosition) * m_View.InvScale;
- for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i)
- io.MouseClickedPos[i] = (m_MouseClickedPosBackup[i] - m_ViewTransformPosition) * m_View.InvScale;
-
- m_ViewRect = CalcViewRect(m_View);;
-
- auto& fringeScale = ImFringeScaleRef(m_DrawList);
- m_LastFringeScale = fringeScale;
- fringeScale *= m_View.InvScale;
-}
-
-void ImGuiEx::Canvas::LeaveLocalSpace()
-{
- IM_ASSERT(m_DrawList->_Splitter._Current == m_ExpectedChannel);
-
-# if IMGUI_EX_CANVAS_DEFERED()
- IM_ASSERT(m_CurrentRange != nullptr);
-
- m_CurrentRange->EndVertexIndex = m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList);
- m_CurrentRange->EndCommandIndex = m_DrawList->CmdBuffer.size();
- if (m_CurrentRange->BeginVertexIndex == m_CurrentRange->EndVertexIndex)
- {
- // Drop empty range
- m_Ranges.resize(m_Ranges.Size - 1);
- }
- m_CurrentRange = nullptr;
-# endif
-
- // Move vertices to screen space.
- auto vertex = m_DrawList->VtxBuffer.Data + m_DrawListStartVertexIndex;
- auto vertexEnd = m_DrawList->VtxBuffer.Data + m_DrawList->_VtxCurrentIdx + ImVtxOffsetRef(m_DrawList);
-
- // If canvas view is not scaled take a faster path.
- if (m_View.Scale != 1.0f)
- {
- while (vertex < vertexEnd)
- {
- vertex->pos.x = vertex->pos.x * m_View.Scale + m_ViewTransformPosition.x;
- vertex->pos.y = vertex->pos.y * m_View.Scale + m_ViewTransformPosition.y;
- ++vertex;
- }
-
- // Move clip rectangles to screen space.
- for (int i = m_DrawListCommadBufferSize; i < m_DrawList->CmdBuffer.size(); ++i)
- {
- auto& command = m_DrawList->CmdBuffer[i];
- command.ClipRect.x = command.ClipRect.x * m_View.Scale + m_ViewTransformPosition.x;
- command.ClipRect.y = command.ClipRect.y * m_View.Scale + m_ViewTransformPosition.y;
- command.ClipRect.z = command.ClipRect.z * m_View.Scale + m_ViewTransformPosition.x;
- command.ClipRect.w = command.ClipRect.w * m_View.Scale + m_ViewTransformPosition.y;
- }
- }
- else
- {
- while (vertex < vertexEnd)
- {
- vertex->pos.x = vertex->pos.x + m_ViewTransformPosition.x;
- vertex->pos.y = vertex->pos.y + m_ViewTransformPosition.y;
- ++vertex;
- }
-
- // Move clip rectangles to screen space.
- for (int i = m_DrawListCommadBufferSize; i < m_DrawList->CmdBuffer.size(); ++i)
- {
- auto& command = m_DrawList->CmdBuffer[i];
- command.ClipRect.x = command.ClipRect.x + m_ViewTransformPosition.x;
- command.ClipRect.y = command.ClipRect.y + m_ViewTransformPosition.y;
- command.ClipRect.z = command.ClipRect.z + m_ViewTransformPosition.x;
- command.ClipRect.w = command.ClipRect.w + m_ViewTransformPosition.y;
- }
- }
-
- auto& fringeScale = ImFringeScaleRef(m_DrawList);
- fringeScale = m_LastFringeScale;
-
- // And pop \o/
- ImGui::PopClipRect();
-
- RestoreInputState();
- RestoreViewportState();
-}
diff --git a/3rdparty/imgui-node-editor/imgui_canvas.h b/3rdparty/imgui-node-editor/imgui_canvas.h
deleted file mode 100644
index e5e4959..0000000
--- a/3rdparty/imgui-node-editor/imgui_canvas.h
+++ /dev/null
@@ -1,268 +0,0 @@
-// Canvas widget - view over infinite virtual space.
-//
-// Canvas allows you to draw your widgets anywhere over infinite space and provide
-// view over it with support for panning and scaling.
-//
-// When you enter a canvas ImGui is moved to virtual space which mean:
-// - ImGui::GetCursorScreenPos() return (0, 0) and which correspond to top left corner
-// of the canvas on the screen (this can be changed using CanvasView()).
-// - Mouse input is brought to canvas space, so widgets works as usual.
-// - Everything you draw with ImDrawList will be in virtual space.
-//
-// By default origin point is on top left corner of canvas widget. It can be
-// changed with call to CanvasView() where you can specify what part of space
-// should be viewed by setting viewport origin point and scale. Current state
-// can be queried with CanvasViewOrigin() and CanvasViewScale().
-//
-// Viewport size is controlled by 'size' parameter in BeginCanvas(). You can query
-// it using CanvasContentMin/Max/Size functions. They are useful if you to not specify
-// canvas size in which case all free space is used.
-//
-// Bounds of visible region of infinite space can be queried using CanvasViewMin/Max/Size
-// functions. Everything that is drawn outside of this region will be clipped
-// as usual in ImGui.
-//
-// While drawing inside canvas you can translate position from world (usual ImGui space)
-// to virtual space and back using CanvasFromWorld()/CanvasToWorld().
-//
-// Canvas can be nested in each other (they are regular widgets after all). There
-// is a way to transform position between current and parent canvas with
-// CanvasFromParent()/CanvasToParent().
-//
-// Sometimes in more elaborate scenarios you want to move out canvas virtual space,
-// do something and came back. You can do that with SuspendCanvas() and ResumeCanvas().
-//
-// Note:
-// It is not valid to call canvas API outside of BeginCanvas() / EndCanvas() scope.
-//
-// VERSION 0.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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-# ifndef __IMGUI_EX_CANVAS_H__
-# define __IMGUI_EX_CANVAS_H__
-# pragma once
-
-# include <imgui.h>
-# include <imgui_internal.h> // ImRect, ImFloor
-
-namespace ImGuiEx {
-
-struct CanvasView
-{
- ImVec2 Origin;
- float Scale = 1.0f;
- float InvScale = 1.0f;
-
- CanvasView() = default;
- CanvasView(const ImVec2& origin, float scale)
- : Origin(origin)
- , Scale(scale)
- , InvScale(scale ? 1.0f / scale : 0.0f)
- {
- }
-
- void Set(const ImVec2& origin, float scale)
- {
- *this = CanvasView(origin, scale);
- }
-};
-
-// Canvas widget represent view over infinite plane.
-//
-// It acts like a child window without scroll bars with
-// ability to zoom to specific part of canvas plane.
-//
-// Widgets are clipped according to current view exactly
-// same way ImGui do. To avoid `missing widgets` artifacts first
-// setup visible region with SetView() then draw content.
-//
-// Everything drawn with ImDrawList betwen calls to Begin()/End()
-// will be drawn on canvas plane. This behavior can be suspended
-// by calling Suspend() and resumed by calling Resume().
-//
-// Warning:
-// Please do not interleave canvas with use of channel splitter.
-// Keep channel splitter contained inside canvas or always
-// call canvas functions from same channel.
-struct Canvas
-{
- // Begins drawing content of canvas plane.
- //
- // When false is returned that mean canvas is not visible to the
- // user can drawing should be skipped and End() not called.
- // When true is returned drawing must be ended with call to End().
- //
- // If any size component is equal to zero or less canvas will
- // automatically expand to all available area on that axis.
- // So (0, 300) will take horizontal space and have height
- // of 300 points. (0, 0) will take all remaining space of
- // the window.
- //
- // You can query size of the canvas while it is being drawn
- // by calling Rect().
- bool Begin(const char* id, const ImVec2& size);
- bool Begin(ImGuiID id, const ImVec2& size);
-
- // Ends interaction with canvas plane.
- //
- // Must be called only when Begin() retuned true.
- void End();
-
- // Sets visible region of canvas plane.
- //
- // Origin is an offset of infinite plane origin from top left
- // corner of the canvas.
- //
- // Scale greater than 1 make canvas content be bigger, less than 1 smaller.
- void SetView(const ImVec2& origin, float scale);
- void SetView(const CanvasView& view);
-
- // Centers view over specific point on canvas plane.
- //
- // View will be centered on specific point by changing origin
- // but not scale.
- void CenterView(const ImVec2& canvasPoint);
-
- // Calculates view over specific point on canvas plane.
- CanvasView CalcCenterView(const ImVec2& canvasPoint) const;
-
- // Centers view over specific rectangle on canvas plane.
- //
- // Whole rectangle will fit in canvas view. This will affect both
- // origin and scale.
- void CenterView(const ImRect& canvasRect);
-
- // Calculates view over specific rectangle on canvas plane.
- CanvasView CalcCenterView(const ImRect& canvasRect) const;
-
- // Suspends canvas by returning to normal ImGui transformation space.
- // While suspended UI will not be drawn on canvas plane.
- //
- // Calls to Suspend()/Resume() are symetrical. Each call to Suspend()
- // must be matched with call to Resume().
- void Suspend();
- void Resume();
-
- // Transforms point from canvas plane to ImGui.
- ImVec2 FromLocal(const ImVec2& point) const;
- ImVec2 FromLocal(const ImVec2& point, const CanvasView& view) const;
-
- // Transforms vector from canvas plant to ImGui.
- ImVec2 FromLocalV(const ImVec2& vector) const;
- ImVec2 FromLocalV(const ImVec2& vector, const CanvasView& view) const;
-
- // Transforms point from ImGui to canvas plane.
- ImVec2 ToLocal(const ImVec2& point) const;
- ImVec2 ToLocal(const ImVec2& point, const CanvasView& view) const;
-
- // Transforms vector from ImGui to canvas plane.
- ImVec2 ToLocalV(const ImVec2& vector) const;
- ImVec2 ToLocalV(const ImVec2& vector, const CanvasView& view) const;
-
- // Returns widget bounds.
- //
- // Note:
- // Rect is valid after call to Begin().
- const ImRect& Rect() const { return m_WidgetRect; }
-
- // Returns visible region on canvas plane (in canvas plane coordinates).
- const ImRect& ViewRect() const { return m_ViewRect; }
-
- // Calculates visible region for view.
- ImRect CalcViewRect(const CanvasView& view) const;
-
- // Returns current view.
- const CanvasView& View() const { return m_View; }
-
- // Returns origin of the view.
- //
- // Origin is an offset of infinite plane origin from top left
- // corner of the canvas.
- const ImVec2& ViewOrigin() const { return m_View.Origin; }
-
- // Returns scale of the view.
- float ViewScale() const { return m_View.Scale; }
-
- // Returns true if canvas is suspended.
- //
- // See: Suspend()/Resume()
- bool IsSuspended() const { return m_SuspendCounter > 0; }
-
-private:
-# define IMGUI_EX_CANVAS_DEFERED() 0
-
-# if IMGUI_EX_CANVAS_DEFERED()
- struct Range
- {
- int BeginVertexIndex = 0;
- int EndVertexIndex = 0;
- int BeginComandIndex = 0;
- int EndCommandIndex = 0;
- };
-# endif
-
- void UpdateViewTransformPosition();
-
- void SaveInputState();
- void RestoreInputState();
-
- void SaveViewportState();
- void RestoreViewportState();
-
- void EnterLocalSpace();
- void LeaveLocalSpace();
-
- bool m_InBeginEnd = false;
-
- ImVec2 m_WidgetPosition;
- ImVec2 m_WidgetSize;
- ImRect m_WidgetRect;
-
- ImDrawList* m_DrawList = nullptr;
- int m_ExpectedChannel = 0;
-
-# if IMGUI_EX_CANVAS_DEFERED()
- ImVector<Range> m_Ranges;
- Range* m_CurrentRange = nullptr;
-# endif
-
- int m_DrawListCommadBufferSize = 0;
- int m_DrawListStartVertexIndex = 0;
-
- CanvasView m_View;
- ImRect m_ViewRect;
-
- ImVec2 m_ViewTransformPosition;
-
- int m_SuspendCounter = 0;
-
- float m_LastFringeScale = 1.0f;
-
- ImVec2 m_MousePosBackup;
- ImVec2 m_MousePosPrevBackup;
- ImVec2 m_MouseClickedPosBackup[IM_ARRAYSIZE(ImGuiIO::MouseClickedPos)];
- ImVec2 m_WindowCursorMaxBackup;
-
-# if defined(IMGUI_HAS_VIEWPORT)
- ImVec2 m_WindowPosBackup;
- ImVec2 m_ViewportPosBackup;
- ImVec2 m_ViewportSizeBackup;
-# if IMGUI_VERSION_NUM > 18002
- ImVec2 m_ViewportWorkPosBackup;
- ImVec2 m_ViewportWorkSizeBackup;
-# else
- ImVec2 m_ViewportWorkOffsetMinBackup;
- ImVec2 m_ViewportWorkOffsetMaxBackup;
-# endif
-# endif
-};
-
-} // namespace ImGuiEx
-
-# endif // __IMGUI_EX_CANVAS_H__ \ No newline at end of file
diff --git a/3rdparty/imgui-node-editor/imgui_extra_math.h b/3rdparty/imgui-node-editor/imgui_extra_math.h
deleted file mode 100644
index 3022055..0000000
--- a/3rdparty/imgui-node-editor/imgui_extra_math.h
+++ /dev/null
@@ -1,73 +0,0 @@
-//------------------------------------------------------------------------------
-// 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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-//------------------------------------------------------------------------------
-# ifndef __IMGUI_EXTRA_MATH_H__
-# define __IMGUI_EXTRA_MATH_H__
-# pragma once
-
-
-//------------------------------------------------------------------------------
-# include <imgui.h>
-# ifndef IMGUI_DEFINE_MATH_OPERATORS
-# define IMGUI_DEFINE_MATH_OPERATORS
-# endif
-# include <imgui_internal.h>
-
-
-//------------------------------------------------------------------------------
-struct ImLine
-{
- ImVec2 A, B;
-};
-
-
-//------------------------------------------------------------------------------
-inline bool operator==(const ImVec2& lhs, const ImVec2& rhs);
-inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs);
-inline ImVec2 operator*(const float lhs, const ImVec2& rhs);
-inline ImVec2 operator-(const ImVec2& lhs);
-
-
-//------------------------------------------------------------------------------
-inline float ImLength(float v);
-inline float ImLength(const ImVec2& v);
-inline float ImLengthSqr(float v);
-inline ImVec2 ImNormalized(const ImVec2& v);
-
-
-//------------------------------------------------------------------------------
-inline bool ImRect_IsEmpty(const ImRect& rect);
-inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge);
-inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge, float radius);
-inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImRect& b);
-inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b);
-inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b, float radius_a, float radius_b);
-
-
-
-//------------------------------------------------------------------------------
-namespace ImEasing {
-
-template <typename V, typename T>
-inline V EaseOutQuad(V b, V c, T t)
-{
- return b - c * (t * (t - 2));
-}
-
-} // namespace ImEasing
-
-
-//------------------------------------------------------------------------------
-# include "imgui_extra_math.inl"
-
-
-//------------------------------------------------------------------------------
-# endif // __IMGUI_EXTRA_MATH_H__
diff --git a/3rdparty/imgui-node-editor/imgui_extra_math.inl b/3rdparty/imgui-node-editor/imgui_extra_math.inl
deleted file mode 100644
index 13cf990..0000000
--- a/3rdparty/imgui-node-editor/imgui_extra_math.inl
+++ /dev/null
@@ -1,189 +0,0 @@
-//------------------------------------------------------------------------------
-// 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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-//------------------------------------------------------------------------------
-# ifndef __IMGUI_EXTRA_MATH_INL__
-# define __IMGUI_EXTRA_MATH_INL__
-# pragma once
-
-
-//------------------------------------------------------------------------------
-# include "imgui_extra_math.h"
-
-
-//------------------------------------------------------------------------------
-inline bool operator==(const ImVec2& lhs, const ImVec2& rhs)
-{
- return lhs.x == rhs.x && lhs.y == rhs.y;
-}
-
-inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs)
-{
- return lhs.x != rhs.x || lhs.y != rhs.y;
-}
-
-inline ImVec2 operator*(const float lhs, const ImVec2& rhs)
-{
- return ImVec2(lhs * rhs.x, lhs * rhs.y);
-}
-
-inline ImVec2 operator-(const ImVec2& lhs)
-{
- return ImVec2(-lhs.x, -lhs.y);
-}
-
-
-//------------------------------------------------------------------------------
-inline float ImLength(float v)
-{
- return v;
-}
-
-inline float ImLength(const ImVec2& v)
-{
- return ImSqrt(ImLengthSqr(v));
-}
-
-inline float ImLengthSqr(float v)
-{
- return v * v;
-}
-
-inline ImVec2 ImNormalized(const ImVec2& v)
-{
- return v * ImInvLength(v, 0.0f);
-}
-
-
-
-
-//------------------------------------------------------------------------------
-inline bool ImRect_IsEmpty(const ImRect& rect)
-{
- return rect.Min.x >= rect.Max.x
- || rect.Min.y >= rect.Max.y;
-}
-
-inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge)
-{
- if (!snap_to_edge && rect.Contains(p))
- return p;
-
- return ImVec2(
- (p.x > rect.Max.x) ? rect.Max.x : (p.x < rect.Min.x ? rect.Min.x : p.x),
- (p.y > rect.Max.y) ? rect.Max.y : (p.y < rect.Min.y ? rect.Min.y : p.y)
- );
-}
-
-inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge, float radius)
-{
- auto point = ImRect_ClosestPoint(rect, p, snap_to_edge);
-
- const auto offset = p - point;
- const auto distance_sq = offset.x * offset.x + offset.y * offset.y;
- if (distance_sq <= 0)
- return point;
-
- const auto distance = ImSqrt(distance_sq);
-
- return point + offset * (ImMin(distance, radius) * (1.0f / distance));
-}
-
-inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImRect& other)
-{
- ImVec2 result;
- if (other.Min.x >= rect.Max.x)
- result.x = rect.Max.x;
- else if (other.Max.x <= rect.Min.x)
- result.x = rect.Min.x;
- else
- result.x = (ImMax(rect.Min.x, other.Min.x) + ImMin(rect.Max.x, other.Max.x)) / 2;
-
- if (other.Min.y >= rect.Max.y)
- result.y = rect.Max.y;
- else if (other.Max.y <= rect.Min.y)
- result.y = rect.Min.y;
- else
- result.y = (ImMax(rect.Min.y, other.Min.y) + ImMin(rect.Max.y, other.Max.y)) / 2;
-
- return result;
-}
-
-inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b)
-{
- ImLine result;
- result.A = ImRect_ClosestPoint(rect_a, rect_b);
- result.B = ImRect_ClosestPoint(rect_b, rect_a);
-
- auto distribute = [](float& a, float& b, float a0, float a1, float b0, float b1)
- {
- if (a0 >= b1 || a1 <= b0)
- return;
-
- const auto aw = a1 - a0;
- const auto bw = b1 - b0;
-
- if (aw > bw)
- {
- b = b0 + bw - bw * (a - a0) / aw;
- a = b;
- }
- else if (aw < bw)
- {
- a = a0 + aw - aw * (b - b0) / bw;
- b = a;
- }
- };
-
- distribute(result.A.x, result.B.x, rect_a.Min.x, rect_a.Max.x, rect_b.Min.x, rect_b.Max.x);
- distribute(result.A.y, result.B.y, rect_a.Min.y, rect_a.Max.y, rect_b.Min.y, rect_b.Max.y);
-
- return result;
-}
-
-inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b, float radius_a, float radius_b)
-{
- auto line = ImRect_ClosestLine(rect_a, rect_b);
- if (radius_a < 0)
- radius_a = 0;
- if (radius_b < 0)
- radius_b = 0;
-
- if (radius_a == 0 && radius_b == 0)
- return line;
-
- const auto offset = line.B - line.A;
- const auto length_sq = offset.x * offset.x + offset.y * offset.y;
- const auto radius_a_sq = radius_a * radius_a;
- const auto radius_b_sq = radius_b * radius_b;
-
- if (length_sq <= 0)
- return line;
-
- const auto length = ImSqrt(length_sq);
- const auto direction = ImVec2(offset.x / length, offset.y / length);
-
- const auto total_radius_sq = radius_a_sq + radius_b_sq;
- if (total_radius_sq > length_sq)
- {
- const auto scale = length / (radius_a + radius_b);
- radius_a *= scale;
- radius_b *= scale;
- }
-
- line.A = line.A + (direction * radius_a);
- line.B = line.B - (direction * radius_b);
-
- return line;
-}
-
-
-//------------------------------------------------------------------------------
-# endif // __IMGUI_EXTRA_MATH_INL__
diff --git a/3rdparty/imgui-node-editor/imgui_node_editor.cpp b/3rdparty/imgui-node-editor/imgui_node_editor.cpp
deleted file mode 100644
index 1042bed..0000000
--- a/3rdparty/imgui-node-editor/imgui_node_editor.cpp
+++ /dev/null
@@ -1,5629 +0,0 @@
-//------------------------------------------------------------------------------
-// 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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-//------------------------------------------------------------------------------
-# include "imgui_node_editor_internal.h"
-# include <cstdio> // snprintf
-# include <string>
-# include <fstream>
-# include <bitset>
-# include <climits>
-# include <algorithm>
-# include <sstream>
-# include <streambuf>
-# include <type_traits>
-
-// https://stackoverflow.com/a/8597498
-# define DECLARE_HAS_NESTED(Name, Member) \
- \
- template<class T> \
- struct has_nested_ ## Name \
- { \
- typedef char yes; \
- typedef yes(&no)[2]; \
- \
- template<class U> static yes test(decltype(U::Member)*); \
- template<class U> static no test(...); \
- \
- static bool const value = sizeof(test<T>(0)) == sizeof(yes); \
- };
-
-
-namespace ax {
-namespace NodeEditor {
-namespace Detail {
-
-# define DECLARE_KEY_TESTER(Key) \
- DECLARE_HAS_NESTED(Key, Key) \
- struct KeyTester_ ## Key \
- { \
- template <typename T> \
- static int Get(typename std::enable_if<has_nested_ ## Key<ImGuiKey_>::value, T>::type*) \
- { \
- return ImGui::GetKeyIndex(T::Key); \
- } \
- \
- template <typename T> \
- static int Get(typename std::enable_if<!has_nested_ ## Key<ImGuiKey_>::value, T>::type*) \
- { \
- return -1; \
- } \
- }
-
-DECLARE_KEY_TESTER(ImGuiKey_F);
-DECLARE_KEY_TESTER(ImGuiKey_D);
-
-static inline int GetKeyIndexForF()
-{
- return KeyTester_ImGuiKey_F::Get<ImGuiKey_>(nullptr);
-}
-
-static inline int GetKeyIndexForD()
-{
- return KeyTester_ImGuiKey_D::Get<ImGuiKey_>(nullptr);
-}
-
-} // namespace Detail
-} // namespace NodeEditor
-} // namespace ax
-
-
-//------------------------------------------------------------------------------
-namespace ed = ax::NodeEditor::Detail;
-
-
-//------------------------------------------------------------------------------
-static const int c_BackgroundChannelCount = 1;
-static const int c_LinkChannelCount = 4;
-static const int c_UserLayersCount = 5;
-
-static const int c_UserLayerChannelStart = 0;
-static const int c_BackgroundChannelStart = c_UserLayerChannelStart + c_UserLayersCount;
-static const int c_LinkStartChannel = c_BackgroundChannelStart + c_BackgroundChannelCount;
-static const int c_NodeStartChannel = c_LinkStartChannel + c_LinkChannelCount;
-
-static const int c_BackgroundChannel_SelectionRect = c_BackgroundChannelStart + 0;
-
-static const int c_UserChannel_Content = c_UserLayerChannelStart + 1;
-static const int c_UserChannel_Grid = c_UserLayerChannelStart + 2;
-static const int c_UserChannel_HintsBackground = c_UserLayerChannelStart + 3;
-static const int c_UserChannel_Hints = c_UserLayerChannelStart + 4;
-
-static const int c_LinkChannel_Selection = c_LinkStartChannel + 0;
-static const int c_LinkChannel_Links = c_LinkStartChannel + 1;
-static const int c_LinkChannel_Flow = c_LinkStartChannel + 2;
-static const int c_LinkChannel_NewLink = c_LinkStartChannel + 3;
-
-static const int c_ChannelsPerNode = 5;
-static const int c_NodeBaseChannel = 0;
-static const int c_NodeBackgroundChannel = 1;
-static const int c_NodeUserBackgroundChannel = 2;
-static const int c_NodePinChannel = 3;
-static const int c_NodeContentChannel = 4;
-
-static const float c_GroupSelectThickness = 6.0f; // canvas pixels
-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_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
-
-
-//------------------------------------------------------------------------------
-# if defined(_DEBUG) && defined(_WIN32)
-extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* string);
-
-static void LogV(const char* fmt, va_list args)
-{
- const int buffer_size = 1024;
- static char buffer[1024];
-
- vsnprintf(buffer, buffer_size - 1, fmt, args);
- buffer[buffer_size - 1] = 0;
-
- ImGui::LogText("\nNode Editor: %s", buffer);
-
- OutputDebugStringA("NodeEditor: ");
- OutputDebugStringA(buffer);
- OutputDebugStringA("\n");
-}
-# endif
-
-void ed::Log(const char* fmt, ...)
-{
-# if defined(_DEBUG) && defined(_WIN32)
- va_list args;
- va_start(args, fmt);
- LogV(fmt, args);
- va_end(args);
-# endif
-}
-
-
-//------------------------------------------------------------------------------
-static bool IsGroup(const ed::Node* node)
-{
- if (node && node->m_Type == ed::NodeType::Group)
- return true;
- else
- return false;
-}
-
-
-//------------------------------------------------------------------------------
-static void ImDrawListSplitter_Grow(ImDrawList* draw_list, ImDrawListSplitter* splitter, int channels_count)
-{
- IM_ASSERT(splitter != nullptr);
- IM_ASSERT(splitter->_Count <= channels_count);
-
- if (splitter->_Count == 1)
- {
- splitter->Split(draw_list, channels_count);
- return;
- }
-
- int old_channels_count = splitter->_Channels.Size;
- if (old_channels_count < channels_count)
- splitter->_Channels.resize(channels_count);
- int old_used_channels_count = splitter->_Count;
- splitter->_Count = channels_count;
-
- for (int i = old_used_channels_count; i < channels_count; i++)
- {
- if (i >= old_channels_count)
- {
- IM_PLACEMENT_NEW(&splitter->_Channels[i]) ImDrawChannel();
- }
- else
- {
- splitter->_Channels[i]._CmdBuffer.resize(0);
- splitter->_Channels[i]._IdxBuffer.resize(0);
- }
- if (splitter->_Channels[i]._CmdBuffer.Size == 0)
- {
- ImDrawCmd draw_cmd;
- draw_cmd.ClipRect = draw_list->_ClipRectStack.back();
- draw_cmd.TextureId = draw_list->_TextureIdStack.back();
- splitter->_Channels[i]._CmdBuffer.push_back(draw_cmd);
- }
- }
-}
-
-static void ImDrawList_ChannelsGrow(ImDrawList* draw_list, int channels_count)
-{
- ImDrawListSplitter_Grow(draw_list, &draw_list->_Splitter, channels_count);
-}
-
-static void ImDrawListSplitter_SwapChannels(ImDrawListSplitter* splitter, int left, int right)
-{
- IM_ASSERT(left < splitter->_Count && right < splitter->_Count);
- if (left == right)
- return;
-
- auto currentChannel = splitter->_Current;
-
- auto* leftCmdBuffer = &splitter->_Channels[left]._CmdBuffer;
- auto* leftIdxBuffer = &splitter->_Channels[left]._IdxBuffer;
- auto* rightCmdBuffer = &splitter->_Channels[right]._CmdBuffer;
- auto* rightIdxBuffer = &splitter->_Channels[right]._IdxBuffer;
-
- leftCmdBuffer->swap(*rightCmdBuffer);
- leftIdxBuffer->swap(*rightIdxBuffer);
-
- if (currentChannel == left)
- splitter->_Current = right;
- else if (currentChannel == right)
- splitter->_Current = left;
-}
-
-static void ImDrawList_SwapChannels(ImDrawList* drawList, int left, int right)
-{
- ImDrawListSplitter_SwapChannels(&drawList->_Splitter, left, right);
-}
-
-static void ImDrawList_SwapSplitter(ImDrawList* drawList, ImDrawListSplitter& splitter)
-{
- auto& currentSplitter = drawList->_Splitter;
-
- std::swap(currentSplitter._Current, splitter._Current);
- std::swap(currentSplitter._Count, splitter._Count);
- currentSplitter._Channels.swap(splitter._Channels);
-}
-
-//static void ImDrawList_TransformChannel_Inner(ImVector<ImDrawVert>& vtxBuffer, const ImVector<ImDrawIdx>& idxBuffer, const ImVector<ImDrawCmd>& cmdBuffer, const ImVec2& preOffset, const ImVec2& scale, const ImVec2& postOffset)
-//{
-// auto idxRead = idxBuffer.Data;
-//
-// int indexOffset = 0;
-// for (auto& cmd : cmdBuffer)
-// {
-// auto idxCount = cmd.ElemCount;
-//
-// if (idxCount == 0) continue;
-//
-// auto minIndex = idxRead[indexOffset];
-// auto maxIndex = idxRead[indexOffset];
-//
-// for (auto i = 1u; i < idxCount; ++i)
-// {
-// auto idx = idxRead[indexOffset + i];
-// minIndex = std::min(minIndex, idx);
-// maxIndex = ImMax(maxIndex, idx);
-// }
-//
-// for (auto vtx = vtxBuffer.Data + minIndex, vtxEnd = vtxBuffer.Data + maxIndex + 1; vtx < vtxEnd; ++vtx)
-// {
-// vtx->pos.x = (vtx->pos.x + preOffset.x) * scale.x + postOffset.x;
-// vtx->pos.y = (vtx->pos.y + preOffset.y) * scale.y + postOffset.y;
-// }
-//
-// indexOffset += idxCount;
-// }
-//}
-
-//static void ImDrawList_TransformChannels(ImDrawList* drawList, int begin, int end, const ImVec2& preOffset, const ImVec2& scale, const ImVec2& postOffset)
-//{
-// int lastCurrentChannel = drawList->_ChannelsCurrent;
-// if (lastCurrentChannel != 0)
-// drawList->ChannelsSetCurrent(0);
-//
-// auto& vtxBuffer = drawList->VtxBuffer;
-//
-// if (begin == 0 && begin != end)
-// {
-// ImDrawList_TransformChannel_Inner(vtxBuffer, drawList->IdxBuffer, drawList->CmdBuffer, preOffset, scale, postOffset);
-// ++begin;
-// }
-//
-// for (int channelIndex = begin; channelIndex < end; ++channelIndex)
-// {
-// auto& channel = drawList->_Channels[channelIndex];
-// ImDrawList_TransformChannel_Inner(vtxBuffer, channel.IdxBuffer, channel.CmdBuffer, preOffset, scale, postOffset);
-// }
-//
-// if (lastCurrentChannel != 0)
-// drawList->ChannelsSetCurrent(lastCurrentChannel);
-//}
-
-//static void ImDrawList_ClampClipRects_Inner(ImVector<ImDrawCmd>& cmdBuffer, const ImVec4& clipRect, const ImVec2& offset)
-//{
-// for (auto& cmd : cmdBuffer)
-// {
-// cmd.ClipRect.x = ImMax(cmd.ClipRect.x + offset.x, clipRect.x);
-// cmd.ClipRect.y = ImMax(cmd.ClipRect.y + offset.y, clipRect.y);
-// cmd.ClipRect.z = std::min(cmd.ClipRect.z + offset.x, clipRect.z);
-// cmd.ClipRect.w = std::min(cmd.ClipRect.w + offset.y, clipRect.w);
-// }
-//}
-
-//static void ImDrawList_TranslateAndClampClipRects(ImDrawList* drawList, int begin, int end, const ImVec2& offset)
-//{
-// int lastCurrentChannel = drawList->_ChannelsCurrent;
-// if (lastCurrentChannel != 0)
-// drawList->ChannelsSetCurrent(0);
-//
-// auto clipRect = drawList->_ClipRectStack.back();
-//
-// if (begin == 0 && begin != end)
-// {
-// ImDrawList_ClampClipRects_Inner(drawList->CmdBuffer, clipRect, offset);
-// ++begin;
-// }
-//
-// for (int channelIndex = begin; channelIndex < end; ++channelIndex)
-// {
-// auto& channel = drawList->_Channels[channelIndex];
-// ImDrawList_ClampClipRects_Inner(channel.CmdBuffer, clipRect, offset);
-// }
-//
-// if (lastCurrentChannel != 0)
-// drawList->ChannelsSetCurrent(lastCurrentChannel);
-//}
-
-static void ImDrawList_PathBezierOffset(ImDrawList* drawList, float offset, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3)
-{
- using namespace ed;
-
- auto acceptPoint = [drawList, offset](const ImCubicBezierSubdivideSample& r)
- {
- drawList->PathLineTo(r.Point + ImNormalized(ImVec2(-r.Tangent.y, r.Tangent.x)) * offset);
- };
-
- ImCubicBezierSubdivide(acceptPoint, p0, p1, p2, p3);
-}
-
-/*
-static void ImDrawList_PolyFillScanFlood(ImDrawList *draw, std::vector<ImVec2>* poly, ImColor color, int gap = 1, float strokeWidth = 1.0f)
-{
- std::vector<ImVec2> scanHits;
- ImVec2 min, max; // polygon min/max points
- auto io = ImGui::GetIO();
- float y;
- bool isMinMaxDone = false;
- unsigned int polysize = poly->size();
-
- // find the orthagonal bounding box
- // probably can put this as a predefined
- if (!isMinMaxDone)
- {
- min.x = min.y = FLT_MAX;
- max.x = max.y = FLT_MIN;
- for (auto p : *poly)
- {
- if (p.x < min.x) min.x = p.x;
- if (p.y < min.y) min.y = p.y;
- if (p.x > max.x) max.x = p.x;
- if (p.y > max.y) max.y = p.y;
- }
- isMinMaxDone = true;
- }
-
- // Bounds check
- if ((max.x < 0) || (min.x > io.DisplaySize.x) || (max.y < 0) || (min.y > io.DisplaySize.y)) return;
-
- // Vertically clip
- if (min.y < 0) min.y = 0;
- if (max.y > io.DisplaySize.y) max.y = io.DisplaySize.y;
-
- // so we know we start on the outside of the object we step out by 1.
- min.x -= 1;
- max.x += 1;
-
- // Initialise our starting conditions
- y = min.y;
-
- // Go through each scan line iteratively, jumping by 'gap' pixels each time
- while (y < max.y)
- {
- scanHits.clear();
-
- {
- int jump = 1;
- ImVec2 fp = poly->at(0);
-
- for (size_t i = 0; i < polysize - 1; i++)
- {
- ImVec2 pa = poly->at(i);
- ImVec2 pb = poly->at(i + 1);
-
- // jump double/dud points
- if (pa.x == pb.x && pa.y == pb.y) continue;
-
- // if we encounter our hull/poly start point, then we've now created the
- // closed
- // hull, jump the next segment and reset the first-point
- if ((!jump) && (fp.x == pb.x) && (fp.y == pb.y))
- {
- if (i < polysize - 2)
- {
- fp = poly->at(i + 2);
- jump = 1;
- i++;
- }
- }
- else
- {
- jump = 0;
- }
-
- // test to see if this segment makes the scan-cut.
- if ((pa.y > pb.y && y < pa.y && y > pb.y) || (pa.y < pb.y && y > pa.y && y < pb.y))
- {
- ImVec2 intersect;
-
- intersect.y = y;
- if (pa.x == pb.x)
- {
- intersect.x = pa.x;
- }
- else
- {
- intersect.x = (pb.x - pa.x) / (pb.y - pa.y) * (y - pa.y) + pa.x;
- }
- scanHits.push_back(intersect);
- }
- }
-
- // Sort the scan hits by X, so we have a proper left->right ordering
- sort(scanHits.begin(), scanHits.end(), [](ImVec2 const &a, ImVec2 const &b) { return a.x < b.x; });
-
- // generate the line segments.
- {
- int i = 0;
- int l = scanHits.size() - 1; // we need pairs of points, this prevents segfault.
- for (i = 0; i < l; i += 2)
- {
- draw->AddLine(scanHits[i], scanHits[i + 1], color, strokeWidth);
- }
- }
- }
- y += gap;
- } // for each scan line
- scanHits.clear();
-}
-*/
-
-static void ImDrawList_AddBezierWithArrows(ImDrawList* drawList, const ImCubicBezierPoints& curve, float thickness,
- float startArrowSize, float startArrowWidth, float endArrowSize, float endArrowWidth,
- bool fill, ImU32 color, float strokeThickness)
-{
- using namespace ax;
-
- if ((color >> 24) == 0)
- return;
-
- const auto half_thickness = thickness * 0.5f;
-
- if (fill)
- {
- drawList->AddBezierCubic(curve.P0, curve.P1, curve.P2, curve.P3, color, thickness);
-
- if (startArrowSize > 0.0f)
- {
- const auto start_dir = ImNormalized(ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 0.0f));
- const auto start_n = ImVec2(-start_dir.y, start_dir.x);
- const auto half_width = startArrowWidth * 0.5f;
- const auto tip = curve.P0 - start_dir * startArrowSize;
-
- drawList->PathLineTo(curve.P0 - start_n * ImMax(half_width, half_thickness));
- drawList->PathLineTo(curve.P0 + start_n * ImMax(half_width, half_thickness));
- drawList->PathLineTo(tip);
- drawList->PathFillConvex(color);
- }
-
- if (endArrowSize > 0.0f)
- {
- const auto end_dir = ImNormalized(ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 1.0f));
- const auto end_n = ImVec2( -end_dir.y, end_dir.x);
- const auto half_width = endArrowWidth * 0.5f;
- const auto tip = curve.P3 + end_dir * endArrowSize;
-
- drawList->PathLineTo(curve.P3 + end_n * ImMax(half_width, half_thickness));
- drawList->PathLineTo(curve.P3 - end_n * ImMax(half_width, half_thickness));
- drawList->PathLineTo(tip);
- drawList->PathFillConvex(color);
- }
- }
- else
- {
- if (startArrowSize > 0.0f)
- {
- const auto start_dir = ImNormalized(ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 0.0f));
- const auto start_n = ImVec2(-start_dir.y, start_dir.x);
- const auto half_width = startArrowWidth * 0.5f;
- const auto tip = curve.P0 - start_dir * startArrowSize;
-
- if (half_width > half_thickness)
- drawList->PathLineTo(curve.P0 - start_n * half_width);
- drawList->PathLineTo(tip);
- if (half_width > half_thickness)
- drawList->PathLineTo(curve.P0 + start_n * half_width);
- }
-
- ImDrawList_PathBezierOffset(drawList, half_thickness, curve.P0, curve.P1, curve.P2, curve.P3);
-
- if (endArrowSize > 0.0f)
- {
- const auto end_dir = ImNormalized(ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 1.0f));
- const auto end_n = ImVec2( -end_dir.y, end_dir.x);
- const auto half_width = endArrowWidth * 0.5f;
- const auto tip = curve.P3 + end_dir * endArrowSize;
-
- if (half_width > half_thickness)
- drawList->PathLineTo(curve.P3 + end_n * half_width);
- drawList->PathLineTo(tip);
- if (half_width > half_thickness)
- drawList->PathLineTo(curve.P3 - end_n * half_width);
- }
-
- ImDrawList_PathBezierOffset(drawList, half_thickness, curve.P3, curve.P2, curve.P1, curve.P0);
-
- drawList->PathStroke(color, true, strokeThickness);
- }
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Pin
-//
-//------------------------------------------------------------------------------
-void ed::Pin::Draw(ImDrawList* drawList, DrawFlags flags)
-{
- if (flags & Hovered)
- {
- drawList->ChannelsSetCurrent(m_Node->m_Channel + c_NodePinChannel);
-
- drawList->AddRectFilled(m_Bounds.Min, m_Bounds.Max,
- m_Color, m_Rounding, m_Corners);
-
- if (m_BorderWidth > 0.0f)
- {
- FringeScaleScope fringe(1.0f);
- drawList->AddRect(m_Bounds.Min, m_Bounds.Max,
- m_BorderColor, m_Rounding, m_Corners, m_BorderWidth);
- }
-
- if (!Editor->IsSelected(m_Node))
- m_Node->Draw(drawList, flags);
- }
-}
-
-ImVec2 ed::Pin::GetClosestPoint(const ImVec2& p) const
-{
- return ImRect_ClosestPoint(m_Pivot, p, true, m_Radius + m_ArrowSize);
-}
-
-ImLine ed::Pin::GetClosestLine(const Pin* pin) const
-{
- return ImRect_ClosestLine(m_Pivot, pin->m_Pivot, m_Radius + m_ArrowSize, pin->m_Radius + pin->m_ArrowSize);
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Node
-//
-//------------------------------------------------------------------------------
-bool ed::Node::AcceptDrag()
-{
- m_DragStart = m_Bounds.Min;
- return true;
-}
-
-void ed::Node::UpdateDrag(const ImVec2& offset)
-{
- auto size = m_Bounds.GetSize();
- m_Bounds.Min = ImFloor(m_DragStart + offset);
- m_Bounds.Max = m_Bounds.Min + size;
-}
-
-bool ed::Node::EndDrag()
-{
- return m_Bounds.Min != m_DragStart;
-}
-
-void ed::Node::Draw(ImDrawList* drawList, DrawFlags flags)
-{
- if (flags == Detail::Object::None)
- {
- drawList->ChannelsSetCurrent(m_Channel + c_NodeBackgroundChannel);
-
- drawList->AddRectFilled(
- m_Bounds.Min,
- m_Bounds.Max,
- m_Color, m_Rounding);
-
- if (IsGroup(this))
- {
- drawList->AddRectFilled(
- m_GroupBounds.Min,
- m_GroupBounds.Max,
- m_GroupColor, m_GroupRounding);
-
- if (m_GroupBorderWidth > 0.0f)
- {
- FringeScaleScope fringe(1.0f);
-
- drawList->AddRect(
- m_GroupBounds.Min,
- m_GroupBounds.Max,
- m_GroupBorderColor, m_GroupRounding, c_AllRoundCornersFlags, m_GroupBorderWidth);
- }
- }
-
-# if 0
- // #debug: highlight group regions
- auto drawRect = [drawList](const ImRect& rect, ImU32 color)
- {
- if (ImRect_IsEmpty(rect)) return;
- drawList->AddRectFilled(rect.Min, rect.Max, color);
- };
-
- drawRect(GetRegionBounds(NodeRegion::Top), IM_COL32(255, 0, 0, 64));
- drawRect(GetRegionBounds(NodeRegion::Bottom), IM_COL32(255, 0, 0, 64));
- drawRect(GetRegionBounds(NodeRegion::Left), IM_COL32(0, 255, 0, 64));
- drawRect(GetRegionBounds(NodeRegion::Right), IM_COL32(0, 255, 0, 64));
- drawRect(GetRegionBounds(NodeRegion::TopLeft), IM_COL32(255, 0, 255, 64));
- drawRect(GetRegionBounds(NodeRegion::TopRight), IM_COL32(255, 0, 255, 64));
- drawRect(GetRegionBounds(NodeRegion::BottomLeft), IM_COL32(255, 0, 255, 64));
- drawRect(GetRegionBounds(NodeRegion::BottomRight), IM_COL32(255, 0, 255, 64));
- drawRect(GetRegionBounds(NodeRegion::Center), IM_COL32(0, 0, 255, 64));
- drawRect(GetRegionBounds(NodeRegion::Header), IM_COL32(0, 255, 255, 64));
-# endif
-
- DrawBorder(drawList, m_BorderColor, m_BorderWidth);
- }
- else if (flags & Selected)
- {
- const auto borderColor = Editor->GetColor(StyleColor_SelNodeBorder);
- const auto& editorStyle = Editor->GetStyle();
-
- drawList->ChannelsSetCurrent(m_Channel + c_NodeBaseChannel);
-
- DrawBorder(drawList, borderColor, editorStyle.SelectedNodeBorderWidth);
- }
- else if (!IsGroup(this) && (flags & Hovered))
- {
- const auto borderColor = Editor->GetColor(StyleColor_HovNodeBorder);
- const auto& editorStyle = Editor->GetStyle();
-
- drawList->ChannelsSetCurrent(m_Channel + c_NodeBaseChannel);
-
- DrawBorder(drawList, borderColor, editorStyle.HoveredNodeBorderWidth);
- }
-}
-
-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, c_AllRoundCornersFlags, thickness);
- }
-}
-
-void ed::Node::GetGroupedNodes(std::vector<Node*>& result, bool append)
-{
- if (!append)
- result.resize(0);
-
- if (!IsGroup(this))
- return;
-
- const auto firstNodeIndex = result.size();
- Editor->FindNodesInRect(m_GroupBounds, result, true, false);
-
- for (auto index = firstNodeIndex; index < result.size(); ++index)
- result[index]->GetGroupedNodes(result, true);
-}
-
-ImRect ed::Node::GetRegionBounds(NodeRegion region) const
-{
- if (m_Type == NodeType::Node)
- {
- if (region == NodeRegion::Header)
- return m_Bounds;
- }
- else if (m_Type == NodeType::Group)
- {
- const float activeAreaMinimumSize = ImMax(ImMax(
- Editor->GetView().InvScale * c_GroupSelectThickness,
- m_GroupBorderWidth), c_GroupSelectThickness);
- const float minimumSize = activeAreaMinimumSize * 5;
-
- auto bounds = m_Bounds;
- if (bounds.GetWidth() < minimumSize)
- bounds.Expand(ImVec2(minimumSize - bounds.GetWidth(), 0.0f));
- if (bounds.GetHeight() < minimumSize)
- bounds.Expand(ImVec2(0.0f, minimumSize - bounds.GetHeight()));
-
- if (region == NodeRegion::Top)
- {
- bounds.Max.y = bounds.Min.y + activeAreaMinimumSize;
- bounds.Min.x += activeAreaMinimumSize;
- bounds.Max.x -= activeAreaMinimumSize;
- return bounds;
- }
- else if (region == NodeRegion::Bottom)
- {
- bounds.Min.y = bounds.Max.y - activeAreaMinimumSize;
- bounds.Min.x += activeAreaMinimumSize;
- bounds.Max.x -= activeAreaMinimumSize;
- return bounds;
- }
- else if (region == NodeRegion::Left)
- {
- bounds.Max.x = bounds.Min.x + activeAreaMinimumSize;
- bounds.Min.y += activeAreaMinimumSize;
- bounds.Max.y -= activeAreaMinimumSize;
- return bounds;
- }
- else if (region == NodeRegion::Right)
- {
- bounds.Min.x = bounds.Max.x - activeAreaMinimumSize;
- bounds.Min.y += activeAreaMinimumSize;
- bounds.Max.y -= activeAreaMinimumSize;
- return bounds;
- }
- else if (region == NodeRegion::TopLeft)
- {
- bounds.Max.x = bounds.Min.x + activeAreaMinimumSize * 2;
- bounds.Max.y = bounds.Min.y + activeAreaMinimumSize * 2;
- return bounds;
- }
- else if (region == NodeRegion::TopRight)
- {
- bounds.Min.x = bounds.Max.x - activeAreaMinimumSize * 2;
- bounds.Max.y = bounds.Min.y + activeAreaMinimumSize * 2;
- return bounds;
- }
- else if (region == NodeRegion::BottomRight)
- {
- bounds.Min.x = bounds.Max.x - activeAreaMinimumSize * 2;
- bounds.Min.y = bounds.Max.y - activeAreaMinimumSize * 2;
- return bounds;
- }
- else if (region == NodeRegion::BottomLeft)
- {
- bounds.Max.x = bounds.Min.x + activeAreaMinimumSize * 2;
- bounds.Min.y = bounds.Max.y - activeAreaMinimumSize * 2;
- return bounds;
- }
- else if (region == NodeRegion::Header)
- {
- bounds.Min.x += activeAreaMinimumSize;
- bounds.Max.x -= activeAreaMinimumSize;
- bounds.Min.y += activeAreaMinimumSize;
- bounds.Max.y = ImMax(bounds.Min.y + activeAreaMinimumSize, m_GroupBounds.Min.y);
- return bounds;
- }
- else if (region == NodeRegion::Center)
- {
- bounds.Max.x -= activeAreaMinimumSize;
- bounds.Min.y = ImMax(bounds.Min.y + activeAreaMinimumSize, m_GroupBounds.Min.y);
- bounds.Min.x += activeAreaMinimumSize;
- bounds.Max.y -= activeAreaMinimumSize;
- return bounds;
- }
- }
-
- return ImRect();
-}
-
-ed::NodeRegion ed::Node::GetRegion(const ImVec2& point) const
-{
- if (m_Type == NodeType::Node)
- {
- if (m_Bounds.Contains(point))
- return NodeRegion::Header;
- else
- return NodeRegion::None;
- }
- else if (m_Type == NodeType::Group)
- {
- static const NodeRegion c_Regions[] =
- {
- // Corners first, they may overlap other regions.
- NodeRegion::TopLeft,
- NodeRegion::TopRight,
- NodeRegion::BottomLeft,
- NodeRegion::BottomRight,
- NodeRegion::Header,
- NodeRegion::Top,
- NodeRegion::Bottom,
- NodeRegion::Left,
- NodeRegion::Right,
- NodeRegion::Center
- };
-
- for (auto region : c_Regions)
- {
- auto bounds = GetRegionBounds(region);
- if (bounds.Contains(point))
- return region;
- }
- }
-
- return NodeRegion::None;
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Link
-//
-//------------------------------------------------------------------------------
-void ed::Link::Draw(ImDrawList* drawList, DrawFlags flags)
-{
- if (flags == None)
- {
- drawList->ChannelsSetCurrent(c_LinkChannel_Links);
-
- Draw(drawList, m_Color, 0.0f);
- }
- else if (flags & Selected)
- {
- const auto borderColor = Editor->GetColor(StyleColor_SelLinkBorder);
-
- drawList->ChannelsSetCurrent(c_LinkChannel_Selection);
-
- Draw(drawList, borderColor, 4.5f);
- }
- else if (flags & Hovered)
- {
- const auto borderColor = Editor->GetColor(StyleColor_HovLinkBorder);
-
- drawList->ChannelsSetCurrent(c_LinkChannel_Selection);
-
- Draw(drawList, borderColor, 2.0f);
- }
-}
-
-void ed::Link::Draw(ImDrawList* drawList, ImU32 color, float extraThickness) const
-{
- if (!m_IsLive)
- return;
-
- const auto curve = GetCurve();
-
- ImDrawList_AddBezierWithArrows(drawList, curve, m_Thickness + extraThickness,
- m_StartPin && m_StartPin->m_ArrowSize > 0.0f ? m_StartPin->m_ArrowSize + extraThickness : 0.0f,
- m_StartPin && m_StartPin->m_ArrowWidth > 0.0f ? m_StartPin->m_ArrowWidth + extraThickness : 0.0f,
- m_EndPin && m_EndPin->m_ArrowSize > 0.0f ? m_EndPin->m_ArrowSize + extraThickness : 0.0f,
- m_EndPin && m_EndPin->m_ArrowWidth > 0.0f ? m_EndPin->m_ArrowWidth + extraThickness : 0.0f,
- true, color, 1.0f);
-}
-
-void ed::Link::UpdateEndpoints()
-{
- const auto line = m_StartPin->GetClosestLine(m_EndPin);
- m_Start = line.A;
- m_End = line.B;
-}
-
-ImCubicBezierPoints ed::Link::GetCurve() const
-{
- auto easeLinkStrength = [](const ImVec2& a, const ImVec2& b, float strength)
- {
- const auto distanceX = b.x - a.x;
- const auto distanceY = b.y - a.y;
- const auto distance = ImSqrt(distanceX * distanceX + distanceY * distanceY);
- const auto halfDistance = distance * 0.5f;
-
- if (halfDistance < strength)
- strength = strength * ImSin(IM_PI * 0.5f * halfDistance / strength);
-
- return strength;
- };
-
- const auto startStrength = easeLinkStrength(m_Start, m_End, m_StartPin->m_Strength);
- const auto endStrength = easeLinkStrength(m_Start, m_End, m_EndPin->m_Strength);
- const auto cp0 = m_Start + m_StartPin->m_Dir * startStrength;
- const auto cp1 = m_End + m_EndPin->m_Dir * endStrength;
-
- ImCubicBezierPoints result;
- result.P0 = m_Start;
- result.P1 = cp0;
- result.P2 = cp1;
- result.P3 = m_End;
-
- return result;
-}
-
-bool ed::Link::TestHit(const ImVec2& point, float extraThickness) const
-{
- if (!m_IsLive)
- return false;
-
- auto bounds = GetBounds();
- if (extraThickness > 0.0f)
- bounds.Expand(extraThickness);
-
- if (!bounds.Contains(point))
- return false;
-
- const auto bezier = GetCurve();
- const auto result = ImProjectOnCubicBezier(point, bezier.P0, bezier.P1, bezier.P2, bezier.P3, 50);
-
- return result.Distance <= m_Thickness + extraThickness;
-}
-
-bool ed::Link::TestHit(const ImRect& rect, bool allowIntersect) const
-{
- if (!m_IsLive)
- return false;
-
- const auto bounds = GetBounds();
-
- if (rect.Contains(bounds))
- return true;
-
- if (!allowIntersect || !rect.Overlaps(bounds))
- return false;
-
- const auto bezier = GetCurve();
-
- const auto p0 = rect.GetTL();
- const auto p1 = rect.GetTR();
- const auto p2 = rect.GetBR();
- const auto p3 = rect.GetBL();
-
- if (ImCubicBezierLineIntersect(bezier.P0, bezier.P1, bezier.P2, bezier.P3, p0, p1).Count > 0)
- return true;
- if (ImCubicBezierLineIntersect(bezier.P0, bezier.P1, bezier.P2, bezier.P3, p1, p2).Count > 0)
- return true;
- if (ImCubicBezierLineIntersect(bezier.P0, bezier.P1, bezier.P2, bezier.P3, p2, p3).Count > 0)
- return true;
- if (ImCubicBezierLineIntersect(bezier.P0, bezier.P1, bezier.P2, bezier.P3, p3, p0).Count > 0)
- return true;
-
- return false;
-}
-
-ImRect ed::Link::GetBounds() const
-{
- if (m_IsLive)
- {
- const auto curve = GetCurve();
- auto bounds = ImCubicBezierBoundingRect(curve.P0, curve.P1, curve.P2, curve.P3);
-
- if (bounds.GetWidth() == 0.0f)
- {
- bounds.Min.x -= 0.5f;
- bounds.Max.x += 0.5f;
- }
-
- if (bounds.GetHeight() == 0.0f)
- {
- bounds.Min.y -= 0.5f;
- bounds.Max.y += 0.5f;
- }
-
- if (m_StartPin->m_ArrowSize)
- {
- const auto start_dir = ImNormalized(ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 0.0f));
- const auto p0 = curve.P0;
- const auto p1 = curve.P0 - start_dir * m_StartPin->m_ArrowSize;
- const auto min = ImMin(p0, p1);
- const auto max = ImMax(p0, p1);
- auto arrowBounds = ImRect(min, ImMax(max, min + ImVec2(1, 1)));
- bounds.Add(arrowBounds);
- }
-
- if (m_EndPin->m_ArrowSize)
- {
- const auto end_dir = ImNormalized(ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, 1.0f));
- const auto p0 = curve.P3;
- const auto p1 = curve.P3 + end_dir * m_EndPin->m_ArrowSize;
- const auto min = ImMin(p0, p1);
- const auto max = ImMax(p0, p1);
- auto arrowBounds = ImRect(min, ImMax(max, min + ImVec2(1, 1)));
- bounds.Add(arrowBounds);
- }
-
- return bounds;
- }
- else
- return ImRect();
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Editor Context
-//
-//------------------------------------------------------------------------------
-ed::EditorContext::EditorContext(const ax::NodeEditor::Config* config)
- : m_IsFirstFrame(true)
- , m_IsFocused(false)
- , m_IsHovered(false)
- , m_IsHoveredWithoutOverlapp(false)
- , m_ShortcutsEnabled(true)
- , m_Style()
- , m_Nodes()
- , m_Pins()
- , m_Links()
- , m_SelectionId(1)
- , m_LastActiveLink(nullptr)
- , m_Canvas()
- , m_IsCanvasVisible(false)
- , m_NodeBuilder(this)
- , m_HintBuilder(this)
- , m_CurrentAction(nullptr)
- , m_NavigateAction(this, m_Canvas)
- , m_SizeAction(this)
- , m_DragAction(this)
- , m_SelectAction(this)
- , m_ContextMenuAction(this)
- , m_ShortcutAction(this)
- , m_CreateItemAction(this)
- , 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)
- , m_BackgroundClicked(false)
- , m_BackgroundDoubleClicked(false)
- , m_IsInitialized(false)
- , m_Settings()
- , m_Config(config)
- , m_DrawList(nullptr)
- , m_ExternalChannel(0)
-{
-}
-
-ed::EditorContext::~EditorContext()
-{
- if (m_IsInitialized)
- SaveSettings();
-
- for (auto link : m_Links) delete link.m_Object;
- for (auto pin : m_Pins) delete pin.m_Object;
- for (auto node : m_Nodes) delete node.m_Object;
-
- m_Splitter.ClearFreeMemory();
-}
-
-void ed::EditorContext::Begin(const char* id, const ImVec2& size)
-{
- if (!m_IsInitialized)
- {
- LoadSettings();
- m_IsInitialized = true;
- }
-
- //ImGui::LogToClipboard();
- //Log("---- begin ----");
-
- for (auto node : m_Nodes) node->Reset();
- for (auto pin : m_Pins) pin->Reset();
- for (auto link : m_Links) link->Reset();
-
- m_DrawList = ImGui::GetWindowDrawList();
-
- ImDrawList_SwapSplitter(m_DrawList, m_Splitter);
- m_ExternalChannel = m_DrawList->_Splitter._Current;
-
- ImGui::PushID(id);
-
- auto availableContentSize = ImGui::GetContentRegionAvail();
- ImVec2 canvasSize = ImFloor(size);
- if (canvasSize.x <= 0.0f)
- canvasSize.x = ImMax(4.0f, availableContentSize.x);
- 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));
- //ImGui::BeginChild(id, size, false,
- // ImGuiWindowFlags_NoMove |
- // ImGuiWindowFlags_NoScrollbar |
- // ImGuiWindowFlags_NoScrollWithMouse);
-
- m_IsFocused = ImGui::IsWindowFocused();
-
- //
- m_NavigateAction.SetWindow(m_Canvas.ViewRect().Min, m_Canvas.ViewRect().GetSize());
-
- // Handle canvas size change. Scale to Y axis, center on X.
- if (!ImRect_IsEmpty(previousVisibleRect) && previousSize != canvasSize)
- {
- 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);
- }
-
- m_Canvas.SetView(m_NavigateAction.GetView());
-
- // #debug #clip
- //ImGui::Text("CLIP = { x=%g y=%g w=%g h=%g r=%g b=%g }",
- // clipMin.x, clipMin.y, clipMax.x - clipMin.x, clipMax.y - clipMin.y, clipMax.x, clipMax.y);
-
- // Reserve channels for background and links
- ImDrawList_ChannelsGrow(m_DrawList, c_NodeStartChannel);
-
- if (HasSelectionChanged())
- ++m_SelectionId;
-
- m_LastSelectedObjects = m_SelectedObjects;
-}
-
-void ed::EditorContext::End()
-{
- //auto& io = ImGui::GetIO();
- auto control = BuildControl(m_CurrentAction && m_CurrentAction->IsDragging()); // NavigateAction.IsMovingOverEdge()
- //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;
- m_BackgroundClicked = control.BackgroundClicked;
- m_BackgroundDoubleClicked = control.BackgroundDoubleClicked;
-
- //if (DoubleClickedNode) LOG_TRACE(0, "DOUBLE CLICK NODE: %d", DoubleClickedNode);
- //if (DoubleClickedPin) LOG_TRACE(0, "DOUBLE CLICK PIN: %d", DoubleClickedPin);
- //if (DoubleClickedLink) LOG_TRACE(0, "DOUBLE CLICK LINK: %d", DoubleClickedLink);
- //if (BackgroundDoubleClicked) LOG_TRACE(0, "DOUBLE CLICK BACKGROUND", DoubleClickedLink);
-
- const bool isSelecting = m_CurrentAction && m_CurrentAction->AsSelect() != nullptr;
- const bool isDragging = m_CurrentAction && m_CurrentAction->AsDrag() != nullptr;
- //const bool isSizing = CurrentAction && CurrentAction->AsSize() != nullptr;
-
- // Draw nodes
- for (auto node : m_Nodes)
- if (node->m_IsLive && node->IsVisible())
- node->Draw(m_DrawList);
-
- // Draw links
- for (auto link : m_Links)
- if (link->m_IsLive && link->IsVisible())
- link->Draw(m_DrawList);
-
- // Highlight selected objects
- {
- auto selectedObjects = &m_SelectedObjects;
- if (auto selectAction = m_CurrentAction ? m_CurrentAction->AsSelect() : nullptr)
- selectedObjects = &selectAction->m_CandidateObjects;
-
- for (auto selectedObject : *selectedObjects)
- if (selectedObject->IsVisible())
- selectedObject->Draw(m_DrawList, Object::Selected);
- }
-
- if (!isSelecting)
- {
- auto hoveredObject = control.HotObject;
- if (auto dragAction = m_CurrentAction ? m_CurrentAction->AsDrag() : nullptr)
- hoveredObject = dragAction->m_DraggedObject;
- if (auto sizeAction = m_CurrentAction ? m_CurrentAction->AsSize() : nullptr)
- hoveredObject = sizeAction->m_SizedNode;
-
- if (hoveredObject && !IsSelected(hoveredObject) && hoveredObject->IsVisible())
- hoveredObject->Draw(m_DrawList, Object::Hovered);
- }
-
- // Draw animations
- for (auto controller : m_AnimationControllers)
- controller->Draw(m_DrawList);
-
- if (m_CurrentAction && !m_CurrentAction->Process(control))
- m_CurrentAction = nullptr;
-
- if (m_NavigateAction.m_IsActive)
- m_NavigateAction.Process(control);
- else
- m_NavigateAction.Accept(control);
-
- if (nullptr == m_CurrentAction)
- {
- EditorAction* possibleAction = nullptr;
-
- auto accept = [&possibleAction, &control](EditorAction& action)
- {
- auto result = action.Accept(control);
-
- if (result == EditorAction::True)
- return true;
- else if (/*!possibleAction &&*/ result == EditorAction::Possible)
- possibleAction = &action;
- else if (result == EditorAction::Possible)
- action.Reject();
-
- return false;
- };
-
- if (accept(m_ContextMenuAction))
- m_CurrentAction = &m_ContextMenuAction;
- else if (accept(m_ShortcutAction))
- m_CurrentAction = &m_ShortcutAction;
- else if (accept(m_SizeAction))
- m_CurrentAction = &m_SizeAction;
- else if (accept(m_DragAction))
- m_CurrentAction = &m_DragAction;
- else if (accept(m_SelectAction))
- m_CurrentAction = &m_SelectAction;
- else if (accept(m_CreateItemAction))
- m_CurrentAction = &m_CreateItemAction;
- else if (accept(m_DeleteItemsAction))
- m_CurrentAction = &m_DeleteItemsAction;
-
- if (possibleAction)
- ImGui::SetMouseCursor(possibleAction->GetCursor());
-
- if (m_CurrentAction && possibleAction)
- possibleAction->Reject();
- }
-
- if (m_CurrentAction)
- ImGui::SetMouseCursor(m_CurrentAction->GetCursor());
-
- // Draw selection rectangle
- m_SelectAction.Draw(m_DrawList);
-
- bool sortGroups = false;
- if (control.ActiveNode)
- {
- if (!IsGroup(control.ActiveNode))
- {
- // Bring active node to front
- auto activeNodeIt = std::find(m_Nodes.begin(), m_Nodes.end(), control.ActiveNode);
- std::rotate(activeNodeIt, activeNodeIt + 1, m_Nodes.end());
- }
- else if (!isDragging && m_CurrentAction && m_CurrentAction->AsDrag())
- {
- // Bring content of dragged group to front
- std::vector<Node*> nodes;
- control.ActiveNode->GetGroupedNodes(nodes);
-
- std::stable_partition(m_Nodes.begin(), m_Nodes.end(), [&nodes](Node* node)
- {
- return std::find(nodes.begin(), nodes.end(), node) == nodes.end();
- });
-
- sortGroups = true;
- }
- }
-
- // Sort nodes if bounds of node changed
- if (sortGroups || ((m_Settings.m_DirtyReason & (SaveReasonFlags::Position | SaveReasonFlags::Size)) != SaveReasonFlags::None))
- {
- // Bring all groups before regular nodes
- auto groupsItEnd = std::stable_partition(m_Nodes.begin(), m_Nodes.end(), IsGroup);
-
- // Sort groups by area
- std::sort(m_Nodes.begin(), groupsItEnd, [this](Node* lhs, Node* rhs)
- {
- const auto& lhsSize = lhs == m_SizeAction.m_SizedNode ? m_SizeAction.GetStartGroupBounds().GetSize() : lhs->m_GroupBounds.GetSize();
- const auto& rhsSize = rhs == m_SizeAction.m_SizedNode ? m_SizeAction.GetStartGroupBounds().GetSize() : rhs->m_GroupBounds.GetSize();
-
- const auto lhsArea = lhsSize.x * lhsSize.y;
- const auto rhsArea = rhsSize.x * rhsSize.y;
-
- return lhsArea > rhsArea;
- });
- }
-
- // 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
- // node drawing order.
- {
- // Copy group nodes
- 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 = m_DrawList->_Splitter._Count;
- ImDrawList_ChannelsGrow(m_DrawList, m_DrawList->_Splitter._Count + c_ChannelsPerNode * liveNodeCount + c_LinkChannelCount);
-
- int targetChannel = nodeChannelCount;
-
- auto copyNode = [this, &targetChannel](Node* node)
- {
- if (!node->m_IsLive)
- return;
-
- for (int i = 0; i < c_ChannelsPerNode; ++i)
- ImDrawList_SwapChannels(m_DrawList, node->m_Channel + i, targetChannel + i);
-
- node->m_Channel = targetChannel;
- targetChannel += c_ChannelsPerNode;
- };
-
- auto groupsItEnd = std::find_if(m_Nodes.begin(), m_Nodes.end(), [](Node* node) { return !IsGroup(node); });
-
- // Copy group nodes
- std::for_each(m_Nodes.begin(), groupsItEnd, copyNode);
-
- // Copy links
- for (int i = 0; i < c_LinkChannelCount; ++i, ++targetChannel)
- ImDrawList_SwapChannels(m_DrawList, c_LinkStartChannel + i, targetChannel);
-
- // Copy normal nodes
- std::for_each(groupsItEnd, m_Nodes.end(), copyNode);
- }
-# endif
-
- // ImGui::PopClipRect();
-
- // Draw grid
-# if 1 // #FIXME
- {
- //auto& style = ImGui::GetStyle();
-
- 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));
- float GRID_SX = 32.0f;// * m_Canvas.ViewScale();
- float GRID_SY = 32.0f;// * m_Canvas.ViewScale();
- ImVec2 VIEW_POS = m_Canvas.ViewRect().Min;
- ImVec2 VIEW_SIZE = m_Canvas.ViewRect().GetSize();
-
- 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)
- 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)
- m_DrawList->AddLine(ImVec2(0.0f, y) + VIEW_POS, ImVec2(VIEW_SIZE.x, y) + VIEW_POS, GRID_COLOR);
- }
-# endif
-
-# if 0
- {
- auto userChannel = drawList->_Splitter._Count;
- auto channelsToCopy = c_UserLayersCount;
- ImDrawList_ChannelsGrow(drawList, userChannel + channelsToCopy);
- for (int i = 0; i < channelsToCopy; ++i)
- ImDrawList_SwapChannels(drawList, userChannel + i, c_UserLayerChannelStart + i);
- }
-# endif
-
-# if 0
- {
- auto preOffset = ImVec2(0, 0);
- auto postOffset = m_OldCanvas.WindowScreenPos + m_OldCanvas.ClientOrigin;
- auto scale = m_OldCanvas.Zoom;
-
- ImDrawList_TransformChannels(drawList, 0, 1, preOffset, scale, postOffset);
- ImDrawList_TransformChannels(drawList, c_BackgroundChannelStart, drawList->_ChannelsCount - 1, preOffset, scale, postOffset);
-
- auto clipTranslation = m_OldCanvas.WindowScreenPos - m_OldCanvas.FromScreen(m_OldCanvas.WindowScreenPos);
- ImGui::PushClipRect(m_OldCanvas.WindowScreenPos + ImVec2(1, 1), m_OldCanvas.WindowScreenPos + m_OldCanvas.WindowScreenSize - ImVec2(1, 1), false);
- ImDrawList_TranslateAndClampClipRects(drawList, 0, 1, clipTranslation);
- ImDrawList_TranslateAndClampClipRects(drawList, c_BackgroundChannelStart, drawList->_ChannelsCount - 1, clipTranslation);
- ImGui::PopClipRect();
-
- // #debug: Static grid in local space
- //for (float x = 0; x < Canvas.WindowScreenSize.x; x += 100)
- // drawList->AddLine(ImVec2(x, 0.0f) + Canvas.WindowScreenPos, ImVec2(x, Canvas.WindowScreenSize.y) + Canvas.WindowScreenPos, IM_COL32(255, 0, 0, 128));
- //for (float y = 0; y < Canvas.WindowScreenSize.y; y += 100)
- // drawList->AddLine(ImVec2(0.0f, y) + Canvas.WindowScreenPos, ImVec2(Canvas.WindowScreenSize.x, y) + Canvas.WindowScreenPos, IM_COL32(255, 0, 0, 128));
- }
-# endif
-
-# if 1
- // Move user and hint channels to top
- {
- // Clip plane is transformed to global space.
- // 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](int channelIndex)
- {
- ImDrawChannel& channel = m_DrawList->_Splitter._Channels[channelIndex];
- for (ImDrawCmd& cmd : channel._CmdBuffer)
- {
- auto a = ToCanvas(ImVec2(cmd.ClipRect.x, cmd.ClipRect.y));
- auto b = ToCanvas(ImVec2(cmd.ClipRect.z, cmd.ClipRect.w));
- cmd.ClipRect = ImVec4(a.x, a.y, b.x, b.y);
- }
- };
-
- m_DrawList->ChannelsSetCurrent(0);
-
- 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);
- preTransformClipRect(channelCount + 2);
- }
-# endif
-
- UpdateAnimations();
-
- m_DrawList->ChannelsMerge();
-
- // #debug
- // drawList->AddRectFilled(ImVec2(-10.0f, -10.0f), ImVec2(10.0f, 10.0f), IM_COL32(255, 0, 255, 255));
-
- // ImGui::EndChild();
- // ImGui::PopStyleColor();
- if (m_IsCanvasVisible)
- m_Canvas.End();
-
- ImDrawList_SwapSplitter(m_DrawList, m_Splitter);
-
- // Draw border
- {
- auto& style = ImGui::GetStyle();
- auto borderShadoColor = style.Colors[ImGuiCol_BorderShadow];
- auto borderColor = style.Colors[ImGuiCol_Border];
- 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();
-
- if (!m_CurrentAction && m_IsFirstFrame && !m_Settings.m_Selection.empty())
- {
- ClearSelection();
- for (auto id : m_Settings.m_Selection)
- if (auto object = FindObject(id))
- SelectObject(object);
- }
-
- if (HasSelectionChanged())
- MakeDirty(SaveReasonFlags::Selection);
-
- if (m_Settings.m_IsDirty && !m_CurrentAction)
- SaveSettings();
-
- m_DrawList = nullptr;
- m_IsFirstFrame = false;
-}
-
-bool ed::EditorContext::DoLink(LinkId id, PinId startPinId, PinId endPinId, ImU32 color, float thickness)
-{
- //auto& editorStyle = GetStyle();
-
- auto startPin = FindPin(startPinId);
- auto endPin = FindPin(endPinId);
-
- if (!startPin || !startPin->m_IsLive || !endPin || !endPin->m_IsLive)
- return false;
-
- startPin->m_HasConnection = true;
- endPin->m_HasConnection = true;
-
- auto link = GetLink(id);
- link->m_StartPin = startPin;
- link->m_EndPin = endPin;
- link->m_Color = color;
- link->m_Thickness = thickness;
- link->m_IsLive = true;
-
- link->UpdateEndpoints();
-
- return true;
-}
-
-void ed::EditorContext::SetNodePosition(NodeId nodeId, const ImVec2& position)
-{
- auto node = FindNode(nodeId);
- if (!node)
- {
- node = CreateNode(nodeId);
- node->m_IsLive = false;
- }
-
- if (node->m_Bounds.Min != position)
- {
- node->m_Bounds.Translate(position - node->m_Bounds.Min);
- node->m_Bounds.Floor();
- MakeDirty(NodeEditor::SaveReasonFlags::Position, node);
- }
-}
-
-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);
- if (!node)
- return ImVec2(FLT_MAX, FLT_MAX);
-
- return node->m_Bounds.Min;
-}
-
-ImVec2 ed::EditorContext::GetNodeSize(NodeId nodeId)
-{
- auto node = FindNode(nodeId);
- if (!node)
- return ImVec2(0, 0);
-
- 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::UpdateNodeState(Node* node)
-{
- bool tryLoadState = node->m_RestoreState;
-
- node->m_RestoreState = false;
-
- auto settings = m_Settings.FindNode(node->m_ID);
- if (!settings)
- return;
-
- 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();
- node->m_GroupBounds.Min = settings->m_Location;
- node->m_GroupBounds.Max = node->m_GroupBounds.Min + settings->m_GroupSize;
- 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();
-}
-
-void ed::EditorContext::SelectObject(Object* object)
-{
- m_SelectedObjects.push_back(object);
-}
-
-void ed::EditorContext::DeselectObject(Object* object)
-{
- auto objectIt = std::find(m_SelectedObjects.begin(), m_SelectedObjects.end(), object);
- if (objectIt != m_SelectedObjects.end())
- m_SelectedObjects.erase(objectIt);
-}
-
-void ed::EditorContext::SetSelectedObject(Object* object)
-{
- ClearSelection();
- SelectObject(object);
-}
-
-void ed::EditorContext::ToggleObjectSelection(Object* object)
-{
- if (IsSelected(object))
- DeselectObject(object);
- else
- SelectObject(object);
-}
-
-bool ed::EditorContext::IsSelected(Object* object)
-{
- return std::find(m_SelectedObjects.begin(), m_SelectedObjects.end(), object) != m_SelectedObjects.end();
-}
-
-const ed::vector<ed::Object*>& ed::EditorContext::GetSelectedObjects()
-{
- return m_SelectedObjects;
-}
-
-bool ed::EditorContext::IsAnyNodeSelected()
-{
- for (auto object : m_SelectedObjects)
- if (object->AsNode())
- return true;
-
- return false;
-}
-
-bool ed::EditorContext::IsAnyLinkSelected()
-{
- for (auto object : m_SelectedObjects)
- if (object->AsLink())
- return true;
-
- return false;
-}
-
-bool ed::EditorContext::HasSelectionChanged()
-{
- return m_LastSelectedObjects != m_SelectedObjects;
-}
-
-ed::Node* ed::EditorContext::FindNodeAt(const ImVec2& p)
-{
- for (auto node : m_Nodes)
- if (node->TestHit(p))
- return node;
-
- return nullptr;
-}
-
-void ed::EditorContext::FindNodesInRect(const ImRect& r, vector<Node*>& result, bool append, bool includeIntersecting)
-{
- if (!append)
- result.resize(0);
-
- if (ImRect_IsEmpty(r))
- return;
-
- for (auto node : m_Nodes)
- if (node->TestHit(r, includeIntersecting))
- result.push_back(node);
-}
-
-void ed::EditorContext::FindLinksInRect(const ImRect& r, vector<Link*>& result, bool append)
-{
- if (!append)
- result.resize(0);
-
- if (ImRect_IsEmpty(r))
- return;
-
- for (auto link : m_Links)
- if (link->TestHit(r))
- 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)
- result.clear();
-
- 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)
- result.push_back(link);
- }
-}
-
-bool ed::EditorContext::PinHadAnyLinks(PinId pinId)
-{
- auto pin = FindPin(pinId);
- if (!pin || !pin->m_IsLive)
- return false;
-
- return pin->m_HasConnection || pin->m_HadConnection;
-}
-
-void ed::EditorContext::NotifyLinkDeleted(Link* link)
-{
- if (m_LastActiveLink == link)
- m_LastActiveLink = nullptr;
-}
-
-void ed::EditorContext::Suspend(SuspendFlags flags)
-{
- 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();
- m_DrawList->ChannelsSetCurrent(lastChannel);
- if ((flags & SuspendFlags::KeepSplitter) != SuspendFlags::KeepSplitter)
- ImDrawList_SwapSplitter(m_DrawList, m_Splitter);
-}
-
-void ed::EditorContext::Resume(SuspendFlags flags)
-{
- IM_ASSERT(m_DrawList != nullptr && "Reasume was called outiside of Begin/End.");
- if ((flags & SuspendFlags::KeepSplitter) != SuspendFlags::KeepSplitter)
- ImDrawList_SwapSplitter(m_DrawList, m_Splitter);
- auto lastChannel = m_DrawList->_Splitter._Current;
- m_DrawList->ChannelsSetCurrent(m_ExternalChannel);
- m_Canvas.Resume();
- m_DrawList->ChannelsSetCurrent(lastChannel);
-}
-
-bool ed::EditorContext::IsSuspended()
-{
- return m_Canvas.IsSuspended();
-}
-
-bool ed::EditorContext::IsFocused()
-{
- return m_IsFocused;
-}
-
-bool ed::EditorContext::IsHovered() const
-{
- return m_IsHovered;
-}
-
-bool ed::EditorContext::IsHoveredWithoutOverlapp() const
-{
- 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)
-{
- IM_ASSERT(nullptr == FindObject(id));
- auto pin = new Pin(this, id, kind);
- m_Pins.push_back({id, pin});
- std::sort(m_Pins.begin(), m_Pins.end());
- return pin;
-}
-
-ed::Node* ed::EditorContext::CreateNode(NodeId id)
-{
- IM_ASSERT(nullptr == FindObject(id));
- auto node = new Node(this, id);
- m_Nodes.push_back({id, node});
- //std::sort(Nodes.begin(), Nodes.end());
-
- auto settings = m_Settings.FindNode(id);
- if (!settings)
- settings = m_Settings.AddNode(id);
-
- UpdateNodeState(node);
-
- if (settings->m_GroupSize.x > 0 || settings->m_GroupSize.y > 0)
- node->m_Type = NodeType::Group;
-
- node->m_IsLive = false;
-
- return node;
-}
-
-ed::Link* ed::EditorContext::CreateLink(LinkId id)
-{
- IM_ASSERT(nullptr == FindObject(id));
- auto link = new Link(this, id);
- m_Links.push_back({id, link});
- std::sort(m_Links.begin(), m_Links.end());
-
- return link;
-}
-
-template <typename C, typename Id>
-static inline auto FindItemInLinear(C& container, Id id)
-{
-# if defined(_DEBUG)
- auto start = container.data();
- auto end = container.data() + container.size();
- for (auto it = start; it < end; ++it)
- if ((*it).m_ID == id)
- return it->m_Object;
-# else
- for (auto item : container)
- if (item.m_ID == id)
- return item.m_Object;
-# endif
-
- return static_cast<decltype(container[0].m_Object)>(nullptr);
-}
-
-template <typename C, typename Id>
-static inline auto FindItemIn(C& container, Id id)
-{
-//# if defined(_DEBUG)
-// auto start = container.data();
-// auto end = container.data() + container.size();
-// for (auto it = start; it < end; ++it)
-// if ((*it)->ID == id)
-// return *it;
-//# else
-// for (auto item : container)
-// if (item->ID == id)
-// return item;
-//# endif
- auto key = typename C::value_type{ id, nullptr };
- auto first = container.cbegin();
- auto last = container.cend();
- auto it = std::lower_bound(first, last, key);
- if (it != last && (key.m_ID == it->m_ID))
- return it->m_Object;
- else
- return static_cast<decltype(it->m_Object)>(nullptr);
-}
-
-ed::Node* ed::EditorContext::FindNode(NodeId id)
-{
- return FindItemInLinear(m_Nodes, id);
-}
-
-ed::Pin* ed::EditorContext::FindPin(PinId id)
-{
- return FindItemIn(m_Pins, id);
-}
-
-ed::Link* ed::EditorContext::FindLink(LinkId id)
-{
- return FindItemIn(m_Links, id);
-}
-
-ed::Object* ed::EditorContext::FindObject(ObjectId id)
-{
- if (id.IsNodeId())
- return FindNode(id.AsNodeId());
- else if (id.IsLinkId())
- return FindLink(id.AsLinkId());
- else if (id.IsPinId())
- return FindPin(id.AsPinId());
- else
- return nullptr;
-}
-
-ed::Node* ed::EditorContext::GetNode(NodeId id)
-{
- auto node = FindNode(id);
- if (!node)
- node = CreateNode(id);
- return node;
-}
-
-ed::Pin* ed::EditorContext::GetPin(PinId id, PinKind kind)
-{
- if (auto pin = FindPin(id))
- {
- pin->m_Kind = kind;
- return pin;
- }
- else
- return CreatePin(id, kind);
-}
-
-ed::Link* ed::EditorContext::GetLink(LinkId id)
-{
- if (auto link = FindLink(id))
- return link;
- else
- return CreateLink(id);
-}
-
-void ed::EditorContext::LoadSettings()
-{
- ed::Settings::Parse(m_Config.Load(), m_Settings);
-
- 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()
-{
- m_Config.BeginSave();
-
- for (auto& node : m_Nodes)
- {
- auto settings = m_Settings.FindNode(node->m_ID);
- settings->m_Location = node->m_Bounds.Min;
- settings->m_Size = node->m_Bounds.GetSize();
- if (IsGroup(node))
- settings->m_GroupSize = node->m_GroupBounds.GetSize();
-
- if (!node->m_RestoreState && settings->m_IsDirty && m_Config.SaveNodeSettings)
- {
- if (m_Config.SaveNode(node->m_ID, settings->Serialize().dump(), settings->m_DirtyReason))
- settings->ClearDirty();
- }
- }
-
- m_Settings.m_Selection.resize(0);
- 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_VisibleRect = m_NavigateAction.m_VisibleRect;
-
- if (m_Config.Save(m_Settings.Serialize(), m_Settings.m_DirtyReason))
- m_Settings.ClearDirty();
-
- m_Config.EndSave();
-}
-
-void ed::EditorContext::MakeDirty(SaveReasonFlags reason)
-{
- m_Settings.MakeDirty(reason);
-}
-
-void ed::EditorContext::MakeDirty(SaveReasonFlags reason, Node* node)
-{
- m_Settings.MakeDirty(reason, node);
-}
-
-ed::Link* ed::EditorContext::FindLinkAt(const ImVec2& p)
-{
- for (auto& link : m_Links)
- if (link->TestHit(p, c_LinkSelectThickness))
- return link;
-
- return nullptr;
-}
-
-ImU32 ed::EditorContext::GetColor(StyleColor colorIndex) const
-{
- return ImColor(m_Style.Colors[colorIndex]);
-}
-
-ImU32 ed::EditorContext::GetColor(StyleColor colorIndex, float alpha) const
-{
- auto color = m_Style.Colors[colorIndex];
- 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);
-}
-
-void ed::EditorContext::UnregisterAnimation(Animation* animation)
-{
- auto it = std::find(m_LiveAnimations.begin(), m_LiveAnimations.end(), animation);
- if (it != m_LiveAnimations.end())
- m_LiveAnimations.erase(it);
-}
-
-void ed::EditorContext::UpdateAnimations()
-{
- m_LastLiveAnimations = m_LiveAnimations;
-
- for (auto animation : m_LastLiveAnimations)
- {
- const bool isLive = (std::find(m_LiveAnimations.begin(), m_LiveAnimations.end(), animation) != m_LiveAnimations.end());
-
- if (isLive)
- animation->Update();
- }
-}
-
-void ed::EditorContext::Flow(Link* link, FlowDirection direction)
-{
- m_FlowAnimationController.Flow(link, direction);
-}
-
-void ed::EditorContext::SetUserContext(bool globalSpace)
-{
- const auto mousePos = ImGui::GetMousePos();
-
- // Move drawing cursor to mouse location and prepare layer for
- // content added by user.
- if (globalSpace)
- ImGui::SetCursorScreenPos(m_Canvas.FromLocal(mousePos));
- else
- ImGui::SetCursorScreenPos(m_Canvas.FromLocal(mousePos));
- //ImGui::SetCursorScreenPos(ImFloor(mousePos));
- //ImGui::SetCursorScreenPos(ImVec2(floorf(mousePos.x), floorf(mousePos.y)));
-
- if (!IsSuspended())
- {
- m_DrawList->ChannelsSetCurrent(c_UserChannel_Content);
- }
-
- // #debug
- // drawList->AddCircleFilled(ImGui::GetMousePos(), 4, IM_COL32(0, 255, 0, 255));
-}
-
-void ed::EditorContext::EnableShortcuts(bool enable)
-{
- m_ShortcutsEnabled = enable;
-}
-
-bool ed::EditorContext::AreShortcutsEnabled()
-{
- return m_ShortcutsEnabled;
-}
-
-ed::Control ed::EditorContext::BuildControl(bool allowOffscreen)
-{
- 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();
-
- // Expand clip rectangle to always contain cursor
- auto editorRect = m_Canvas.ViewRect();
- auto isMouseOffscreen = allowOffscreen && !editorRect.Contains(mousePos);
- if (isMouseOffscreen)
- {
- // Extend clip rect to capture off-screen mouse cursor
- editorRect.Add(ImFloor(mousePos));
- editorRect.Add(ImVec2(ImCeil(mousePos.x), ImCeil(mousePos.y)));
-
- ImGui::PushClipRect(editorRect.Min, editorRect.Max, false);
- }
-
- Object* hotObject = nullptr;
- Object* activeObject = nullptr;
- 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 = [extraFlags](ObjectId id, const ImRect& rect)
- {
- char idString[33] = { 0 }; // itoa can output 33 bytes maximum
- snprintf(idString, 32, "%p", id.AsPointer());
- ImGui::SetCursorScreenPos(rect.Min);
-
- // debug
- //if (id < 0) return ImGui::Button(idString, to_imvec(rect.size));
-
- auto result = invisibleButtonEx(idString, rect.GetSize(), extraFlags);
-
- // #debug
- //m_DrawList->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(0, 255, 0, 64));
-
- return result;
- };
-
- // Check input interactions over area.
- 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(m_Config.DragButtonIndex) && ImGui::IsItemHovered())
- doubleClickedObject = object;
-
- if (!hotObject && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
- hotObject = object;
-
- if (ImGui::IsItemActive())
- activeObject = object;
- };
-
- // Process live nodes and pins.
- for (auto nodeIt = m_Nodes.rbegin(), nodeItEnd = m_Nodes.rend(); nodeIt != nodeItEnd; ++nodeIt)
- {
- auto node = *nodeIt;
-
- if (!node->m_IsLive) continue;
-
- // Check for interactions with live pins in node before
- // processing node itself. Pins does not overlap each other
- // and all are within node bounds.
- for (auto pin = node->m_LastPin; pin; pin = pin->m_PreviousPin)
- {
- if (!pin->m_IsLive) continue;
-
- checkInteractionsInArea(pin->m_ID, pin->m_Bounds, pin);
- }
-
- // Check for interactions with node.
- if (node->m_Type == NodeType::Group)
- {
- // Node with a hole
- ImGui::PushID(node->m_ID.AsPointer());
-
- static const NodeRegion c_Regions[] =
- {
- NodeRegion::TopLeft,
- NodeRegion::TopRight,
- NodeRegion::BottomLeft,
- NodeRegion::BottomRight,
- NodeRegion::Top,
- NodeRegion::Bottom,
- NodeRegion::Left,
- NodeRegion::Right,
- NodeRegion::Header,
- };
-
- for (auto region : c_Regions)
- {
- auto bounds = node->GetRegionBounds(region);
- if (ImRect_IsEmpty(bounds))
- continue;
- checkInteractionsInArea(NodeId(static_cast<int>(region)), bounds, node);
- }
-
- ImGui::PopID();
- }
- else
- checkInteractionsInArea(node->m_ID, node->m_Bounds, node);
- }
-
- // Links are not regular widgets and must be done manually since
- // ImGui does not support interactive elements with custom hit maps.
- //
- // Links can steal input from background.
-
- // Links are just over background. So if anything else
- // is hovered we can skip them.
- if (nullptr == hotObject)
- hotObject = FindLinkAt(mousePos);
-
- // Check for interaction with background.
- auto backgroundClicked = emitInteractiveArea(NodeId(0), editorRect);
- 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);
-
- if (backgroundDoubleClicked)
- backgroundClicked = false;
-
- if (isMouseOffscreen)
- ImGui::PopClipRect();
-
- // Process link input using background interactions.
- auto hotLink = hotObject ? hotObject->AsLink() : nullptr;
-
- // ImGui take care of tracking active items. With link
- // we must do this ourself.
- if (!isDragging && isBackgroundActive && hotLink && !m_LastActiveLink)
- m_LastActiveLink = hotLink;
- if (isBackgroundActive && m_LastActiveLink)
- {
- activeObject = m_LastActiveLink;
- isBackgroundActive = false;
- }
- else if (!isBackgroundActive && m_LastActiveLink)
- m_LastActiveLink = nullptr;
-
- // Steal click from backgrounds if link is hovered.
- if (!isDragging && backgroundClicked && hotLink)
- {
- clickedObject = hotLink;
- backgroundClicked = false;
- }
-
- // Steal double-click from backgrounds if link is hovered.
- if (!isDragging && backgroundDoubleClicked && hotLink)
- {
- doubleClickedObject = hotLink;
- 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);
-}
-
-void ed::EditorContext::ShowMetrics(const Control& control)
-{
- auto& io = ImGui::GetIO();
-
- auto getObjectName = [](Object* object)
- {
- if (!object) return "";
- else if (object->AsNode()) return "Node";
- else if (object->AsPin()) return "Pin";
- else if (object->AsLink()) return "Link";
- else return "";
- };
-
- auto getHotObjectName = [&control, &getObjectName]()
- {
- if (control.HotObject)
- return getObjectName(control.HotObject);
- else if (control.BackgroundHot)
- return "Background";
- else
- return "<unknown>";
- };
-
- auto getActiveObjectName = [&control, &getObjectName]()
- {
- if (control.ActiveObject)
- return getObjectName(control.ActiveObject);
- else if (control.BackgroundActive)
- return "Background";
- else
- return "<unknown>";
- };
-
- auto liveNodeCount = CountLiveNodes();
- auto livePinCount = CountLivePins();
- auto liveLinkCount = CountLiveLinks();
-
- auto canvasRect = m_Canvas.Rect();
- auto viewRect = m_Canvas.ViewRect();
- auto localMousePos = m_Canvas.ToLocal(io.MousePos);
- auto globalMousePos = io.MousePos;
-
- ImGui::SetCursorScreenPos(canvasRect.Min + ImVec2(5, 5));
- ImGui::BeginGroup();
- 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());
- ImGui::Text("Mouse: { x=%.0f y=%.0f } global: { x=%g y=%g }", localMousePos.x, localMousePos.y, globalMousePos.x, globalMousePos.y);
- ImGui::Text("Live Nodes: %d", liveNodeCount);
- ImGui::Text("Live Pins: %d", livePinCount);
- ImGui::Text("Live Links: %d", liveLinkCount);
- ImGui::Text("Hot Object: %s (%p)", getHotObjectName(), control.HotObject ? control.HotObject->ID().AsPointer() : nullptr);
- if (auto node = control.HotObject ? control.HotObject->AsNode() : nullptr)
- {
- ImGui::SameLine();
- ImGui::Text("{ x=%g y=%g w=%g h=%g }", node->m_Bounds.Min.x, node->m_Bounds.Min.y, node->m_Bounds.GetWidth(), node->m_Bounds.GetHeight());
- }
- ImGui::Text("Active Object: %s (%p)", getActiveObjectName(), control.ActiveObject ? control.ActiveObject->ID().AsPointer() : nullptr);
- if (auto node = control.ActiveObject ? control.ActiveObject->AsNode() : nullptr)
- {
- ImGui::SameLine();
- ImGui::Text("{ x=%g y=%g w=%g h=%g }", node->m_Bounds.Min.x, node->m_Bounds.Min.y, node->m_Bounds.GetWidth(), node->m_Bounds.GetHeight());
- }
- ImGui::Text("Action: %s", m_CurrentAction ? m_CurrentAction->GetName() : "<none>");
- ImGui::Text("Action Is Dragging: %s", m_CurrentAction && m_CurrentAction->IsDragging() ? "Yes" : "No");
- m_NavigateAction.ShowMetrics();
- m_SizeAction.ShowMetrics();
- m_DragAction.ShowMetrics();
- m_SelectAction.ShowMetrics();
- m_ContextMenuAction.ShowMetrics();
- m_CreateItemAction.ShowMetrics();
- m_DeleteItemsAction.ShowMetrics();
- ImGui::EndGroup();
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Node Settings
-//
-//------------------------------------------------------------------------------
-void ed::NodeSettings::ClearDirty()
-{
- m_IsDirty = false;
- m_DirtyReason = SaveReasonFlags::None;
-}
-
-void ed::NodeSettings::MakeDirty(SaveReasonFlags reason)
-{
- m_IsDirty = true;
- m_DirtyReason = m_DirtyReason | reason;
-}
-
-ed::json::value ed::NodeSettings::Serialize()
-{
- json::value result;
- result["location"]["x"] = m_Location.x;
- result["location"]["y"] = m_Location.y;
-
- if (m_GroupSize.x > 0 || m_GroupSize.y > 0)
- {
- result["group_size"]["x"] = m_GroupSize.x;
- result["group_size"]["y"] = m_GroupSize.y;
- }
-
- return result;
-}
-
-bool ed::NodeSettings::Parse(const std::string& string, NodeSettings& settings)
-{
- auto settingsValue = json::value::parse(string);
- if (settingsValue.is_discarded())
- return false;
-
- return Parse(settingsValue, settings);
-}
-
-bool ed::NodeSettings::Parse(const json::value& data, NodeSettings& result)
-{
- if (!data.is_object())
- return false;
-
- auto tryParseVector = [](const json::value& v, ImVec2& result) -> bool
- {
- if (v.is_object())
- {
- auto xValue = v["x"];
- auto yValue = v["y"];
-
- if (xValue.is_number() && yValue.is_number())
- {
- result.x = static_cast<float>(xValue.get<double>());
- result.y = static_cast<float>(yValue.get<double>());
-
- return true;
- }
- }
-
- return false;
- };
-
- if (!tryParseVector(data["location"], result.m_Location))
- return false;
-
- if (data.contains("group_size") && !tryParseVector(data["group_size"], result.m_GroupSize))
- return false;
-
- return true;
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Settings
-//
-//------------------------------------------------------------------------------
-ed::NodeSettings* ed::Settings::AddNode(NodeId id)
-{
- m_Nodes.push_back(NodeSettings(id));
- return &m_Nodes.back();
-}
-
-ed::NodeSettings* ed::Settings::FindNode(NodeId id)
-{
- for (auto& settings : m_Nodes)
- if (settings.m_ID == id)
- return &settings;
-
- 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)
- {
- auto settings = FindNode(node->m_ID);
- IM_ASSERT(settings);
- settings->ClearDirty();
- }
- else
- {
- m_IsDirty = false;
- m_DirtyReason = SaveReasonFlags::None;
-
- for (auto& knownNode : m_Nodes)
- knownNode.ClearDirty();
- }
-}
-
-void ed::Settings::MakeDirty(SaveReasonFlags reason, Node* node)
-{
- m_IsDirty = true;
- m_DirtyReason = m_DirtyReason | reason;
-
- if (node)
- {
- auto settings = FindNode(node->m_ID);
- IM_ASSERT(settings);
-
- settings->MakeDirty(reason);
- }
-}
-
-std::string ed::Settings::Serialize()
-{
- json::value result;
-
- auto serializeObjectId = [](ObjectId id)
- {
- auto value = std::to_string(reinterpret_cast<uintptr_t>(id.AsPointer()));
- switch (id.Type())
- {
- default:
- case NodeEditor::Detail::ObjectType::None: return value;
- case NodeEditor::Detail::ObjectType::Node: return "node:" + value;
- case NodeEditor::Detail::ObjectType::Link: return "link:" + value;
- case NodeEditor::Detail::ObjectType::Pin: return "pin:" + value;
- }
- };
-
- auto& nodes = result["nodes"];
- for (auto& node : m_Nodes)
- {
- if (node.m_WasUsed)
- nodes[serializeObjectId(node.m_ID)] = node.Serialize();
- }
-
- auto& selection = result["selection"];
- for (auto& id : m_Selection)
- selection.push_back(serializeObjectId(id));
-
- auto& view = result["view"];
- 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();
-}
-
-bool ed::Settings::Parse(const std::string& string, Settings& settings)
-{
- Settings result = settings;
-
- auto settingsValue = json::value::parse(string);
- if (settingsValue.is_discarded())
- return false;
-
- if (!settingsValue.is_object())
- return false;
-
- auto tryParseVector = [](const json::value& v, ImVec2& result) -> bool
- {
- if (v.is_object() && v.contains("x") && v.contains("y"))
- {
- auto xValue = v["x"];
- auto yValue = v["y"];
-
- if (xValue.is_number() && yValue.is_number())
- {
- result.x = static_cast<float>(xValue.get<double>());
- result.y = static_cast<float>(yValue.get<double>());
-
- return true;
- }
- }
-
- return false;
- };
-
- auto deserializeObjectId = [](const std::string& str)
- {
- auto separator = str.find_first_of(':');
- auto idStart = str.c_str() + ((separator != std::string::npos) ? separator + 1 : 0);
- auto id = reinterpret_cast<void*>(strtoull(idStart, nullptr, 10));
- if (str.compare(0, separator, "node") == 0)
- return ObjectId(NodeId(id));
- else if (str.compare(0, separator, "link") == 0)
- return ObjectId(LinkId(id));
- else if (str.compare(0, separator, "pin") == 0)
- return ObjectId(PinId(id));
- else
- // fallback to old format
- return ObjectId(NodeId(id)); //return ObjectId();
- };
-
- //auto& settingsObject = settingsValue.get<json::object>();
-
- auto& nodesValue = settingsValue["nodes"];
- if (nodesValue.is_object())
- {
- for (auto& node : nodesValue.get<json::object>())
- {
- auto id = deserializeObjectId(node.first.c_str()).AsNodeId();
-
- auto nodeSettings = result.FindNode(id);
- if (!nodeSettings)
- nodeSettings = result.AddNode(id);
-
- NodeSettings::Parse(node.second, *nodeSettings);
- }
- }
-
- auto& selectionValue = settingsValue["selection"];
- if (selectionValue.is_array())
- {
- const auto selectionArray = selectionValue.get<json::array>();
-
- result.m_Selection.reserve(selectionArray.size());
- result.m_Selection.resize(0);
- for (auto& selection : selectionArray)
- {
- if (selection.is_string())
- result.m_Selection.push_back(deserializeObjectId(selection.get<json::string>()));
- }
- }
-
- auto& viewValue = settingsValue["view"];
- if (viewValue.is_object())
- {
- auto& viewScrollValue = viewValue["scroll"];
- auto& viewZoomValue = viewValue["zoom"];
-
- if (!tryParseVector(viewScrollValue, result.m_ViewScroll))
- 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);
-
- return true;
-}
-
-
-
-//------------------------------------------------------------------------------
-//
-// Animation
-//
-//------------------------------------------------------------------------------
-ed::Animation::Animation(EditorContext* editor):
- Editor(editor),
- m_State(Stopped),
- m_Time(0.0f),
- m_Duration(0.0f)
-{
-}
-
-ed::Animation::~Animation()
-{
- Stop();
-}
-
-void ed::Animation::Play(float duration)
-{
- if (IsPlaying())
- Stop();
-
- m_State = Playing;
- if (duration < 0)
- duration = 0.0f;
-
- m_Time = 0.0f;
- m_Duration = duration;
-
- OnPlay();
-
- Editor->RegisterAnimation(this);
-
- if (duration == 0.0f)
- Finish();
-}
-
-void ed::Animation::Stop()
-{
- if (!IsPlaying())
- return;
-
- m_State = Stopped;
-
- Editor->UnregisterAnimation(this);
-
- OnStop();
-}
-
-void ed::Animation::Finish()
-{
- if (!IsPlaying())
- return;
-
- OnFinish();
-
- Stop();
-}
-
-void ed::Animation::Update()
-{
- if (!IsPlaying())
- return;
-
- m_Time += ImMax(0.0f, ImGui::GetIO().DeltaTime);
- if (m_Time < m_Duration)
- {
- const float progress = GetProgress();
- OnUpdate(progress);
- }
- else
- {
- OnFinish();
- Stop();
- }
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Navigate Animation
-//
-//------------------------------------------------------------------------------
-ed::NavigateAnimation::NavigateAnimation(EditorContext* editor, NavigateAction& scrollAction):
- Animation(editor),
- Action(scrollAction)
-{
-}
-
-void ed::NavigateAnimation::NavigateTo(const ImRect& target, float duration)
-{
- Stop();
-
- m_Start = Action.GetViewRect();
- m_Target = target;
-
- // Skip tiny animations
- auto minoffset = m_Target.Min - m_Start.Min;
- auto maxOffset = m_Target.Max - m_Start.Max;
- auto epsilon = 1e-4f;
- if (ImFabs(minoffset.x) < epsilon && ImFabs(minoffset.y) < epsilon &&
- ImFabs(maxOffset.x) < epsilon && ImFabs(maxOffset.y) < epsilon)
- {
- duration = 0;
- }
-
- Play(duration);
-}
-
-void ed::NavigateAnimation::OnUpdate(float progress)
-{
- ImRect current;
- current.Min = ImEasing::EaseOutQuad(m_Start.Min, m_Target.Min - m_Start.Min, progress);
- current.Max = ImEasing::EaseOutQuad(m_Start.Max, m_Target.Max - m_Start.Max, progress);
- Action.SetViewRect(current);
-}
-
-void ed::NavigateAnimation::OnStop()
-{
- Editor->MakeDirty(SaveReasonFlags::Navigation);
-}
-
-void ed::NavigateAnimation::OnFinish()
-{
- Action.SetViewRect(m_Target);
-
- Editor->MakeDirty(SaveReasonFlags::Navigation);
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Flow Animation
-//
-//------------------------------------------------------------------------------
-ed::FlowAnimation::FlowAnimation(FlowAnimationController* controller):
- Animation(controller->Editor),
- Controller(controller),
- m_Link(nullptr),
- m_Offset(0.0f),
- m_PathLength(0.0f)
-{
-}
-
-void ed::FlowAnimation::Flow(ed::Link* link, float markerDistance, float speed, float duration)
-{
- Stop();
-
- if (m_Link != link)
- {
- m_Offset = 0.0f;
- ClearPath();
- }
-
- if (m_MarkerDistance != markerDistance)
- ClearPath();
-
- m_MarkerDistance = markerDistance;
- m_Speed = speed;
- m_Link = link;
-
- Play(duration);
-}
-
-void ed::FlowAnimation::Draw(ImDrawList* drawList)
-{
- if (!IsPlaying() || !IsLinkValid() || !m_Link->IsVisible())
- return;
-
- if (!IsPathValid())
- UpdatePath();
-
- m_Offset = fmodf(m_Offset, m_MarkerDistance);
- if (m_Offset < 0)
- m_Offset += m_MarkerDistance;
-
- const auto progress = GetProgress();
-
- const auto flowAlpha = 1.0f - progress * progress;
- const auto flowColor = Editor->GetColor(StyleColor_Flow, flowAlpha);
- //const auto flowPath = Link->GetCurve();
-
- m_Link->Draw(drawList, flowColor, 2.0f);
-
- if (IsPathValid())
- {
- //Offset = 0;
-
- const auto markerAlpha = powf(1.0f - progress, 0.35f);
- const auto markerRadius = 4.0f * (1.0f - progress) + 2.0f;
- const auto markerColor = Editor->GetColor(StyleColor_FlowMarker, markerAlpha);
-
- for (float d = m_Offset; d < m_PathLength; d += m_MarkerDistance)
- drawList->AddCircleFilled(SamplePath(d), markerRadius, markerColor);
- }
-}
-
-bool ed::FlowAnimation::IsLinkValid() const
-{
- return m_Link && m_Link->m_IsLive;
-}
-
-bool ed::FlowAnimation::IsPathValid() const
-{
- return m_Path.size() > 1 && m_PathLength > 0.0f && m_Link->m_Start == m_LastStart && m_Link->m_End == m_LastEnd;
-}
-
-void ed::FlowAnimation::UpdatePath()
-{
- if (!IsLinkValid())
- {
- ClearPath();
- return;
- }
-
- const auto curve = m_Link->GetCurve();
-
- m_LastStart = m_Link->m_Start;
- m_LastEnd = m_Link->m_End;
- m_PathLength = ImCubicBezierLength(curve.P0, curve.P1, curve.P2, curve.P3);
-
- auto collectPointsCallback = [this](ImCubicBezierFixedStepSample& result)
- {
- m_Path.push_back(CurvePoint{ result.Length, result.Point });
- };
-
- const auto step = ImMax(m_MarkerDistance * 0.5f, 15.0f);
-
- m_Path.resize(0);
- ImCubicBezierFixedStep(collectPointsCallback, curve, step, false, 0.5f, 0.001f);
-}
-
-void ed::FlowAnimation::ClearPath()
-{
- vector<CurvePoint>().swap(m_Path);
- m_PathLength = 0.0f;
-}
-
-ImVec2 ed::FlowAnimation::SamplePath(float distance) const
-{
- //distance = ImMax(0.0f, std::min(distance, PathLength));
-
- auto endPointIt = std::find_if(m_Path.begin(), m_Path.end(), [distance](const CurvePoint& p) { return distance < p.Distance; });
- if (endPointIt == m_Path.end())
- endPointIt = m_Path.end() - 1;
- else if (endPointIt == m_Path.begin())
- endPointIt = m_Path.begin() + 1;
-
- const auto& start = endPointIt[-1];
- const auto& end = *endPointIt;
- const auto t = (distance - start.Distance) / (end.Distance - start.Distance);
-
- return start.Point + (end.Point - start.Point) * t;
-}
-
-void ed::FlowAnimation::OnUpdate(float progress)
-{
- IM_UNUSED(progress);
-
- m_Offset += m_Speed * ImGui::GetIO().DeltaTime;
-}
-
-void ed::FlowAnimation::OnStop()
-{
- Controller->Release(this);
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Flow Animation Controller
-//
-//------------------------------------------------------------------------------
-ed::FlowAnimationController::FlowAnimationController(EditorContext* editor):
- AnimationController(editor)
-{
-}
-
-ed::FlowAnimationController::~FlowAnimationController()
-{
- for (auto animation : m_Animations)
- delete animation;
-}
-
-void ed::FlowAnimationController::Flow(Link* link, FlowDirection direction)
-{
- if (!link || !link->m_IsLive)
- return;
-
- auto& editorStyle = GetStyle();
-
- auto animation = GetOrCreate(link);
-
- 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)
-{
- if (m_Animations.empty())
- return;
-
- drawList->ChannelsSetCurrent(c_LinkChannel_Flow);
-
- for (auto animation : m_Animations)
- animation->Draw(drawList);
-}
-
-ed::FlowAnimation* ed::FlowAnimationController::GetOrCreate(Link* link)
-{
- // Return live animation which match target link
- {
- auto animationIt = std::find_if(m_Animations.begin(), m_Animations.end(), [link](FlowAnimation* animation) { return animation->m_Link == link; });
- if (animationIt != m_Animations.end())
- return *animationIt;
- }
-
- // There are no live animations for target link, try to reuse inactive old one
- if (!m_FreePool.empty())
- {
- auto animation = m_FreePool.back();
- m_FreePool.pop_back();
- return animation;
- }
-
- // Cache miss, allocate new one
- auto animation = new FlowAnimation(this);
- m_Animations.push_back(animation);
-
- return animation;
-}
-
-void ed::FlowAnimationController::Release(FlowAnimation* animation)
-{
- IM_UNUSED(animation);
-}
-
-
-
-//------------------------------------------------------------------------------
-//
-// Navigate Action
-//
-//------------------------------------------------------------------------------
-const float ed::NavigateAction::s_ZoomLevels[] =
-{
- 0.1f, 0.15f, 0.20f, 0.25f, 0.33f, 0.5f, 0.75f, 1.0f, 1.25f, 1.50f, 2.0f, 2.5f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f
-};
-
-const int ed::NavigateAction::s_ZoomLevelCount = sizeof(s_ZoomLevels) / sizeof(*s_ZoomLevels);
-
-ed::NavigateAction::NavigateAction(EditorContext* editor, ImGuiEx::Canvas& canvas):
- EditorAction(editor),
- m_IsActive(false),
- m_Zoom(1),
- m_VisibleRect(),
- m_Scroll(0, 0),
- m_ScrollStart(0, 0),
- m_ScrollDelta(0, 0),
- m_Canvas(canvas),
- m_WindowScreenPos(0, 0),
- m_WindowScreenSize(0, 0),
- m_Animation(editor, *this),
- m_Reason(NavigationReason::Unknown),
- m_LastSelectionId(0),
- m_LastObject(nullptr),
- m_MovingOverEdge(false),
- m_MoveScreenOffset(0, 0)
-{
-}
-
-ed::EditorAction::AcceptResult ed::NavigateAction::Accept(const Control& control)
-{
- IM_ASSERT(!m_IsActive);
-
- if (m_IsActive)
- return False;
-
- if (Editor->CanAcceptUserInput() /*&& !ImGui::IsAnyItemActive()*/ && ImGui::IsMouseDragging(Editor->GetConfig().NavigateButtonIndex, 0.0f))
- {
- m_IsActive = true;
- m_ScrollStart = m_Scroll;
- m_ScrollDelta = ImGui::GetMouseDragDelta(Editor->GetConfig().NavigateButtonIndex);
- m_Scroll = m_ScrollStart - m_ScrollDelta * m_Zoom;
- }
-
- auto& io = ImGui::GetIO();
-
- if (Editor->CanAcceptUserInput() && ImGui::IsKeyPressed(GetKeyIndexForF()) && Editor->AreShortcutsEnabled())
- {
- const auto zoomMode = io.KeyShift ? NavigateAction::ZoomMode::WithMargin : NavigateAction::ZoomMode::None;
-
- auto findHotObjectToZoom = [this, &control, &io]() -> Object*
- {
- if (control.HotObject)
- {
- if (auto pin = control.HotObject->AsPin())
- return pin->m_Node;
- else
- return control.HotObject;
- }
- else if (control.BackgroundHot)
- {
- auto node = Editor->FindNodeAt(io.MousePos);
- if (IsGroup(node))
- return node;
- }
-
- return nullptr;
- };
-
- bool navigateToContent = false;
- if (!Editor->GetSelectedObjects().empty())
- {
- if (m_Reason != NavigationReason::Selection || m_LastSelectionId != Editor->GetSelectionId() || (zoomMode != NavigateAction::ZoomMode::None))
- {
- m_LastSelectionId = Editor->GetSelectionId();
- NavigateTo(Editor->GetSelectionBounds(), zoomMode, -1.0f, NavigationReason::Selection);
- }
- else
- navigateToContent = true;
- }
- else if(auto hotObject = findHotObjectToZoom())
- {
- if (m_Reason != NavigationReason::Object || m_LastObject != hotObject || (zoomMode != NavigateAction::ZoomMode::None))
- {
- m_LastObject = hotObject;
- auto bounds = hotObject->GetBounds();
- NavigateTo(bounds, zoomMode, -1.0f, NavigationReason::Object);
- }
- else
- navigateToContent = true;
- }
- else
- navigateToContent = true;
-
- if (navigateToContent)
- 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 (m_DrawList)
- // m_DrawList->AddCircleFilled(io.MousePos, 4.0f, IM_COL32(255, 0, 255, 255));
-
- if (HandleZoom(control))
- return True;
-
- return m_IsActive ? True : False;
-}
-
-bool ed::NavigateAction::Process(const Control& control)
-{
- IM_UNUSED(control);
-
- if (!m_IsActive)
- return false;
-
- if (ImGui::IsMouseDragging(Editor->GetConfig().NavigateButtonIndex, 0.0f))
- {
- 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;
- }
- else
- {
- if (m_Scroll != m_ScrollStart)
- Editor->MakeDirty(SaveReasonFlags::Navigation);
-
- m_IsActive = false;
- }
-
- // #TODO: Handle zoom while scrolling
- // HandleZoom(control);
-
- return m_IsActive;
-}
-
-bool ed::NavigateAction::HandleZoom(const Control& control)
-{
- IM_UNUSED(control);
-
- const auto currentAction = Editor->GetCurrentAction();
- const auto allowOffscreen = currentAction && currentAction->IsDragging();
-
- auto& io = ImGui::GetIO();
-
- if (!io.MouseWheel || (!allowOffscreen && !Editor->IsHoveredWithoutOverlapp()))// && !ImGui::IsAnyItemActive())
- return false;
-
- auto savedScroll = m_Scroll;
- auto savedZoom = m_Zoom;
-
- m_Animation.Finish();
-
- auto mousePos = io.MousePos;
- auto steps = (int)io.MouseWheel;
- auto newZoom = MatchZoom(steps, s_ZoomLevels[steps < 0 ? 0 : s_ZoomLevelCount - 1]);
-
- auto oldView = GetView();
- m_Zoom = newZoom;
- auto newView = GetView();
-
- auto screenPos = m_Canvas.FromLocal(mousePos, oldView);
- auto canvasPos = m_Canvas.ToLocal(screenPos, newView);
-
- auto offset = (canvasPos - mousePos) * m_Zoom;
- auto targetScroll = m_Scroll - offset;
-
- 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_VisibleRect = visibleRect;
-
- Editor->MakeDirty(SaveReasonFlags::Navigation);
- }
-
- auto targetRect = m_Canvas.CalcViewRect(ImGuiEx::CanvasView(-targetScroll, newZoom));
-
- NavigateTo(targetRect, c_MouseZoomDuration, NavigationReason::MouseZoom);
-
- return true;
-}
-
-void ed::NavigateAction::ShowMetrics()
-{
- EditorAction::ShowMetrics();
-
- ImGui::Text("%s:", GetName());
- 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, ZoomMode zoomMode, float duration, NavigationReason reason)
-{
- if (ImRect_IsEmpty(bounds))
- return;
-
- if (duration < 0.0f)
- duration = GetStyle().ScrollDuration;
-
- if (zoomMode == ZoomMode::None)
- {
- auto viewRect = m_Canvas.ViewRect();
- auto viewRectCenter = viewRect.GetCenter();
- auto targetCenter = bounds.GetCenter();
-
- viewRect.Translate(targetCenter - viewRectCenter);
-
- NavigateTo(viewRect, duration, reason);
- }
- else
- {
- // Grow rect by 5% to leave some reasonable margin
- // from the edges of the canvas.
- auto rect = bounds;
-
- if (zoomMode == ZoomMode::WithMargin)
- {
- auto extend = ImMax(rect.GetWidth(), rect.GetHeight());
- rect.Expand(extend * c_NavigationZoomMargin * 0.5f);
- }
-
- NavigateTo(rect, duration, reason);
- }
-}
-
-void ed::NavigateAction::NavigateTo(const ImRect& target, float duration, NavigationReason reason)
-{
- m_Reason = reason;
-
- m_Animation.NavigateTo(target, duration);
-}
-
-void ed::NavigateAction::StopNavigation()
-{
- m_Animation.Stop();
-}
-
-void ed::NavigateAction::FinishNavigation()
-{
- m_Animation.Finish();
-}
-
-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 screenMousePos = io.MousePos;
- const auto screenRect = ImRect(ImGui::GetCursorScreenPos(), ImGui::GetCursorScreenPos() + canvasSize);
-
- // Mouse is over screen, do nothing
- if (screenRect.Contains(screenMousePos))
- return false;
-
- // 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);
-
- 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_Scroll = m_Scroll + relativeOffset;
-
- m_MoveScreenOffset = relativeOffset;
- m_MovingOverEdge = true;
-
- return true;
-}
-
-void ed::NavigateAction::StopMoveOverEdge()
-{
- if (m_MovingOverEdge)
- {
- Editor->MakeDirty(SaveReasonFlags::Navigation);
-
- m_MoveScreenOffset = ImVec2(0, 0);
- m_MovingOverEdge = false;
- }
-}
-
-void ed::NavigateAction::SetWindow(ImVec2 position, ImVec2 size)
-{
- m_WindowScreenPos = position;
- m_WindowScreenSize = size;
-}
-
-ImGuiEx::CanvasView ed::NavigateAction::GetView() const
-{
- return ImGuiEx::CanvasView(-m_Scroll, m_Zoom);
-}
-
-ImVec2 ed::NavigateAction::GetViewOrigin() const
-{
- return -m_Scroll;
-}
-
-float ed::NavigateAction::GetViewScale() const
-{
- return m_Zoom;
-}
-
-void ed::NavigateAction::SetViewRect(const ImRect& rect)
-{
- auto view = m_Canvas.CalcCenterView(rect);
- m_Scroll = -view.Origin;
- m_Zoom = view.Scale;
-}
-
-ImRect ed::NavigateAction::GetViewRect() const
-{
- return m_Canvas.CalcViewRect(GetView());
-}
-
-float ed::NavigateAction::MatchZoom(int steps, float fallbackZoom)
-{
- auto currentZoomIndex = MatchZoomIndex(steps);
- if (currentZoomIndex < 0)
- return fallbackZoom;
-
- auto currentZoom = s_ZoomLevels[currentZoomIndex];
- if (fabsf(currentZoom - m_Zoom) > 0.001f)
- return currentZoom;
-
- auto newIndex = currentZoomIndex + steps;
- if (newIndex >= 0 && newIndex < s_ZoomLevelCount)
- return s_ZoomLevels[newIndex];
- else
- return fallbackZoom;
-}
-
-int ed::NavigateAction::MatchZoomIndex(int direction)
-{
- int bestIndex = -1;
- float bestDistance = 0.0f;
-
- for (int i = 0; i < s_ZoomLevelCount; ++i)
- {
- auto distance = fabsf(s_ZoomLevels[i] - m_Zoom);
- if (distance < bestDistance || bestIndex < 0)
- {
- bestDistance = distance;
- bestIndex = i;
- }
- }
-
- if (bestDistance > 0.001f)
- {
- if (direction > 0)
- {
- ++bestIndex;
-
- if (bestIndex >= s_ZoomLevelCount)
- bestIndex = s_ZoomLevelCount - 1;
- }
- else if (direction < 0)
- {
- --bestIndex;
-
- if (bestIndex < 0)
- bestIndex = 0;
- }
- }
-
- return bestIndex;
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Size Action
-//
-//------------------------------------------------------------------------------
-ed::SizeAction::SizeAction(EditorContext* editor):
- EditorAction(editor),
- m_IsActive(false),
- m_Clean(false),
- m_SizedNode(nullptr),
- m_Pivot(NodeRegion::None),
- m_Cursor(ImGuiMouseCursor_Arrow)
-{
-}
-
-ed::EditorAction::AcceptResult ed::SizeAction::Accept(const Control& control)
-{
- IM_ASSERT(!m_IsActive);
-
- if (m_IsActive)
- return False;
-
- 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));
-
- auto pivot = GetRegion(control.ActiveNode);
- if (pivot != NodeRegion::Header && pivot != NodeRegion::Center)
- {
- m_StartBounds = control.ActiveNode->m_Bounds;
- m_StartGroupBounds = control.ActiveNode->m_GroupBounds;
- m_LastSize = control.ActiveNode->m_Bounds.GetSize();
- m_MinimumSize = ImVec2(0, 0);
- m_LastDragOffset = ImVec2(0, 0);
- m_Pivot = pivot;
- m_Cursor = ChooseCursor(m_Pivot);
- m_SizedNode = control.ActiveNode;
- m_IsActive = true;
- }
- }
- else if (control.HotNode && IsGroup(control.HotNode))
- {
- m_Cursor = ChooseCursor(GetRegion(control.HotNode));
- return Possible;
- }
-
- return m_IsActive ? True : False;
-}
-
-bool ed::SizeAction::Process(const Control& control)
-{
- if (m_Clean)
- {
- m_Clean = false;
-
- if (m_SizedNode->m_Bounds.Min != m_StartBounds.Min || m_SizedNode->m_GroupBounds.Min != m_StartGroupBounds.Min)
- Editor->MakeDirty(SaveReasonFlags::Position | SaveReasonFlags::User, m_SizedNode);
-
- if (m_SizedNode->m_Bounds.GetSize() != m_StartBounds.GetSize() || m_SizedNode->m_GroupBounds.GetSize() != m_StartGroupBounds.GetSize())
- Editor->MakeDirty(SaveReasonFlags::Size | SaveReasonFlags::User, m_SizedNode);
-
- m_SizedNode = nullptr;
- }
-
- if (!m_IsActive)
- return false;
-
- if (control.ActiveNode == m_SizedNode)
- {
- const auto dragOffset = (control.ActiveNode == m_SizedNode) ? ImGui::GetMouseDragDelta(0, 0.0f) : m_LastDragOffset;
- m_LastDragOffset = dragOffset;
-
- if (m_MinimumSize.x == 0.0f && m_LastSize.x != m_SizedNode->m_Bounds.GetWidth())
- m_MinimumSize.x = m_SizedNode->m_Bounds.GetWidth();
- if (m_MinimumSize.y == 0.0f && m_LastSize.y != m_SizedNode->m_Bounds.GetHeight())
- m_MinimumSize.y = m_SizedNode->m_Bounds.GetHeight();
-
- auto minimumSize = ImMax(m_MinimumSize, m_StartBounds.GetSize() - m_StartGroupBounds.GetSize());
-
-
- auto newBounds = m_StartBounds;
-
- if ((m_Pivot & NodeRegion::Top) == NodeRegion::Top)
- newBounds.Min.y = ImMin(newBounds.Max.y - minimumSize.y, Editor->AlignPointToGrid(newBounds.Min.y + dragOffset.y));
- if ((m_Pivot & NodeRegion::Bottom) == NodeRegion::Bottom)
- newBounds.Max.y = ImMax(newBounds.Min.y + minimumSize.y, Editor->AlignPointToGrid(newBounds.Max.y + dragOffset.y));
- if ((m_Pivot & NodeRegion::Left) == NodeRegion::Left)
- newBounds.Min.x = ImMin(newBounds.Max.x - minimumSize.x, Editor->AlignPointToGrid(newBounds.Min.x + dragOffset.x));
- if ((m_Pivot & NodeRegion::Right) == NodeRegion::Right)
- newBounds.Max.x = ImMax(newBounds.Min.x + minimumSize.x, Editor->AlignPointToGrid(newBounds.Max.x + dragOffset.x));
-
- newBounds.Floor();
-
- m_LastSize = newBounds.GetSize();
-
- m_SizedNode->m_Bounds = newBounds;
- m_SizedNode->m_GroupBounds = newBounds;
- m_SizedNode->m_GroupBounds.Min.x -= m_StartBounds.Min.x - m_StartGroupBounds.Min.x;
- m_SizedNode->m_GroupBounds.Min.y -= m_StartBounds.Min.y - m_StartGroupBounds.Min.y;
- m_SizedNode->m_GroupBounds.Max.x -= m_StartBounds.Max.x - m_StartGroupBounds.Max.x;
- m_SizedNode->m_GroupBounds.Max.y -= m_StartBounds.Max.y - m_StartGroupBounds.Max.y;
- }
- else if (!control.ActiveNode)
- {
- m_Clean = true;
- m_IsActive = false;
- return true;
- }
-
- return m_IsActive;
-}
-
-void ed::SizeAction::ShowMetrics()
-{
- EditorAction::ShowMetrics();
-
- auto getObjectName = [](Object* object)
- {
- if (!object) return "";
- else if (object->AsNode()) return "Node";
- else if (object->AsPin()) return "Pin";
- else if (object->AsLink()) return "Link";
- else return "";
- };
-
- ImGui::Text("%s:", GetName());
- ImGui::Text(" Active: %s", m_IsActive ? "yes" : "no");
- ImGui::Text(" Node: %s (%p)", getObjectName(m_SizedNode), m_SizedNode ? m_SizedNode->m_ID.AsPointer() : nullptr);
- if (m_SizedNode && m_IsActive)
- {
- ImGui::Text(" Bounds: { x=%g y=%g w=%g h=%g }", m_SizedNode->m_Bounds.Min.x, m_SizedNode->m_Bounds.Min.y, m_SizedNode->m_Bounds.GetWidth(), m_SizedNode->m_Bounds.GetHeight());
- ImGui::Text(" Group Bounds: { x=%g y=%g w=%g h=%g }", m_SizedNode->m_GroupBounds.Min.x, m_SizedNode->m_GroupBounds.Min.y, m_SizedNode->m_GroupBounds.GetWidth(), m_SizedNode->m_GroupBounds.GetHeight());
- ImGui::Text(" Start Bounds: { x=%g y=%g w=%g h=%g }", m_StartBounds.Min.x, m_StartBounds.Min.y, m_StartBounds.GetWidth(), m_StartBounds.GetHeight());
- ImGui::Text(" Start Group Bounds: { x=%g y=%g w=%g h=%g }", m_StartGroupBounds.Min.x, m_StartGroupBounds.Min.y, m_StartGroupBounds.GetWidth(), m_StartGroupBounds.GetHeight());
- ImGui::Text(" Minimum Size: { w=%g h=%g }", m_MinimumSize.x, m_MinimumSize.y);
- ImGui::Text(" Last Size: { w=%g h=%g }", m_LastSize.x, m_LastSize.y);
- }
-}
-
-ed::NodeRegion ed::SizeAction::GetRegion(Node* node)
-{
- return node->GetRegion(ImGui::GetMousePos());
-}
-
-ImGuiMouseCursor ed::SizeAction::ChooseCursor(NodeRegion region)
-{
- switch (region)
- {
- default:
- case NodeRegion::Center:
- return ImGuiMouseCursor_Arrow;
-
- case NodeRegion::Top:
- case NodeRegion::Bottom:
- return ImGuiMouseCursor_ResizeNS;
-
- case NodeRegion::Left:
- case NodeRegion::Right:
- return ImGuiMouseCursor_ResizeEW;
-
- case NodeRegion::TopLeft:
- case NodeRegion::BottomRight:
- return ImGuiMouseCursor_ResizeNWSE;
-
- case NodeRegion::TopRight:
- case NodeRegion::BottomLeft:
- return ImGuiMouseCursor_ResizeNESW;
- }
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Drag Action
-//
-//------------------------------------------------------------------------------
-ed::DragAction::DragAction(EditorContext* editor):
- EditorAction(editor),
- m_IsActive(false),
- m_Clear(false),
- m_DraggedObject(nullptr)
-{
-}
-
-ed::EditorAction::AcceptResult ed::DragAction::Accept(const Control& control)
-{
- IM_ASSERT(!m_IsActive);
-
- if (m_IsActive)
- return False;
-
- if (Editor->CanAcceptUserInput() && control.ActiveObject && ImGui::IsMouseDragging(Editor->GetConfig().DragButtonIndex))
- {
- if (!control.ActiveObject->AcceptDrag())
- return False;
-
- m_DraggedObject = control.ActiveObject;
-
- m_Objects.resize(0);
- m_Objects.push_back(m_DraggedObject);
-
- if (Editor->IsSelected(m_DraggedObject))
- {
- for (auto selectedObject : Editor->GetSelectedObjects())
- if (auto selectedNode = selectedObject->AsNode())
- if (selectedNode != m_DraggedObject && selectedNode->AcceptDrag())
- m_Objects.push_back(selectedNode);
- }
-
- auto& io = ImGui::GetIO();
- if (!io.KeyShift)
- {
- std::vector<Node*> groupedNodes;
- for (auto object : m_Objects)
- if (auto node = object->AsNode())
- node->GetGroupedNodes(groupedNodes, true);
-
- auto isAlreadyPicked = [this](Node* node)
- {
- return std::find(m_Objects.begin(), m_Objects.end(), node) != m_Objects.end();
- };
-
- for (auto candidate : groupedNodes)
- if (!isAlreadyPicked(candidate) && candidate->AcceptDrag())
- m_Objects.push_back(candidate);
- }
-
- m_IsActive = true;
- }
- else if (control.HotNode && IsGroup(control.HotNode) && control.HotNode->GetRegion(ImGui::GetMousePos()) == NodeRegion::Header)
- {
- return Possible;
- }
-
- return m_IsActive ? True : False;
-}
-
-bool ed::DragAction::Process(const Control& control)
-{
- if (m_Clear)
- {
- m_Clear = false;
-
- for (auto object : m_Objects)
- {
- if (object->EndDrag())
- Editor->MakeDirty(SaveReasonFlags::Position | SaveReasonFlags::User, object->AsNode());
- }
-
- m_Objects.resize(0);
-
- m_DraggedObject = nullptr;
- }
-
- if (!m_IsActive)
- return false;
-
- if (control.ActiveObject == m_DraggedObject)
- {
- auto dragOffset = ImGui::GetMouseDragDelta(Editor->GetConfig().DragButtonIndex, 0.0f);
-
- auto draggedOrigin = m_DraggedObject->DragStartLocation();
- auto alignPivot = ImVec2(0, 0);
-
- // TODO: Move this experimental alignment to closes pivot out of internals to node API
- if (auto draggedNode = m_DraggedObject->AsNode())
- {
- float x = FLT_MAX;
- float y = FLT_MAX;
-
- auto testPivot = [this, &x, &y, &draggedOrigin, &dragOffset, &alignPivot](const ImVec2& pivot)
- {
- auto initial = draggedOrigin + dragOffset + pivot;
- auto candidate = Editor->AlignPointToGrid(initial) - draggedOrigin - pivot;
-
- if (ImFabs(candidate.x) < ImFabs(ImMin(x, FLT_MAX)))
- {
- x = candidate.x;
- alignPivot.x = pivot.x;
- }
-
- if (ImFabs(candidate.y) < ImFabs(ImMin(y, FLT_MAX)))
- {
- y = candidate.y;
- alignPivot.y = pivot.y;
- }
- };
-
- for (auto pin = draggedNode->m_LastPin; pin; pin = pin->m_PreviousPin)
- {
- auto pivot = pin->m_Pivot.GetCenter() - draggedNode->m_Bounds.Min;
- testPivot(pivot);
- }
-
- //testPivot(point(0, 0));
- }
-
- auto alignedOffset = Editor->AlignPointToGrid(draggedOrigin + dragOffset + alignPivot) - draggedOrigin - alignPivot;
-
- if (!ImGui::GetIO().KeyAlt)
- dragOffset = alignedOffset;
-
- for (auto object : m_Objects)
- object->UpdateDrag(dragOffset);
- }
- else if (!control.ActiveObject)
- {
- m_Clear = true;
-
- m_IsActive = false;
- return true;
- }
-
- return m_IsActive;
-}
-
-void ed::DragAction::ShowMetrics()
-{
- EditorAction::ShowMetrics();
-
- auto getObjectName = [](Object* object)
- {
- if (!object) return "";
- else if (object->AsNode()) return "Node";
- else if (object->AsPin()) return "Pin";
- else if (object->AsLink()) return "Link";
- else return "";
- };
-
- ImGui::Text("%s:", GetName());
- ImGui::Text(" Active: %s", m_IsActive ? "yes" : "no");
- ImGui::Text(" Node: %s (%p)", getObjectName(m_DraggedObject), m_DraggedObject ? m_DraggedObject->ID().AsPointer() : nullptr);
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Select Action
-//
-//------------------------------------------------------------------------------
-ed::SelectAction::SelectAction(EditorContext* editor):
- EditorAction(editor),
- m_IsActive(false),
- m_SelectGroups(false),
- m_SelectLinkMode(false),
- m_CommitSelection(false),
- m_StartPoint(),
- m_Animation(editor)
-{
-}
-
-ed::EditorAction::AcceptResult ed::SelectAction::Accept(const Control& control)
-{
- IM_ASSERT(!m_IsActive);
-
- if (m_IsActive)
- return False;
-
- auto& io = ImGui::GetIO();
- m_SelectGroups = io.KeyShift;
- m_SelectLinkMode = io.KeyAlt;
-
- m_SelectedObjectsAtStart.clear();
-
- if (Editor->CanAcceptUserInput() && control.BackgroundHot && ImGui::IsMouseDragging(Editor->GetConfig().SelectButtonIndex, 1))
- {
- m_IsActive = true;
- m_StartPoint = ImGui::GetMousePos();
- m_EndPoint = m_StartPoint;
-
- // Links and nodes cannot be selected together
- if ((m_SelectLinkMode && Editor->IsAnyNodeSelected()) ||
- (!m_SelectLinkMode && Editor->IsAnyLinkSelected()))
- {
- Editor->ClearSelection();
- }
-
- if (io.KeyCtrl)
- m_SelectedObjectsAtStart = Editor->GetSelectedObjects();
- }
- else if (control.BackgroundClicked)
- {
- Editor->ClearSelection();
- }
- else
- {
- Object* clickedObject = control.ClickedNode ? static_cast<Object*>(control.ClickedNode) : static_cast<Object*>(control.ClickedLink);
-
- if (clickedObject)
- {
- // Links and nodes cannot be selected together
- if ((clickedObject->AsLink() && Editor->IsAnyNodeSelected()) ||
- (clickedObject->AsNode() && Editor->IsAnyLinkSelected()))
- {
- Editor->ClearSelection();
- }
-
- if (io.KeyCtrl)
- Editor->ToggleObjectSelection(clickedObject);
- else
- Editor->SetSelectedObject(clickedObject);
- }
- }
-
- if (m_IsActive)
- m_Animation.Stop();
-
- return m_IsActive ? True : False;
-}
-
-bool ed::SelectAction::Process(const Control& control)
-{
- IM_UNUSED(control);
-
- if (m_CommitSelection)
- {
- Editor->ClearSelection();
- for (auto object : m_CandidateObjects)
- Editor->SelectObject(object);
-
- m_CandidateObjects.clear();
-
- m_CommitSelection = false;
- }
-
- if (!m_IsActive)
- return false;
-
- if (ImGui::IsMouseDragging(Editor->GetConfig().SelectButtonIndex, 0))
- {
- m_EndPoint = ImGui::GetMousePos();
-
- auto topLeft = ImVec2(std::min(m_StartPoint.x, m_EndPoint.x), std::min(m_StartPoint.y, m_EndPoint.y));
- auto bottomRight = ImVec2(ImMax(m_StartPoint.x, m_EndPoint.x), ImMax(m_StartPoint.y, m_EndPoint.y));
- auto rect = ImRect(topLeft, bottomRight);
- if (rect.GetWidth() <= 0)
- rect.Max.x = rect.Min.x + 1;
- if (rect.GetHeight() <= 0)
- rect.Max.y = rect.Min.y + 1;
-
- vector<Node*> nodes;
- vector<Link*> links;
-
- if (m_SelectLinkMode)
- {
- Editor->FindLinksInRect(rect, links);
- m_CandidateObjects.assign(links.begin(), links.end());
- }
- else
- {
- Editor->FindNodesInRect(rect, nodes);
- m_CandidateObjects.assign(nodes.begin(), nodes.end());
-
- if (m_SelectGroups)
- {
- auto endIt = std::remove_if(m_CandidateObjects.begin(), m_CandidateObjects.end(), [](Object* object) { return !IsGroup(object->AsNode()); });
- m_CandidateObjects.erase(endIt, m_CandidateObjects.end());
- }
- else
- {
- auto endIt = std::remove_if(m_CandidateObjects.begin(), m_CandidateObjects.end(), [](Object* object) { return IsGroup(object->AsNode()); });
- m_CandidateObjects.erase(endIt, m_CandidateObjects.end());
- }
- }
-
- m_CandidateObjects.insert(m_CandidateObjects.end(), m_SelectedObjectsAtStart.begin(), m_SelectedObjectsAtStart.end());
- std::sort(m_CandidateObjects.begin(), m_CandidateObjects.end());
- m_CandidateObjects.erase(std::unique(m_CandidateObjects.begin(), m_CandidateObjects.end()), m_CandidateObjects.end());
- }
- else
- {
- m_IsActive = false;
-
- m_Animation.Play(c_SelectionFadeOutDuration);
-
- m_CommitSelection = true;
-
- return true;
- }
-
- return m_IsActive;
-}
-
-void ed::SelectAction::ShowMetrics()
-{
- EditorAction::ShowMetrics();
-
- ImGui::Text("%s:", GetName());
- ImGui::Text(" Active: %s", m_IsActive ? "yes" : "no");
-}
-
-void ed::SelectAction::Draw(ImDrawList* drawList)
-{
- if (!m_IsActive && !m_Animation.IsPlaying())
- return;
-
- const auto alpha = m_Animation.IsPlaying() ? ImEasing::EaseOutQuad(1.0f, -1.0f, m_Animation.GetProgress()) : 1.0f;
-
- const auto fillColor = Editor->GetColor(m_SelectLinkMode ? StyleColor_LinkSelRect : StyleColor_NodeSelRect, alpha);
- const auto outlineColor = Editor->GetColor(m_SelectLinkMode ? StyleColor_LinkSelRectBorder : StyleColor_NodeSelRectBorder, alpha);
-
- drawList->ChannelsSetCurrent(c_BackgroundChannel_SelectionRect);
-
- auto min = ImVec2(std::min(m_StartPoint.x, m_EndPoint.x), std::min(m_StartPoint.y, m_EndPoint.y));
- auto max = ImVec2(ImMax(m_StartPoint.x, m_EndPoint.x), ImMax(m_StartPoint.y, m_EndPoint.y));
-
- drawList->AddRectFilled(min, max, fillColor);
- FringeScaleScope fringe(1.0f);
- drawList->AddRect(min, max, outlineColor);
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Context Menu Action
-//
-//------------------------------------------------------------------------------
-ed::ContextMenuAction::ContextMenuAction(EditorContext* editor):
- EditorAction(editor),
- m_CandidateMenu(Menu::None),
- m_CurrentMenu(Menu::None),
- m_ContextId()
-{
-}
-
-ed::EditorAction::AcceptResult ed::ContextMenuAction::Accept(const Control& control)
-{
- 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)
- {
- Menu candidateMenu = ContextMenuAction::None;
- ObjectId contextId;
-
- if (auto hotObejct = control.HotObject)
- {
- if (hotObejct->AsNode())
- candidateMenu = Node;
- else if (hotObejct->AsPin())
- candidateMenu = Pin;
- else if (hotObejct->AsLink())
- candidateMenu = Link;
-
- if (candidateMenu != None)
- contextId = hotObejct->ID();
- }
- else if (control.BackgroundHot)
- candidateMenu = Background;
-
- if (isPressed)
- {
- m_CandidateMenu = candidateMenu;
- m_ContextId = contextId;
- return Possible;
- }
- else if (isReleased && m_CandidateMenu == candidateMenu && m_ContextId == contextId)
- {
- m_CurrentMenu = m_CandidateMenu;
- m_CandidateMenu = ContextMenuAction::None;
- return True;
- }
- else
- {
- m_CandidateMenu = None;
- m_CurrentMenu = None;
- m_ContextId = ObjectId();
- return False;
- }
- }
-
- return False;
-}
-
-bool ed::ContextMenuAction::Process(const Control& control)
-{
- IM_UNUSED(control);
-
- m_CandidateMenu = None;
- m_CurrentMenu = None;
- m_ContextId = ObjectId();
- return false;
-}
-
-void ed::ContextMenuAction::Reject()
-{
- m_CandidateMenu = None;
- m_CurrentMenu = None;
- m_ContextId = ObjectId();
-}
-
-void ed::ContextMenuAction::ShowMetrics()
-{
- EditorAction::ShowMetrics();
-
- auto getMenuName = [](Menu menu)
- {
- switch (menu)
- {
- default:
- case None: return "None";
- case Node: return "Node";
- case Pin: return "Pin";
- case Link: return "Link";
- case Background: return "Background";
- }
- };
-
-
- ImGui::Text("%s:", GetName());
- ImGui::Text(" Menu: %s", getMenuName(m_CurrentMenu));
-}
-
-bool ed::ContextMenuAction::ShowNodeContextMenu(NodeId* nodeId)
-{
- if (m_CurrentMenu != Node)
- return false;
-
- *nodeId = m_ContextId.AsNodeId();
- Editor->SetUserContext();
- return true;
-}
-
-bool ed::ContextMenuAction::ShowPinContextMenu(PinId* pinId)
-{
- if (m_CurrentMenu != Pin)
- return false;
-
- *pinId = m_ContextId.AsPinId();
- Editor->SetUserContext();
- return true;
-}
-
-bool ed::ContextMenuAction::ShowLinkContextMenu(LinkId* linkId)
-{
- if (m_CurrentMenu != Link)
- return false;
-
- *linkId = m_ContextId.AsLinkId();
- Editor->SetUserContext();
- return true;
-}
-
-bool ed::ContextMenuAction::ShowBackgroundContextMenu()
-{
- if (m_CurrentMenu != Background)
- return false;
-
- Editor->SetUserContext();
- return true;
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Cut/Copy/Paste Action
-//
-//------------------------------------------------------------------------------
-ed::ShortcutAction::ShortcutAction(EditorContext* editor):
- EditorAction(editor),
- m_IsActive(false),
- m_InAction(false),
- m_CurrentAction(Action::None),
- m_Context()
-{
-}
-
-ed::EditorAction::AcceptResult ed::ShortcutAction::Accept(const Control& control)
-{
- if (!Editor->IsFocused() || !Editor->AreShortcutsEnabled())
- return False;
-
- Action candidateAction = None;
-
- auto& io = ImGui::GetIO();
- if (io.KeyCtrl && !io.KeyShift && !io.KeyAlt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_X)))
- candidateAction = Cut;
- if (io.KeyCtrl && !io.KeyShift && !io.KeyAlt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
- candidateAction = Copy;
- if (io.KeyCtrl && !io.KeyShift && !io.KeyAlt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_V)))
- candidateAction = Paste;
- if (io.KeyCtrl && !io.KeyShift && !io.KeyAlt && ImGui::IsKeyPressed(GetKeyIndexForD()))
- candidateAction = Duplicate;
- if (!io.KeyCtrl && !io.KeyShift && !io.KeyAlt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space)))
- candidateAction = CreateNode;
-
- if (candidateAction != None)
- {
- if (candidateAction != Paste && candidateAction != CreateNode)
- {
- auto& selection = Editor->GetSelectedObjects();
- if (!selection.empty())
- {
- // #TODO: Find a way to simplify logic.
-
- m_Context.assign(selection.begin(), selection.end());
-
- // Expand groups
- vector<Node*> extra;
- for (auto object : m_Context)
- {
- auto node = object->AsNode();
- if (IsGroup(node))
- node->GetGroupedNodes(extra, true);
- }
-
- // Apply groups and remove duplicates
- if (!extra.empty())
- {
- m_Context.insert(m_Context.end(), extra.begin(), extra.end());
- std::sort(m_Context.begin(), m_Context.end());
- m_Context.erase(std::unique(m_Context.begin(), m_Context.end()), m_Context.end());
- }
- }
- else if (control.HotObject && control.HotObject->IsSelectable() && !IsGroup(control.HotObject->AsNode()))
- {
- m_Context.push_back(control.HotObject);
- }
-
- if (m_Context.empty())
- return False;
-
- // Does copying only links make sense?
- //const auto hasOnlyLinks = std::all_of(Context.begin(), Context.end(), [](Object* object) { return object->AsLink() != nullptr; });
- //if (hasOnlyLinks)
- // return False;
-
- // If no links are selected, pick all links between nodes within context
- const auto hasAnyLinks = std::any_of(m_Context.begin(), m_Context.end(), [](Object* object) { return object->AsLink() != nullptr; });
- if (!hasAnyLinks && m_Context.size() > 1) // one node cannot make connection to anything
- {
- // Collect nodes in sorted vector viable for binary search
- std::vector<ObjectWrapper<Node>> nodes;
-
- nodes.reserve(m_Context.size());
- std::for_each(m_Context.begin(), m_Context.end(), [&nodes](Object* object) { if (auto node = object->AsNode()) nodes.push_back({node->m_ID, node}); });
-
- std::sort(nodes.begin(), nodes.end());
-
- auto isNodeInContext = [&nodes](NodeId nodeId)
- {
- return std::binary_search(nodes.begin(), nodes.end(), ObjectWrapper<Node>{nodeId, nullptr});
- };
-
- // Collect links connected to nodes and drop those reaching out of context
- std::vector<Link*> links;
-
- for (auto node : nodes)
- Editor->FindLinksForNode(node.m_ID, links, true);
-
- // Remove duplicates
- std::sort(links.begin(), links.end());
- links.erase(std::unique(links.begin(), links.end()), links.end());
-
- // Drop out of context links
- links.erase(std::remove_if(links.begin(), links.end(), [&isNodeInContext](Link* link)
- {
- return !isNodeInContext(link->m_StartPin->m_Node->m_ID) || !isNodeInContext(link->m_EndPin->m_Node->m_ID);
- }), links.end());
-
- // Append links and remove duplicates
- m_Context.insert(m_Context.end(), links.begin(), links.end());
- }
- }
- else
- m_Context.resize(0);
-
- m_IsActive = true;
- m_CurrentAction = candidateAction;
-
- return True;
- }
-
- return False;
-}
-
-bool ed::ShortcutAction::Process(const Control& control)
-{
- IM_UNUSED(control);
-
- m_IsActive = false;
- m_CurrentAction = None;
- m_Context.resize(0);
- return false;
-}
-
-void ed::ShortcutAction::Reject()
-{
- m_IsActive = false;
- m_CurrentAction = None;
- m_Context.resize(0);
-}
-
-void ed::ShortcutAction::ShowMetrics()
-{
- EditorAction::ShowMetrics();
-
- auto getActionName = [](Action action)
- {
- switch (action)
- {
- default:
- case None: return "None";
- case Cut: return "Cut";
- case Copy: return "Copy";
- case Paste: return "Paste";
- case Duplicate: return "Duplicate";
- case CreateNode: return "CreateNode";
- }
- };
-
- ImGui::Text("%s:", GetName());
- ImGui::Text(" Action: %s", getActionName(m_CurrentAction));
-}
-
-bool ed::ShortcutAction::Begin()
-{
- if (m_IsActive)
- m_InAction = true;
- return m_IsActive;
-}
-
-void ed::ShortcutAction::End()
-{
- if (m_IsActive)
- m_InAction = false;
-}
-
-bool ed::ShortcutAction::AcceptCut()
-{
- IM_ASSERT(m_InAction);
- return m_CurrentAction == Cut;
-}
-
-bool ed::ShortcutAction::AcceptCopy()
-{
- IM_ASSERT(m_InAction);
- return m_CurrentAction == Copy;
-}
-
-bool ed::ShortcutAction::AcceptPaste()
-{
- IM_ASSERT(m_InAction);
- return m_CurrentAction == Paste;
-}
-
-bool ed::ShortcutAction::AcceptDuplicate()
-{
- IM_ASSERT(m_InAction);
- return m_CurrentAction == Duplicate;
-}
-
-bool ed::ShortcutAction::AcceptCreateNode()
-{
- IM_ASSERT(m_InAction);
- return m_CurrentAction == CreateNode;
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Create Item Action
-//
-//------------------------------------------------------------------------------
-ed::CreateItemAction::CreateItemAction(EditorContext* editor):
- EditorAction(editor),
- m_InActive(false),
- m_NextStage(None),
- m_CurrentStage(None),
- m_ItemType(NoItem),
- m_UserAction(Unknown),
- m_LinkColor(IM_COL32_WHITE),
- m_LinkThickness(1.0f),
- m_LinkStart(nullptr),
- m_LinkEnd(nullptr),
-
- m_IsActive(false),
- m_DraggedPin(nullptr),
-
- m_IsInGlobalSpace(false)
-{
-}
-
-ed::EditorAction::AcceptResult ed::CreateItemAction::Accept(const Control& control)
-{
- IM_ASSERT(!m_IsActive);
-
- if (m_IsActive)
- return EditorAction::False;
-
- if (control.ActivePin && ImGui::IsMouseDragging(Editor->GetConfig().DragButtonIndex))
- {
- m_DraggedPin = control.ActivePin;
- DragStart(m_DraggedPin);
-
- Editor->ClearSelection();
- }
- else if (control.HotPin)
- {
- return EditorAction::Possible;
- }
- else
- return EditorAction::False;
-
- m_IsActive = true;
-
- return EditorAction::True;
-}
-
-bool ed::CreateItemAction::Process(const Control& control)
-{
- IM_ASSERT(m_IsActive);
-
- if (!m_IsActive)
- return false;
-
- if (m_DraggedPin && control.ActivePin == m_DraggedPin && (m_CurrentStage == Possible))
- {
- const auto draggingFromSource = (m_DraggedPin->m_Kind == PinKind::Output);
-
- ed::Pin cursorPin(Editor, 0, draggingFromSource ? PinKind::Input : PinKind::Output);
- cursorPin.m_Pivot = ImRect(ImGui::GetMousePos(), ImGui::GetMousePos());
- cursorPin.m_Dir = -m_DraggedPin->m_Dir;
- cursorPin.m_Strength = m_DraggedPin->m_Strength;
-
- ed::Link candidate(Editor, 0);
- candidate.m_Color = m_LinkColor;
- candidate.m_StartPin = draggingFromSource ? m_DraggedPin : &cursorPin;
- candidate.m_EndPin = draggingFromSource ? &cursorPin : m_DraggedPin;
-
- ed::Pin*& freePin = draggingFromSource ? candidate.m_EndPin : candidate.m_StartPin;
-
- if (control.HotPin)
- {
- DropPin(control.HotPin);
-
- if (m_UserAction == UserAccept)
- freePin = control.HotPin;
- }
- else if (control.BackgroundHot)
- DropNode();
- else
- DropNothing();
-
- auto drawList = Editor->GetDrawList();
- drawList->ChannelsSetCurrent(c_LinkChannel_NewLink);
-
- candidate.UpdateEndpoints();
- candidate.Draw(drawList, m_LinkColor, m_LinkThickness);
- }
- else if (m_CurrentStage == Possible || !control.ActivePin)
- {
- if (!Editor->CanAcceptUserInput())
- {
- m_DraggedPin = nullptr;
- DropNothing();
- }
-
- DragEnd();
- m_IsActive = false;
- }
-
- return m_IsActive;
-}
-
-void ed::CreateItemAction::ShowMetrics()
-{
- EditorAction::ShowMetrics();
-
- auto getStageName = [](Stage stage)
- {
- switch (stage)
- {
- case None: return "None";
- case Possible: return "Possible";
- case Create: return "Create";
- default: return "<unknown>";
- }
- };
-
- auto getActionName = [](Action action)
- {
- switch (action)
- {
- default:
- case Unknown: return "Unknown";
- case UserReject: return "Reject";
- case UserAccept: return "Accept";
- }
- };
-
- auto getItemName = [](Type item)
- {
- switch (item)
- {
- default:
- case NoItem: return "None";
- case Node: return "Node";
- case Link: return "Link";
- }
- };
-
- ImGui::Text("%s:", GetName());
- ImGui::Text(" Stage: %s", getStageName(m_CurrentStage));
- ImGui::Text(" User Action: %s", getActionName(m_UserAction));
- ImGui::Text(" Item Type: %s", getItemName(m_ItemType));
-}
-
-void ed::CreateItemAction::SetStyle(ImU32 color, float thickness)
-{
- m_LinkColor = color;
- m_LinkThickness = thickness;
-}
-
-bool ed::CreateItemAction::Begin()
-{
- IM_ASSERT(false == m_InActive);
-
- m_InActive = true;
- m_CurrentStage = m_NextStage;
- m_UserAction = Unknown;
- m_LinkColor = IM_COL32_WHITE;
- m_LinkThickness = 1.0f;
-
- if (m_CurrentStage == None)
- return false;
-
- m_LastChannel = Editor->GetDrawList()->_Splitter._Current;
-
- return true;
-}
-
-void ed::CreateItemAction::End()
-{
- IM_ASSERT(m_InActive);
-
- if (m_IsInGlobalSpace)
- {
- ImGui::PopClipRect();
- Editor->Resume(SuspendFlags::KeepSplitter);
-
- auto currentChannel = Editor->GetDrawList()->_Splitter._Current;
- if (currentChannel != m_LastChannel)
- Editor->GetDrawList()->ChannelsSetCurrent(m_LastChannel);
-
- m_IsInGlobalSpace = false;
- }
-
- m_InActive = false;
-}
-
-void ed::CreateItemAction::DragStart(Pin* startPin)
-{
- IM_ASSERT(!m_InActive);
-
- m_NextStage = Possible;
- m_LinkStart = startPin;
- m_LinkEnd = nullptr;
-}
-
-void ed::CreateItemAction::DragEnd()
-{
- IM_ASSERT(!m_InActive);
-
- if (m_CurrentStage == Possible && m_UserAction == UserAccept)
- {
- m_NextStage = Create;
- }
- else
- {
- m_NextStage = None;
- m_ItemType = NoItem;
- m_LinkStart = nullptr;
- m_LinkEnd = nullptr;
- }
-}
-
-void ed::CreateItemAction::DropPin(Pin* endPin)
-{
- IM_ASSERT(!m_InActive);
-
- m_ItemType = Link;
- m_LinkEnd = endPin;
-}
-
-void ed::CreateItemAction::DropNode()
-{
- IM_ASSERT(!m_InActive);
-
- m_ItemType = Node;
- m_LinkEnd = nullptr;
-}
-
-void ed::CreateItemAction::DropNothing()
-{
- IM_ASSERT(!m_InActive);
-
- m_ItemType = NoItem;
- m_LinkEnd = nullptr;
-}
-
-ed::CreateItemAction::Result ed::CreateItemAction::RejectItem()
-{
- IM_ASSERT(m_InActive);
-
- if (!m_InActive || m_CurrentStage == None || m_ItemType == NoItem)
- return Indeterminate;
-
- m_UserAction = UserReject;
-
- return True;
-}
-
-ed::CreateItemAction::Result ed::CreateItemAction::AcceptItem()
-{
- IM_ASSERT(m_InActive);
-
- if (!m_InActive || m_CurrentStage == None || m_ItemType == NoItem)
- return Indeterminate;
-
- m_UserAction = UserAccept;
-
- if (m_CurrentStage == Create)
- {
- m_NextStage = None;
- m_ItemType = NoItem;
- m_LinkStart = nullptr;
- m_LinkEnd = nullptr;
- return True;
- }
- else
- return False;
-}
-
-ed::CreateItemAction::Result ed::CreateItemAction::QueryLink(PinId* startId, PinId* endId)
-{
- IM_ASSERT(m_InActive);
-
- if (!m_InActive || m_CurrentStage == None || m_ItemType != Link)
- return Indeterminate;
-
- auto linkStartId = m_LinkStart->m_ID;
- auto linkEndId = m_LinkEnd->m_ID;
-
- *startId = linkStartId;
- *endId = linkEndId;
-
- Editor->SetUserContext(true);
-
- if (!m_IsInGlobalSpace)
- {
- Editor->Suspend(SuspendFlags::KeepSplitter);
-
- auto rect = Editor->GetRect();
- ImGui::PushClipRect(rect.Min + ImVec2(1, 1), rect.Max - ImVec2(1, 1), false);
- m_IsInGlobalSpace = true;
- }
-
- return True;
-}
-
-ed::CreateItemAction::Result ed::CreateItemAction::QueryNode(PinId* pinId)
-{
- IM_ASSERT(m_InActive);
-
- if (!m_InActive || m_CurrentStage == None || m_ItemType != Node)
- return Indeterminate;
-
- *pinId = m_LinkStart ? m_LinkStart->m_ID : 0;
-
- Editor->SetUserContext(true);
-
- if (!m_IsInGlobalSpace)
- {
- Editor->Suspend(SuspendFlags::KeepSplitter);
-
- auto rect = Editor->GetRect();
- ImGui::PushClipRect(rect.Min + ImVec2(1, 1), rect.Max - ImVec2(1, 1), false);
- m_IsInGlobalSpace = true;
- }
-
- return True;
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Delete Items Action
-//
-//------------------------------------------------------------------------------
-ed::DeleteItemsAction::DeleteItemsAction(EditorContext* editor):
- EditorAction(editor),
- m_IsActive(false),
- m_InInteraction(false),
- m_CurrentItemType(Unknown),
- m_UserAction(Undetermined)
-{
-}
-
-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);
-
- if (m_IsActive)
- return False;
-
- auto& io = ImGui::GetIO();
- if (Editor->CanAcceptUserInput() && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)) && Editor->AreShortcutsEnabled())
- {
- auto& selection = Editor->GetSelectedObjects();
- if (!selection.empty())
- {
- m_CandidateObjects = selection;
- m_IsActive = true;
- return True;
- }
- }
- else if (control.ClickedLink && io.KeyAlt)
- {
- m_CandidateObjects.clear();
- m_CandidateObjects.push_back(control.ClickedLink);
- m_IsActive = true;
- return True;
- }
-
- else if (!m_ManuallyDeletedObjects.empty())
- {
- m_CandidateObjects = m_ManuallyDeletedObjects;
- m_ManuallyDeletedObjects.clear();
- m_IsActive = true;
- return True;
- }
-
- return m_IsActive ? True : False;
-}
-
-bool ed::DeleteItemsAction::Process(const Control& control)
-{
- IM_UNUSED(control);
-
- if (!m_IsActive)
- return false;
-
- m_IsActive = false;
- return true;
-}
-
-void ed::DeleteItemsAction::ShowMetrics()
-{
- EditorAction::ShowMetrics();
-
- //auto getObjectName = [](Object* object)
- //{
- // if (!object) return "";
- // else if (object->AsNode()) return "Node";
- // else if (object->AsPin()) return "Pin";
- // else if (object->AsLink()) return "Link";
- // else return "";
- //};
-
- ImGui::Text("%s:", GetName());
- ImGui::Text(" Active: %s", m_IsActive ? "yes" : "no");
- //ImGui::Text(" Node: %s (%d)", getObjectName(DeleteItemsgedNode), DeleteItemsgedNode ? DeleteItemsgedNode->ID : 0);
-}
-
-bool ed::DeleteItemsAction::Add(Object* object)
-{
- if (Editor->GetCurrentAction() != nullptr)
- return false;
-
- m_ManuallyDeletedObjects.push_back(object);
-
- return true;
-}
-
-bool ed::DeleteItemsAction::Begin()
-{
- if (!m_IsActive)
- return false;
-
- IM_ASSERT(!m_InInteraction);
- m_InInteraction = true;
-
- m_CurrentItemType = Unknown;
- m_UserAction = Undetermined;
-
- return m_IsActive;
-}
-
-void ed::DeleteItemsAction::End()
-{
- if (!m_IsActive)
- return;
-
- IM_ASSERT(m_InInteraction);
- m_InInteraction = false;
-}
-
-bool ed::DeleteItemsAction::QueryLink(LinkId* linkId, PinId* startId, PinId* endId)
-{
- ObjectId objectId;
- if (!QueryItem(&objectId, Link))
- return false;
-
- if (auto id = objectId.AsLinkId())
- *linkId = id;
- else
- return false;
-
- if (startId || endId)
- {
- auto link = Editor->FindLink(*linkId);
- if (startId)
- *startId = link->m_StartPin->m_ID;
- if (endId)
- *endId = link->m_EndPin->m_ID;
- }
-
- return true;
-}
-
-bool ed::DeleteItemsAction::QueryNode(NodeId* nodeId)
-{
- ObjectId objectId;
- if (!QueryItem(&objectId, Node))
- return false;
-
- if (auto id = objectId.AsNodeId())
- *nodeId = id;
- else
- return false;
-
- return true;
-}
-
-bool ed::DeleteItemsAction::QueryItem(ObjectId* itemId, IteratorType itemType)
-{
- if (!m_InInteraction)
- return false;
-
- if (m_CurrentItemType != itemType)
- {
- m_CurrentItemType = itemType;
- m_CandidateItemIndex = 0;
- }
- else if (m_UserAction == Undetermined)
- {
- RejectItem();
- }
-
- m_UserAction = Undetermined;
-
- auto itemCount = (int)m_CandidateObjects.size();
- while (m_CandidateItemIndex < itemCount)
- {
- auto item = m_CandidateObjects[m_CandidateItemIndex];
- if (itemType == Node)
- {
- if (auto node = item->AsNode())
- {
- *itemId = node->m_ID;
- return true;
- }
- }
- else if (itemType == Link)
- {
- if (auto link = item->AsLink())
- {
- *itemId = link->m_ID;
- return true;
- }
- }
-
- ++m_CandidateItemIndex;
- }
-
- if (m_CandidateItemIndex == itemCount)
- m_CurrentItemType = Unknown;
-
- return false;
-}
-
-bool ed::DeleteItemsAction::AcceptItem(bool deleteDependencies)
-{
- if (!m_InInteraction)
- return false;
-
- m_UserAction = Accepted;
-
- RemoveItem(deleteDependencies);
-
- return true;
-}
-
-void ed::DeleteItemsAction::RejectItem()
-{
- if (!m_InInteraction)
- return;
-
- m_UserAction = Rejected;
-
- RemoveItem(false);
-}
-
-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());
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Node Builder
-//
-//------------------------------------------------------------------------------
-ed::NodeBuilder::NodeBuilder(EditorContext* editor):
- Editor(editor),
- m_CurrentNode(nullptr),
- m_CurrentPin(nullptr)
-{
-}
-
-ed::NodeBuilder::~NodeBuilder()
-{
- m_Splitter.ClearFreeMemory();
- m_PinSplitter.ClearFreeMemory();
-}
-
-void ed::NodeBuilder::Begin(NodeId nodeId)
-{
- IM_ASSERT(nullptr == m_CurrentNode);
-
- m_CurrentNode = Editor->GetNode(nodeId);
-
- Editor->UpdateNodeState(m_CurrentNode);
-
- if (m_CurrentNode->m_CenterOnScreen)
- {
- auto bounds = Editor->GetViewRect();
- auto offset = bounds.GetCenter() - m_CurrentNode->m_Bounds.GetCenter();
-
- if (ImLengthSqr(offset) > 0)
- {
- if (::IsGroup(m_CurrentNode))
- {
- std::vector<Node*> groupedNodes;
- m_CurrentNode->GetGroupedNodes(groupedNodes);
- groupedNodes.push_back(m_CurrentNode);
-
- for (auto node : groupedNodes)
- {
- node->m_Bounds.Translate(ImFloor(offset));
- node->m_GroupBounds.Translate(ImFloor(offset));
- Editor->MakeDirty(SaveReasonFlags::Position | SaveReasonFlags::User, node);
- }
- }
- else
- {
- m_CurrentNode->m_Bounds.Translate(ImFloor(offset));
- m_CurrentNode->m_GroupBounds.Translate(ImFloor(offset));
- Editor->MakeDirty(SaveReasonFlags::Position | SaveReasonFlags::User, m_CurrentNode);
- }
- }
-
- m_CurrentNode->m_CenterOnScreen = false;
- }
-
- // Position node on screen
- ImGui::SetCursorScreenPos(m_CurrentNode->m_Bounds.Min);
-
- auto& editorStyle = Editor->GetStyle();
-
- const auto alpha = ImGui::GetStyle().Alpha;
-
- m_CurrentNode->m_IsLive = true;
- m_CurrentNode->m_LastPin = nullptr;
- m_CurrentNode->m_Color = Editor->GetColor(StyleColor_NodeBg, alpha);
- m_CurrentNode->m_BorderColor = Editor->GetColor(StyleColor_NodeBorder, alpha);
- m_CurrentNode->m_BorderWidth = editorStyle.NodeBorderWidth;
- m_CurrentNode->m_Rounding = editorStyle.NodeRounding;
- m_CurrentNode->m_GroupColor = Editor->GetColor(StyleColor_GroupBg, alpha);
- m_CurrentNode->m_GroupBorderColor = Editor->GetColor(StyleColor_GroupBorder, alpha);
- m_CurrentNode->m_GroupBorderWidth = editorStyle.GroupBorderWidth;
- m_CurrentNode->m_GroupRounding = editorStyle.GroupRounding;
-
- m_IsGroup = false;
-
- // Grow channel list and select user channel
- if (auto drawList = Editor->GetDrawList())
- {
- m_CurrentNode->m_Channel = drawList->_Splitter._Count;
- ImDrawList_ChannelsGrow(drawList, drawList->_Splitter._Count + c_ChannelsPerNode);
- drawList->ChannelsSetCurrent(m_CurrentNode->m_Channel + c_NodeContentChannel);
-
- m_Splitter.Clear();
- ImDrawList_SwapSplitter(drawList, m_Splitter);
- }
-
- // Begin outer group
- ImGui::BeginGroup();
-
- // Apply frame padding. Begin inner group if necessary.
- if (editorStyle.NodePadding.x != 0 || editorStyle.NodePadding.y != 0 || editorStyle.NodePadding.z != 0 || editorStyle.NodePadding.w != 0)
- {
- ImGui::SetCursorPos(ImGui::GetCursorPos() + ImVec2(editorStyle.NodePadding.x, editorStyle.NodePadding.y));
- ImGui::BeginGroup();
- }
-}
-
-void ed::NodeBuilder::End()
-{
- IM_ASSERT(nullptr != m_CurrentNode);
-
- if (auto drawList = Editor->GetDrawList())
- {
- IM_ASSERT(drawList->_Splitter._Count == 1); // Did you forgot to call drawList->ChannelsMerge()?
- ImDrawList_SwapSplitter(drawList, m_Splitter);
- }
-
- // Apply frame padding. This must be done in this convoluted way if outer group
- // size must contain inner group padding.
- auto& editorStyle = Editor->GetStyle();
- if (editorStyle.NodePadding.x != 0 || editorStyle.NodePadding.y != 0 || editorStyle.NodePadding.z != 0 || editorStyle.NodePadding.w != 0)
- {
- 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);
- }
-
- // End outer group.
- ImGui::EndGroup();
-
- m_NodeRect = ImGui_GetItemRect();
- m_NodeRect.Floor();
-
- if (m_CurrentNode->m_Bounds.GetSize() != m_NodeRect.GetSize())
- {
- m_CurrentNode->m_Bounds.Max = m_CurrentNode->m_Bounds.Min + m_NodeRect.GetSize();
- Editor->MakeDirty(SaveReasonFlags::Size, m_CurrentNode);
- }
-
- if (m_IsGroup)
- {
- // Groups cannot have pins. Discard them.
- for (auto pin = m_CurrentNode->m_LastPin; pin; pin = pin->m_PreviousPin)
- pin->Reset();
-
- m_CurrentNode->m_Type = NodeType::Group;
- m_CurrentNode->m_GroupBounds = m_GroupBounds;
- m_CurrentNode->m_LastPin = nullptr;
- }
- else
- m_CurrentNode->m_Type = NodeType::Node;
-
- m_CurrentNode = nullptr;
-}
-
-void ed::NodeBuilder::BeginPin(PinId pinId, PinKind kind)
-{
- IM_ASSERT(nullptr != m_CurrentNode);
- IM_ASSERT(nullptr == m_CurrentPin);
- IM_ASSERT(false == m_IsGroup);
-
- auto& editorStyle = Editor->GetStyle();
-
- m_CurrentPin = Editor->GetPin(pinId, kind);
- m_CurrentPin->m_Node = m_CurrentNode;
-
- m_CurrentPin->m_IsLive = true;
- m_CurrentPin->m_Color = Editor->GetColor(StyleColor_PinRect);
- m_CurrentPin->m_BorderColor = Editor->GetColor(StyleColor_PinRectBorder);
- m_CurrentPin->m_BorderWidth = editorStyle.PinBorderWidth;
- m_CurrentPin->m_Rounding = editorStyle.PinRounding;
- m_CurrentPin->m_Corners = static_cast<int>(editorStyle.PinCorners);
- m_CurrentPin->m_Radius = editorStyle.PinRadius;
- m_CurrentPin->m_ArrowSize = editorStyle.PinArrowSize;
- m_CurrentPin->m_ArrowWidth = editorStyle.PinArrowWidth;
- m_CurrentPin->m_Dir = kind == PinKind::Output ? editorStyle.SourceDirection : editorStyle.TargetDirection;
- m_CurrentPin->m_Strength = editorStyle.LinkStrength;
-
- m_CurrentPin->m_PreviousPin = m_CurrentNode->m_LastPin;
- m_CurrentNode->m_LastPin = m_CurrentPin;
-
- m_PivotAlignment = editorStyle.PivotAlignment;
- m_PivotSize = editorStyle.PivotSize;
- m_PivotScale = editorStyle.PivotScale;
- m_ResolvePinRect = true;
- m_ResolvePivot = true;
-
- if (auto drawList = Editor->GetDrawList())
- {
- m_PinSplitter.Clear();
- ImDrawList_SwapSplitter(drawList, m_PinSplitter);
- }
-
- ImGui::BeginGroup();
-}
-
-void ed::NodeBuilder::EndPin()
-{
- IM_ASSERT(nullptr != m_CurrentPin);
-
- if (auto drawList = Editor->GetDrawList())
- {
- IM_ASSERT(drawList->_Splitter._Count == 1); // Did you forgot to call drawList->ChannelsMerge()?
- ImDrawList_SwapSplitter(drawList, m_PinSplitter);
- }
-
- ImGui::EndGroup();
-
- if (m_ResolvePinRect)
- m_CurrentPin->m_Bounds = ImGui_GetItemRect();
-
- if (m_ResolvePivot)
- {
- auto& pinRect = m_CurrentPin->m_Bounds;
-
- if (m_PivotSize.x < 0)
- m_PivotSize.x = pinRect.GetWidth();
- if (m_PivotSize.y < 0)
- m_PivotSize.y = pinRect.GetHeight();
-
- m_CurrentPin->m_Pivot.Min = pinRect.Min + ImMul(pinRect.GetSize(), m_PivotAlignment);
- m_CurrentPin->m_Pivot.Max = m_CurrentPin->m_Pivot.Min + ImMul(m_PivotSize, m_PivotScale);
- }
-
- // #debug: Draw pin bounds
- //Editor->GetDrawList()->AddRect(m_CurrentPin->m_Bounds.Min, m_CurrentPin->m_Bounds.Max, IM_COL32(255, 255, 0, 255));
-
- // #debug: Draw pin pivot rectangle
- //Editor->GetDrawList()->AddRect(m_CurrentPin->m_Pivot.Min, m_CurrentPin->m_Pivot.Max, IM_COL32(255, 0, 255, 255));
-
- m_CurrentPin = nullptr;
-}
-
-void ed::NodeBuilder::PinRect(const ImVec2& a, const ImVec2& b)
-{
- IM_ASSERT(nullptr != m_CurrentPin);
-
- m_CurrentPin->m_Bounds = ImRect(a, b);
- m_CurrentPin->m_Bounds.Floor();
- m_ResolvePinRect = false;
-}
-
-void ed::NodeBuilder::PinPivotRect(const ImVec2& a, const ImVec2& b)
-{
- IM_ASSERT(nullptr != m_CurrentPin);
-
- m_CurrentPin->m_Pivot = ImRect(a, b);
- m_ResolvePivot = false;
-}
-
-void ed::NodeBuilder::PinPivotSize(const ImVec2& size)
-{
- IM_ASSERT(nullptr != m_CurrentPin);
-
- m_PivotSize = size;
- m_ResolvePivot = true;
-}
-
-void ed::NodeBuilder::PinPivotScale(const ImVec2& scale)
-{
- IM_ASSERT(nullptr != m_CurrentPin);
-
- m_PivotScale = scale;
- m_ResolvePivot = true;
-}
-
-void ed::NodeBuilder::PinPivotAlignment(const ImVec2& alignment)
-{
- IM_ASSERT(nullptr != m_CurrentPin);
-
- m_PivotAlignment = alignment;
- m_ResolvePivot = true;
-}
-
-void ed::NodeBuilder::Group(const ImVec2& size)
-{
- IM_ASSERT(nullptr != m_CurrentNode);
- IM_ASSERT(nullptr == m_CurrentPin);
- IM_ASSERT(false == m_IsGroup);
-
- m_IsGroup = true;
-
- if (IsGroup(m_CurrentNode))
- ImGui::Dummy(m_CurrentNode->m_GroupBounds.GetSize());
- else
- ImGui::Dummy(size);
-
- m_GroupBounds = ImGui_GetItemRect();
- m_GroupBounds.Floor();
-}
-
-ImDrawList* ed::NodeBuilder::GetUserBackgroundDrawList() const
-{
- return GetUserBackgroundDrawList(m_CurrentNode);
-}
-
-ImDrawList* ed::NodeBuilder::GetUserBackgroundDrawList(Node* node) const
-{
- if (node && node->m_IsLive)
- {
- auto drawList = Editor->GetDrawList();
- drawList->ChannelsSetCurrent(node->m_Channel + c_NodeUserBackgroundChannel);
- return drawList;
- }
- else
- return nullptr;
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Node Builder
-//
-//------------------------------------------------------------------------------
-ed::HintBuilder::HintBuilder(EditorContext* editor):
- Editor(editor),
- m_IsActive(false),
- m_CurrentNode(nullptr)
-{
-}
-
-bool ed::HintBuilder::Begin(NodeId nodeId)
-{
- IM_ASSERT(nullptr == m_CurrentNode);
-
- auto& view = Editor->GetView();
- auto& rect = Editor->GetRect();
-
- const float c_min_zoom = 0.75f;
- const float c_max_zoom = 0.50f;
-
- if (view.Scale > 0.75f)
- return false;
-
- auto node = Editor->FindNode(nodeId);
- if (!IsGroup(node))
- return false;
-
- m_CurrentNode = node;
-
- 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)));
-
- Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_HintsBackground);
- ImGui::PushClipRect(rect.Min + ImVec2(1, 1), rect.Max - ImVec2(1, 1), false);
-
- Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_Hints);
- ImGui::PushClipRect(rect.Min + ImVec2(1, 1), rect.Max - ImVec2(1, 1), false);
-
- ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
-
- m_IsActive = true;
-
- return true;
-}
-
-void ed::HintBuilder::End()
-{
- if (!m_IsActive)
- return;
-
- ImGui::PopStyleVar();
-
- Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_Hints);
- ImGui::PopClipRect();
-
- Editor->GetDrawList()->ChannelsSetCurrent(c_UserChannel_HintsBackground);
- ImGui::PopClipRect();
-
- Editor->GetDrawList()->ChannelsSetCurrent(m_LastChannel);
-
- Editor->Resume(SuspendFlags::KeepSplitter);
-
- m_IsActive = false;
- m_CurrentNode = nullptr;
-}
-
-ImVec2 ed::HintBuilder::GetGroupMin()
-{
- IM_ASSERT(nullptr != m_CurrentNode);
-
- return Editor->ToScreen(m_CurrentNode->m_Bounds.Min);
-}
-
-ImVec2 ed::HintBuilder::GetGroupMax()
-{
- IM_ASSERT(nullptr != m_CurrentNode);
-
- return Editor->ToScreen(m_CurrentNode->m_Bounds.Max);
-}
-
-ImDrawList* ed::HintBuilder::GetForegroundDrawList()
-{
- IM_ASSERT(nullptr != m_CurrentNode);
-
- auto drawList = Editor->GetDrawList();
-
- drawList->ChannelsSetCurrent(c_UserChannel_Hints);
-
- return drawList;
-}
-
-ImDrawList* ed::HintBuilder::GetBackgroundDrawList()
-{
- IM_ASSERT(nullptr != m_CurrentNode);
-
- auto drawList = Editor->GetDrawList();
-
- drawList->ChannelsSetCurrent(c_UserChannel_HintsBackground);
-
- return drawList;
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Style
-//
-//------------------------------------------------------------------------------
-void ed::Style::PushColor(StyleColor colorIndex, const ImVec4& color)
-{
- ColorModifier modifier;
- modifier.Index = colorIndex;
- modifier.Value = Colors[colorIndex];
- m_ColorStack.push_back(modifier);
- Colors[colorIndex] = color;
-}
-
-void ed::Style::PopColor(int count)
-{
- while (count > 0)
- {
- auto& modifier = m_ColorStack.back();
- Colors[modifier.Index] = modifier.Value;
- m_ColorStack.pop_back();
- --count;
- }
-}
-
-void ed::Style::PushVar(StyleVar varIndex, float value)
-{
- auto* var = GetVarFloatAddr(varIndex);
- IM_ASSERT(var != nullptr);
- VarModifier modifier;
- modifier.Index = varIndex;
- modifier.Value = ImVec4(*var, 0, 0, 0);
- *var = value;
- m_VarStack.push_back(modifier);
-}
-
-void ed::Style::PushVar(StyleVar varIndex, const ImVec2& value)
-{
- auto* var = GetVarVec2Addr(varIndex);
- IM_ASSERT(var != nullptr);
- VarModifier modifier;
- modifier.Index = varIndex;
- modifier.Value = ImVec4(var->x, var->y, 0, 0);
- *var = value;
- m_VarStack.push_back(modifier);
-}
-
-void ed::Style::PushVar(StyleVar varIndex, const ImVec4& value)
-{
- auto* var = GetVarVec4Addr(varIndex);
- IM_ASSERT(var != nullptr);
- VarModifier modifier;
- modifier.Index = varIndex;
- modifier.Value = *var;
- *var = value;
- m_VarStack.push_back(modifier);
-}
-
-void ed::Style::PopVar(int count)
-{
- while (count > 0)
- {
- auto& modifier = m_VarStack.back();
- if (auto floatValue = GetVarFloatAddr(modifier.Index))
- *floatValue = modifier.Value.x;
- else if (auto vec2Value = GetVarVec2Addr(modifier.Index))
- *vec2Value = ImVec2(modifier.Value.x, modifier.Value.y);
- else if (auto vec4Value = GetVarVec4Addr(modifier.Index))
- *vec4Value = modifier.Value;
- m_VarStack.pop_back();
- --count;
- }
-}
-
-const char* ed::Style::GetColorName(StyleColor colorIndex) const
-{
- switch (colorIndex)
- {
- case StyleColor_Bg: return "Bg";
- case StyleColor_Grid: return "Grid";
- case StyleColor_NodeBg: return "NodeBg";
- case StyleColor_NodeBorder: return "NodeBorder";
- case StyleColor_HovNodeBorder: return "HoveredNodeBorder";
- case StyleColor_SelNodeBorder: return "SelNodeBorder";
- case StyleColor_NodeSelRect: return "NodeSelRect";
- case StyleColor_NodeSelRectBorder: return "NodeSelRectBorder";
- case StyleColor_HovLinkBorder: return "HoveredLinkBorder";
- case StyleColor_SelLinkBorder: return "SelLinkBorder";
- case StyleColor_LinkSelRect: return "LinkSelRect";
- case StyleColor_LinkSelRectBorder: return "LinkSelRectBorder";
- case StyleColor_PinRect: return "PinRect";
- case StyleColor_PinRectBorder: return "PinRectBorder";
- case StyleColor_Flow: return "Flow";
- case StyleColor_FlowMarker: return "FlowMarker";
- case StyleColor_GroupBg: return "GroupBg";
- case StyleColor_GroupBorder: return "GroupBorder";
- case StyleColor_Count: break;
- }
-
- IM_ASSERT(0);
- return "Unknown";
-}
-
-float* ed::Style::GetVarFloatAddr(StyleVar idx)
-{
- switch (idx)
- {
- case StyleVar_NodeRounding: return &NodeRounding;
- case StyleVar_NodeBorderWidth: return &NodeBorderWidth;
- case StyleVar_HoveredNodeBorderWidth: return &HoveredNodeBorderWidth;
- case StyleVar_SelectedNodeBorderWidth: return &SelectedNodeBorderWidth;
- case StyleVar_PinRounding: return &PinRounding;
- case StyleVar_PinBorderWidth: return &PinBorderWidth;
- case StyleVar_LinkStrength: return &LinkStrength;
- case StyleVar_ScrollDuration: return &ScrollDuration;
- case StyleVar_FlowMarkerDistance: return &FlowMarkerDistance;
- case StyleVar_FlowSpeed: return &FlowSpeed;
- case StyleVar_FlowDuration: return &FlowDuration;
- case StyleVar_PinCorners: return &PinCorners;
- case StyleVar_PinRadius: return &PinRadius;
- case StyleVar_PinArrowSize: return &PinArrowSize;
- case StyleVar_PinArrowWidth: return &PinArrowWidth;
- case StyleVar_GroupRounding: return &GroupRounding;
- case StyleVar_GroupBorderWidth: return &GroupBorderWidth;
- default: return nullptr;
- }
-}
-
-ImVec2* ed::Style::GetVarVec2Addr(StyleVar idx)
-{
- switch (idx)
- {
- case StyleVar_SourceDirection: return &SourceDirection;
- case StyleVar_TargetDirection: return &TargetDirection;
- case StyleVar_PivotAlignment: return &PivotAlignment;
- case StyleVar_PivotSize: return &PivotSize;
- case StyleVar_PivotScale: return &PivotScale;
- default: return nullptr;
- }
-}
-
-ImVec4* ed::Style::GetVarVec4Addr(StyleVar idx)
-{
- switch (idx)
- {
- case StyleVar_NodePadding: return &NodePadding;
- default: return nullptr;
- }
-}
-
-
-
-
-//------------------------------------------------------------------------------
-//
-// Config
-//
-//------------------------------------------------------------------------------
-ed::Config::Config(const ax::NodeEditor::Config* config)
-{
- if (config)
- *static_cast<ax::NodeEditor::Config*>(this) = *config;
-}
-
-std::string ed::Config::Load()
-{
- std::string data;
-
- if (LoadSettings)
- {
- const auto size = LoadSettings(nullptr, UserPointer);
- if (size > 0)
- {
- data.resize(size);
- LoadSettings(const_cast<char*>(data.data()), UserPointer);
- }
- }
- else if (SettingsFile)
- {
- std::ifstream file(SettingsFile);
- if (file)
- {
- file.seekg(0, std::ios_base::end);
- auto size = static_cast<size_t>(file.tellg());
- file.seekg(0, std::ios_base::beg);
-
- data.reserve(size);
- data.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
- }
- }
-
- return data;
-}
-
-std::string ed::Config::LoadNode(NodeId nodeId)
-{
- std::string data;
-
- if (LoadNodeSettings)
- {
- const auto size = LoadNodeSettings(nodeId, nullptr, UserPointer);
- if (size > 0)
- {
- data.resize(size);
- LoadNodeSettings(nodeId, const_cast<char*>(data.data()), UserPointer);
- }
- }
-
- return data;
-}
-
-void ed::Config::BeginSave()
-{
- if (BeginSaveSession)
- BeginSaveSession(UserPointer);
-}
-
-bool ed::Config::Save(const std::string& data, SaveReasonFlags flags)
-{
- if (SaveSettings)
- {
- return SaveSettings(data.c_str(), data.size(), flags, UserPointer);
- }
- else if (SettingsFile)
- {
- std::ofstream settingsFile(SettingsFile);
- if (settingsFile)
- settingsFile << data;
-
- return !!settingsFile;
- }
-
- return false;
-}
-
-bool ed::Config::SaveNode(NodeId nodeId, const std::string& data, SaveReasonFlags flags)
-{
- if (SaveNodeSettings)
- return SaveNodeSettings(nodeId, data.c_str(), data.size(), flags, UserPointer);
-
- return false;
-}
-
-void ed::Config::EndSave()
-{
- if (EndSaveSession)
- EndSaveSession(UserPointer);
-}
diff --git a/3rdparty/imgui-node-editor/imgui_node_editor.h b/3rdparty/imgui-node-editor/imgui_node_editor.h
deleted file mode 100644
index e9bce90..0000000
--- a/3rdparty/imgui-node-editor/imgui_node_editor.h
+++ /dev/null
@@ -1,481 +0,0 @@
-//------------------------------------------------------------------------------
-// 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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-//------------------------------------------------------------------------------
-# ifndef __IMGUI_NODE_EDITOR_H__
-# define __IMGUI_NODE_EDITOR_H__
-# pragma once
-
-
-//------------------------------------------------------------------------------
-# include <imgui.h>
-# include <cstdint> // std::uintXX_t
-# include <utility> // std::move
-
-
-//------------------------------------------------------------------------------
-namespace ax {
-namespace NodeEditor {
-
-
-//------------------------------------------------------------------------------
-struct NodeId;
-struct LinkId;
-struct PinId;
-
-
-//------------------------------------------------------------------------------
-enum class SaveReasonFlags: uint32_t
-{
- None = 0x00000000,
- Navigation = 0x00000001,
- Position = 0x00000002,
- Size = 0x00000004,
- Selection = 0x00000008,
- AddNode = 0x00000010,
- RemoveNode = 0x00000020,
- User = 0x00000040
-};
-
-inline SaveReasonFlags operator |(SaveReasonFlags lhs, SaveReasonFlags rhs) { return static_cast<SaveReasonFlags>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs)); }
-inline SaveReasonFlags operator &(SaveReasonFlags lhs, SaveReasonFlags rhs) { return static_cast<SaveReasonFlags>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs)); }
-
-using ConfigSaveSettings = bool (*)(const char* data, size_t size, SaveReasonFlags reason, void* userPointer);
-using ConfigLoadSettings = size_t (*)(char* data, void* userPointer);
-
-using ConfigSaveNodeSettings = bool (*)(NodeId nodeId, const char* data, size_t size, SaveReasonFlags reason, void* userPointer);
-using ConfigLoadNodeSettings = size_t (*)(NodeId nodeId, char* data, void* userPointer);
-
-using ConfigSession = void (*)(void* userPointer);
-
-struct Config
-{
- const char* SettingsFile;
- ConfigSession BeginSaveSession;
- ConfigSession EndSaveSession;
- ConfigSaveSettings SaveSettings;
- ConfigLoadSettings LoadSettings;
- ConfigSaveNodeSettings SaveNodeSettings;
- ConfigLoadNodeSettings LoadNodeSettings;
- void* UserPointer;
- int DragButtonIndex; // Mouse button index drag action will react to (0-left, 1-right, 2-middle)
- int SelectButtonIndex; // Mouse button index select action will react to (0-left, 1-right, 2-middle)
- int NavigateButtonIndex; // Mouse button index navigate action will react to (0-left, 1-right, 2-middle)
- int ContextMenuButtonIndex; // Mouse button index context menu action will react to (0-left, 1-right, 2-middle)
-
- Config()
- : SettingsFile("NodeEditor.json")
- , BeginSaveSession(nullptr)
- , EndSaveSession(nullptr)
- , SaveSettings(nullptr)
- , LoadSettings(nullptr)
- , SaveNodeSettings(nullptr)
- , LoadNodeSettings(nullptr)
- , UserPointer(nullptr)
- , DragButtonIndex(0)
- , SelectButtonIndex(0)
- , NavigateButtonIndex(1)
- , ContextMenuButtonIndex(1)
- {
- }
-};
-
-
-//------------------------------------------------------------------------------
-enum class PinKind
-{
- Input,
- Output
-};
-
-enum class FlowDirection
-{
- Forward,
- Backward
-};
-
-
-//------------------------------------------------------------------------------
-enum StyleColor
-{
- StyleColor_Bg,
- StyleColor_Grid,
- StyleColor_NodeBg,
- StyleColor_NodeBorder,
- StyleColor_HovNodeBorder,
- StyleColor_SelNodeBorder,
- StyleColor_NodeSelRect,
- StyleColor_NodeSelRectBorder,
- StyleColor_HovLinkBorder,
- StyleColor_SelLinkBorder,
- StyleColor_LinkSelRect,
- StyleColor_LinkSelRectBorder,
- StyleColor_PinRect,
- StyleColor_PinRectBorder,
- StyleColor_Flow,
- StyleColor_FlowMarker,
- StyleColor_GroupBg,
- StyleColor_GroupBorder,
-
- StyleColor_Count
-};
-
-enum StyleVar
-{
- StyleVar_NodePadding,
- StyleVar_NodeRounding,
- StyleVar_NodeBorderWidth,
- StyleVar_HoveredNodeBorderWidth,
- StyleVar_SelectedNodeBorderWidth,
- StyleVar_PinRounding,
- StyleVar_PinBorderWidth,
- StyleVar_LinkStrength,
- StyleVar_SourceDirection,
- StyleVar_TargetDirection,
- StyleVar_ScrollDuration,
- StyleVar_FlowMarkerDistance,
- StyleVar_FlowSpeed,
- StyleVar_FlowDuration,
- StyleVar_PivotAlignment,
- StyleVar_PivotSize,
- StyleVar_PivotScale,
- StyleVar_PinCorners,
- StyleVar_PinRadius,
- StyleVar_PinArrowSize,
- StyleVar_PinArrowWidth,
- StyleVar_GroupRounding,
- StyleVar_GroupBorderWidth,
-
- StyleVar_Count
-};
-
-struct Style
-{
- ImVec4 NodePadding;
- float NodeRounding;
- float NodeBorderWidth;
- float HoveredNodeBorderWidth;
- float SelectedNodeBorderWidth;
- float PinRounding;
- float PinBorderWidth;
- float LinkStrength;
- ImVec2 SourceDirection;
- ImVec2 TargetDirection;
- float ScrollDuration;
- float FlowMarkerDistance;
- float FlowSpeed;
- float FlowDuration;
- ImVec2 PivotAlignment;
- ImVec2 PivotSize;
- ImVec2 PivotScale;
- float PinCorners;
- float PinRadius;
- float PinArrowSize;
- float PinArrowWidth;
- float GroupRounding;
- float GroupBorderWidth;
- ImVec4 Colors[StyleColor_Count];
-
- Style()
- {
- NodePadding = ImVec4(8, 8, 8, 8);
- NodeRounding = 12.0f;
- NodeBorderWidth = 1.5f;
- HoveredNodeBorderWidth = 3.5f;
- SelectedNodeBorderWidth = 3.5f;
- PinRounding = 4.0f;
- PinBorderWidth = 0.0f;
- LinkStrength = 100.0f;
- SourceDirection = ImVec2(1.0f, 0.0f);
- TargetDirection = ImVec2(-1.0f, 0.0f);
- ScrollDuration = 0.35f;
- FlowMarkerDistance = 30.0f;
- FlowSpeed = 150.0f;
- FlowDuration = 2.0f;
- PivotAlignment = ImVec2(0.5f, 0.5f);
- PivotSize = ImVec2(0.0f, 0.0f);
- PivotScale = ImVec2(1, 1);
-#if IMGUI_VERSION_NUM > 18101
- PinCorners = ImDrawFlags_RoundCornersAll;
-#else
- PinCorners = ImDrawCornerFlags_All;
-#endif
- PinRadius = 0.0f;
- PinArrowSize = 0.0f;
- PinArrowWidth = 0.0f;
- GroupRounding = 6.0f;
- GroupBorderWidth = 1.0f;
-
- Colors[StyleColor_Bg] = ImColor( 60, 60, 70, 200);
- Colors[StyleColor_Grid] = ImColor(120, 120, 120, 40);
- Colors[StyleColor_NodeBg] = ImColor( 32, 32, 32, 200);
- Colors[StyleColor_NodeBorder] = ImColor(255, 255, 255, 96);
- Colors[StyleColor_HovNodeBorder] = ImColor( 50, 176, 255, 255);
- Colors[StyleColor_SelNodeBorder] = ImColor(255, 176, 50, 255);
- Colors[StyleColor_NodeSelRect] = ImColor( 5, 130, 255, 64);
- Colors[StyleColor_NodeSelRectBorder] = ImColor( 5, 130, 255, 128);
- Colors[StyleColor_HovLinkBorder] = ImColor( 50, 176, 255, 255);
- Colors[StyleColor_SelLinkBorder] = ImColor(255, 176, 50, 255);
- Colors[StyleColor_LinkSelRect] = ImColor( 5, 130, 255, 64);
- Colors[StyleColor_LinkSelRectBorder] = ImColor( 5, 130, 255, 128);
- Colors[StyleColor_PinRect] = ImColor( 60, 180, 255, 100);
- Colors[StyleColor_PinRectBorder] = ImColor( 60, 180, 255, 128);
- Colors[StyleColor_Flow] = ImColor(255, 128, 64, 255);
- Colors[StyleColor_FlowMarker] = ImColor(255, 128, 64, 255);
- Colors[StyleColor_GroupBg] = ImColor( 0, 0, 0, 160);
- Colors[StyleColor_GroupBorder] = ImColor(255, 255, 255, 32);
- }
-};
-
-
-//------------------------------------------------------------------------------
-struct EditorContext;
-
-
-//------------------------------------------------------------------------------
-void SetCurrentEditor(EditorContext* ctx);
-EditorContext* GetCurrentEditor();
-EditorContext* CreateEditor(const Config* config = nullptr);
-void DestroyEditor(EditorContext* ctx);
-
-Style& GetStyle();
-const char* GetStyleColorName(StyleColor colorIndex);
-
-void PushStyleColor(StyleColor colorIndex, const ImVec4& color);
-void PopStyleColor(int count = 1);
-
-void PushStyleVar(StyleVar varIndex, float value);
-void PushStyleVar(StyleVar varIndex, const ImVec2& value);
-void PushStyleVar(StyleVar varIndex, const ImVec4& value);
-void PopStyleVar(int count = 1);
-
-void Begin(const char* id, const ImVec2& size = ImVec2(0, 0));
-void End();
-
-void BeginNode(NodeId id);
-void BeginPin(PinId id, PinKind kind);
-void PinRect(const ImVec2& a, const ImVec2& b);
-void PinPivotRect(const ImVec2& a, const ImVec2& b);
-void PinPivotSize(const ImVec2& size);
-void PinPivotScale(const ImVec2& scale);
-void PinPivotAlignment(const ImVec2& alignment);
-void EndPin();
-void Group(const ImVec2& size);
-void EndNode();
-
-bool BeginGroupHint(NodeId nodeId);
-ImVec2 GetGroupMin();
-ImVec2 GetGroupMax();
-ImDrawList* GetHintForegroundDrawList();
-ImDrawList* GetHintBackgroundDrawList();
-void EndGroupHint();
-
-// TODO: Add a way to manage node background channels
-ImDrawList* GetNodeBackgroundDrawList(NodeId nodeId);
-
-bool Link(LinkId id, PinId startPinId, PinId endPinId, const ImVec4& color = ImVec4(1, 1, 1, 1), float thickness = 1.0f);
-
-void Flow(LinkId linkId, FlowDirection direction = FlowDirection::Forward);
-
-bool BeginCreate(const ImVec4& color = ImVec4(1, 1, 1, 1), float thickness = 1.0f);
-bool QueryNewLink(PinId* startId, PinId* endId);
-bool QueryNewLink(PinId* startId, PinId* endId, const ImVec4& color, float thickness = 1.0f);
-bool QueryNewNode(PinId* pinId);
-bool QueryNewNode(PinId* pinId, const ImVec4& color, float thickness = 1.0f);
-bool AcceptNewItem();
-bool AcceptNewItem(const ImVec4& color, float thickness = 1.0f);
-void RejectNewItem();
-void RejectNewItem(const ImVec4& color, float thickness = 1.0f);
-void EndCreate();
-
-bool BeginDelete();
-bool QueryDeletedLink(LinkId* linkId, PinId* startId = nullptr, PinId* endId = nullptr);
-bool QueryDeletedNode(NodeId* nodeId);
-bool AcceptDeletedItem(bool deleteDependencies = true);
-void RejectDeletedItem();
-void EndDelete();
-
-void SetNodePosition(NodeId nodeId, const ImVec2& editorPosition);
-void SetGroupSize(NodeId nodeId, const ImVec2& size);
-ImVec2 GetNodePosition(NodeId nodeId);
-ImVec2 GetNodeSize(NodeId nodeId);
-void CenterNodeOnScreen(NodeId nodeId);
-void SetNodeZPosition(NodeId nodeId, float z); // Sets node z position, nodes with higher value are drawn over nodes with lower value
-float GetNodeZPosition(NodeId nodeId); // Returns node z position, defaults is 0.0f
-
-void RestoreNodeState(NodeId nodeId);
-
-void Suspend();
-void Resume();
-bool IsSuspended();
-
-bool IsActive();
-
-bool HasSelectionChanged();
-int GetSelectedObjectCount();
-int GetSelectedNodes(NodeId* nodes, int size);
-int GetSelectedLinks(LinkId* links, int size);
-bool IsNodeSelected(NodeId nodeId);
-bool IsLinkSelected(LinkId linkId);
-void ClearSelection();
-void SelectNode(NodeId nodeId, bool append = false);
-void SelectLink(LinkId linkId, bool append = false);
-void DeselectNode(NodeId nodeId);
-void DeselectLink(LinkId linkId);
-
-bool DeleteNode(NodeId nodeId);
-bool DeleteLink(LinkId linkId);
-
-bool HasAnyLinks(NodeId nodeId); // Returns true if node has any link connected
-bool HasAnyLinks(PinId pinId); // Return true if pin has any link connected
-int BreakLinks(NodeId nodeId); // Break all links connected to this node
-int BreakLinks(PinId pinId); // Break all links connected to this pin
-
-void NavigateToContent(float duration = -1);
-void NavigateToSelection(bool zoomIn = false, float duration = -1);
-
-bool ShowNodeContextMenu(NodeId* nodeId);
-bool ShowPinContextMenu(PinId* pinId);
-bool ShowLinkContextMenu(LinkId* linkId);
-bool ShowBackgroundContextMenu();
-
-void EnableShortcuts(bool enable);
-bool AreShortcutsEnabled();
-
-bool BeginShortcut();
-bool AcceptCut();
-bool AcceptCopy();
-bool AcceptPaste();
-bool AcceptDuplicate();
-bool AcceptCreateNode();
-int GetActionContextSize();
-int GetActionContextNodes(NodeId* nodes, int size);
-int GetActionContextLinks(LinkId* links, int size);
-void EndShortcut();
-
-float GetCurrentZoom();
-
-NodeId GetHoveredNode();
-PinId GetHoveredPin();
-LinkId GetHoveredLink();
-NodeId GetDoubleClickedNode();
-PinId GetDoubleClickedPin();
-LinkId GetDoubleClickedLink();
-bool IsBackgroundClicked();
-bool IsBackgroundDoubleClicked();
-
-bool GetLinkPins(LinkId linkId, PinId* startPinId, PinId* endPinId); // pass nullptr if particular pin do not interest you
-
-bool PinHadAnyLinks(PinId pinId);
-
-ImVec2 GetScreenSize();
-ImVec2 ScreenToCanvas(const ImVec2& pos);
-ImVec2 CanvasToScreen(const ImVec2& pos);
-
-int GetNodeCount(); // Returns number of submitted nodes since Begin() call
-int GetOrderedNodeIds(NodeId* nodes, int size); // Fills an array with node id's in order they're drawn; up to 'size` elements are set. Returns actual size of filled id's.
-
-
-
-
-
-
-
-//------------------------------------------------------------------------------
-namespace Details {
-
-template <typename T, typename Tag>
-struct SafeType
-{
- SafeType(T t)
- : m_Value(std::move(t))
- {
- }
-
- SafeType(const SafeType&) = default;
-
- template <typename T2, typename Tag2>
- SafeType(
- const SafeType
- <
- typename std::enable_if<!std::is_same<T, T2>::value, T2>::type,
- typename std::enable_if<!std::is_same<Tag, Tag2>::value, Tag2>::type
- >&) = delete;
-
- SafeType& operator=(const SafeType&) = default;
-
- explicit operator T() const { return Get(); }
-
- T Get() const { return m_Value; }
-
-private:
- T m_Value;
-};
-
-
-template <typename Tag>
-struct SafePointerType
- : SafeType<uintptr_t, Tag>
-{
- static const Tag Invalid;
-
- using SafeType<uintptr_t, Tag>::SafeType;
-
- SafePointerType()
- : SafePointerType(Invalid)
- {
- }
-
- template <typename T = void> explicit SafePointerType(T* ptr): SafePointerType(reinterpret_cast<uintptr_t>(ptr)) {}
- template <typename T = void> T* AsPointer() const { return reinterpret_cast<T*>(this->Get()); }
-
- explicit operator bool() const { return *this != Invalid; }
-};
-
-template <typename Tag>
-const Tag SafePointerType<Tag>::Invalid = { 0 };
-
-template <typename Tag>
-inline bool operator==(const SafePointerType<Tag>& lhs, const SafePointerType<Tag>& rhs)
-{
- return lhs.Get() == rhs.Get();
-}
-
-template <typename Tag>
-inline bool operator!=(const SafePointerType<Tag>& lhs, const SafePointerType<Tag>& rhs)
-{
- return lhs.Get() != rhs.Get();
-}
-
-} // namespace Details
-
-struct NodeId final: Details::SafePointerType<NodeId>
-{
- using SafePointerType::SafePointerType;
-};
-
-struct LinkId final: Details::SafePointerType<LinkId>
-{
- using SafePointerType::SafePointerType;
-};
-
-struct PinId final: Details::SafePointerType<PinId>
-{
- using SafePointerType::SafePointerType;
-};
-
-
-//------------------------------------------------------------------------------
-} // namespace Editor
-} // namespace ax
-
-
-//------------------------------------------------------------------------------
-# endif // __IMGUI_NODE_EDITOR_H__ \ No newline at end of file
diff --git a/3rdparty/imgui-node-editor/imgui_node_editor_api.cpp b/3rdparty/imgui-node-editor/imgui_node_editor_api.cpp
deleted file mode 100644
index cc6cdc0..0000000
--- a/3rdparty/imgui-node-editor/imgui_node_editor_api.cpp
+++ /dev/null
@@ -1,734 +0,0 @@
-//------------------------------------------------------------------------------
-// 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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-//------------------------------------------------------------------------------
-# include "imgui_node_editor_internal.h"
-# include <algorithm>
-
-
-//------------------------------------------------------------------------------
-static ax::NodeEditor::Detail::EditorContext* s_Editor = nullptr;
-
-
-//------------------------------------------------------------------------------
-template <typename C, typename I, typename F>
-static int BuildIdList(C& container, I* list, int listSize, F&& accept)
-{
- if (list != nullptr)
- {
- int count = 0;
- for (auto object : container)
- {
- if (listSize <= 0)
- break;
-
- if (accept(object))
- {
- list[count] = I(object->ID().AsPointer());
- ++count;
- --listSize;}
- }
-
- return count;
- }
- else
- return static_cast<int>(std::count_if(container.begin(), container.end(), accept));
-}
-
-
-//------------------------------------------------------------------------------
-ax::NodeEditor::EditorContext* ax::NodeEditor::CreateEditor(const Config* config)
-{
- return reinterpret_cast<ax::NodeEditor::EditorContext*>(new ax::NodeEditor::Detail::EditorContext(config));
-}
-
-void ax::NodeEditor::DestroyEditor(EditorContext* ctx)
-{
- auto lastContext = GetCurrentEditor();
-
- // Set context we're about to destroy as current, to give callback valid context
- if (lastContext != ctx)
- SetCurrentEditor(ctx);
-
- auto editor = reinterpret_cast<ax::NodeEditor::Detail::EditorContext*>(ctx);
-
- delete editor;
-
- if (lastContext != ctx)
- SetCurrentEditor(lastContext);
-}
-
-void ax::NodeEditor::SetCurrentEditor(EditorContext* ctx)
-{
- s_Editor = reinterpret_cast<ax::NodeEditor::Detail::EditorContext*>(ctx);
-}
-
-ax::NodeEditor::EditorContext* ax::NodeEditor::GetCurrentEditor()
-{
- return reinterpret_cast<ax::NodeEditor::EditorContext*>(s_Editor);
-}
-
-ax::NodeEditor::Style& ax::NodeEditor::GetStyle()
-{
- return s_Editor->GetStyle();
-}
-
-const char* ax::NodeEditor::GetStyleColorName(StyleColor colorIndex)
-{
- return s_Editor->GetStyle().GetColorName(colorIndex);
-}
-
-void ax::NodeEditor::PushStyleColor(StyleColor colorIndex, const ImVec4& color)
-{
- s_Editor->GetStyle().PushColor(colorIndex, color);
-}
-
-void ax::NodeEditor::PopStyleColor(int count)
-{
- s_Editor->GetStyle().PopColor(count);
-}
-
-void ax::NodeEditor::PushStyleVar(StyleVar varIndex, float value)
-{
- s_Editor->GetStyle().PushVar(varIndex, value);
-}
-
-void ax::NodeEditor::PushStyleVar(StyleVar varIndex, const ImVec2& value)
-{
- s_Editor->GetStyle().PushVar(varIndex, value);
-}
-
-void ax::NodeEditor::PushStyleVar(StyleVar varIndex, const ImVec4& value)
-{
- s_Editor->GetStyle().PushVar(varIndex, value);
-}
-
-void ax::NodeEditor::PopStyleVar(int count)
-{
- s_Editor->GetStyle().PopVar(count);
-}
-
-void ax::NodeEditor::Begin(const char* id, const ImVec2& size)
-{
- s_Editor->Begin(id, size);
-}
-
-void ax::NodeEditor::End()
-{
- s_Editor->End();
-}
-
-void ax::NodeEditor::BeginNode(NodeId id)
-{
- s_Editor->GetNodeBuilder().Begin(id);
-}
-
-void ax::NodeEditor::BeginPin(PinId id, PinKind kind)
-{
- s_Editor->GetNodeBuilder().BeginPin(id, kind);
-}
-
-void ax::NodeEditor::PinRect(const ImVec2& a, const ImVec2& b)
-{
- s_Editor->GetNodeBuilder().PinRect(a, b);
-}
-
-void ax::NodeEditor::PinPivotRect(const ImVec2& a, const ImVec2& b)
-{
- s_Editor->GetNodeBuilder().PinPivotRect(a, b);
-}
-
-void ax::NodeEditor::PinPivotSize(const ImVec2& size)
-{
- s_Editor->GetNodeBuilder().PinPivotSize(size);
-}
-
-void ax::NodeEditor::PinPivotScale(const ImVec2& scale)
-{
- s_Editor->GetNodeBuilder().PinPivotScale(scale);
-}
-
-void ax::NodeEditor::PinPivotAlignment(const ImVec2& alignment)
-{
- s_Editor->GetNodeBuilder().PinPivotAlignment(alignment);
-}
-
-void ax::NodeEditor::EndPin()
-{
- s_Editor->GetNodeBuilder().EndPin();
-}
-
-void ax::NodeEditor::Group(const ImVec2& size)
-{
- s_Editor->GetNodeBuilder().Group(size);
-}
-
-void ax::NodeEditor::EndNode()
-{
- s_Editor->GetNodeBuilder().End();
-}
-
-bool ax::NodeEditor::BeginGroupHint(NodeId nodeId)
-{
- return s_Editor->GetHintBuilder().Begin(nodeId);
-}
-
-ImVec2 ax::NodeEditor::GetGroupMin()
-{
- return s_Editor->GetHintBuilder().GetGroupMin();
-}
-
-ImVec2 ax::NodeEditor::GetGroupMax()
-{
- return s_Editor->GetHintBuilder().GetGroupMax();
-}
-
-ImDrawList* ax::NodeEditor::GetHintForegroundDrawList()
-{
- return s_Editor->GetHintBuilder().GetForegroundDrawList();
-}
-
-ImDrawList* ax::NodeEditor::GetHintBackgroundDrawList()
-{
- return s_Editor->GetHintBuilder().GetBackgroundDrawList();
-}
-
-void ax::NodeEditor::EndGroupHint()
-{
- s_Editor->GetHintBuilder().End();
-}
-
-ImDrawList* ax::NodeEditor::GetNodeBackgroundDrawList(NodeId nodeId)
-{
- if (auto node = s_Editor->FindNode(nodeId))
- return s_Editor->GetNodeBuilder().GetUserBackgroundDrawList(node);
- else
- return nullptr;
-}
-
-bool ax::NodeEditor::Link(LinkId id, PinId startPinId, PinId endPinId, const ImVec4& color/* = ImVec4(1, 1, 1, 1)*/, float thickness/* = 1.0f*/)
-{
- return s_Editor->DoLink(id, startPinId, endPinId, ImColor(color), thickness);
-}
-
-void ax::NodeEditor::Flow(LinkId linkId, FlowDirection direction)
-{
- if (auto link = s_Editor->FindLink(linkId))
- s_Editor->Flow(link, direction);
-}
-
-bool ax::NodeEditor::BeginCreate(const ImVec4& color, float thickness)
-{
- auto& context = s_Editor->GetItemCreator();
-
- if (context.Begin())
- {
- context.SetStyle(ImColor(color), thickness);
- return true;
- }
- else
- return false;
-}
-
-bool ax::NodeEditor::QueryNewLink(PinId* startId, PinId* endId)
-{
- using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
-
- auto& context = s_Editor->GetItemCreator();
-
- return context.QueryLink(startId, endId) == Result::True;
-}
-
-bool ax::NodeEditor::QueryNewLink(PinId* startId, PinId* endId, const ImVec4& color, float thickness)
-{
- using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
-
- auto& context = s_Editor->GetItemCreator();
-
- auto result = context.QueryLink(startId, endId);
- if (result != Result::Indeterminate)
- context.SetStyle(ImColor(color), thickness);
-
- return result == Result::True;
-}
-
-bool ax::NodeEditor::QueryNewNode(PinId* pinId)
-{
- using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
-
- auto& context = s_Editor->GetItemCreator();
-
- return context.QueryNode(pinId) == Result::True;
-}
-
-bool ax::NodeEditor::QueryNewNode(PinId* pinId, const ImVec4& color, float thickness)
-{
- using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
-
- auto& context = s_Editor->GetItemCreator();
-
- auto result = context.QueryNode(pinId);
- if (result != Result::Indeterminate)
- context.SetStyle(ImColor(color), thickness);
-
- return result == Result::True;
-}
-
-bool ax::NodeEditor::AcceptNewItem()
-{
- using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
-
- auto& context = s_Editor->GetItemCreator();
-
- return context.AcceptItem() == Result::True;
-}
-
-bool ax::NodeEditor::AcceptNewItem(const ImVec4& color, float thickness)
-{
- using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
-
- auto& context = s_Editor->GetItemCreator();
-
- auto result = context.AcceptItem();
- if (result != Result::Indeterminate)
- context.SetStyle(ImColor(color), thickness);
-
- return result == Result::True;
-}
-
-void ax::NodeEditor::RejectNewItem()
-{
- auto& context = s_Editor->GetItemCreator();
-
- context.RejectItem();
-}
-
-void ax::NodeEditor::RejectNewItem(const ImVec4& color, float thickness)
-{
- using Result = ax::NodeEditor::Detail::CreateItemAction::Result;
-
- auto& context = s_Editor->GetItemCreator();
-
- if (context.RejectItem() != Result::Indeterminate)
- context.SetStyle(ImColor(color), thickness);
-}
-
-void ax::NodeEditor::EndCreate()
-{
- auto& context = s_Editor->GetItemCreator();
-
- context.End();
-}
-
-bool ax::NodeEditor::BeginDelete()
-{
- auto& context = s_Editor->GetItemDeleter();
-
- return context.Begin();
-}
-
-bool ax::NodeEditor::QueryDeletedLink(LinkId* linkId, PinId* startId, PinId* endId)
-{
- auto& context = s_Editor->GetItemDeleter();
-
- return context.QueryLink(linkId, startId, endId);
-}
-
-bool ax::NodeEditor::QueryDeletedNode(NodeId* nodeId)
-{
- auto& context = s_Editor->GetItemDeleter();
-
- return context.QueryNode(nodeId);
-}
-
-bool ax::NodeEditor::AcceptDeletedItem(bool deleteDependencies)
-{
- auto& context = s_Editor->GetItemDeleter();
-
- return context.AcceptItem(deleteDependencies);
-}
-
-void ax::NodeEditor::RejectDeletedItem()
-{
- auto& context = s_Editor->GetItemDeleter();
-
- context.RejectItem();
-}
-
-void ax::NodeEditor::EndDelete()
-{
- auto& context = s_Editor->GetItemDeleter();
-
- context.End();
-}
-
-void ax::NodeEditor::SetNodePosition(NodeId nodeId, const ImVec2& position)
-{
- s_Editor->SetNodePosition(nodeId, position);
-}
-
-void ax::NodeEditor::SetGroupSize(NodeId nodeId, const ImVec2& size)
-{
- s_Editor->SetGroupSize(nodeId, size);
-}
-
-ImVec2 ax::NodeEditor::GetNodePosition(NodeId nodeId)
-{
- return s_Editor->GetNodePosition(nodeId);
-}
-
-ImVec2 ax::NodeEditor::GetNodeSize(NodeId nodeId)
-{
- return s_Editor->GetNodeSize(nodeId);
-}
-
-void ax::NodeEditor::CenterNodeOnScreen(NodeId nodeId)
-{
- if (auto node = s_Editor->FindNode(nodeId))
- node->CenterOnScreenInNextFrame();
-}
-
-void ax::NodeEditor::SetNodeZPosition(NodeId nodeId, float z)
-{
- s_Editor->SetNodeZPosition(nodeId, z);
-}
-
-float ax::NodeEditor::GetNodeZPosition(NodeId nodeId)
-{
- return s_Editor->GetNodeZPosition(nodeId);
-}
-
-void ax::NodeEditor::RestoreNodeState(NodeId nodeId)
-{
- if (auto node = s_Editor->FindNode(nodeId))
- s_Editor->MarkNodeToRestoreState(node);
-}
-
-void ax::NodeEditor::Suspend()
-{
- s_Editor->Suspend();
-}
-
-void ax::NodeEditor::Resume()
-{
- s_Editor->Resume();
-}
-
-bool ax::NodeEditor::IsSuspended()
-{
- return s_Editor->IsSuspended();
-}
-
-bool ax::NodeEditor::IsActive()
-{
- return s_Editor->IsFocused();
-}
-
-bool ax::NodeEditor::HasSelectionChanged()
-{
- return s_Editor->HasSelectionChanged();
-}
-
-int ax::NodeEditor::GetSelectedObjectCount()
-{
- return (int)s_Editor->GetSelectedObjects().size();
-}
-
-int ax::NodeEditor::GetSelectedNodes(NodeId* nodes, int size)
-{
- return BuildIdList(s_Editor->GetSelectedObjects(), nodes, size, [](auto object)
- {
- return object->AsNode() != nullptr;
- });
-}
-
-int ax::NodeEditor::GetSelectedLinks(LinkId* links, int size)
-{
- return BuildIdList(s_Editor->GetSelectedObjects(), links, size, [](auto object)
- {
- return object->AsLink() != nullptr;
- });
-}
-
-bool ax::NodeEditor::IsNodeSelected(NodeId nodeId)
-{
- if (auto node = s_Editor->FindNode(nodeId))
- return s_Editor->IsSelected(node);
- else
- return false;
-}
-
-bool ax::NodeEditor::IsLinkSelected(LinkId linkId)
-{
- if (auto link = s_Editor->FindLink(linkId))
- return s_Editor->IsSelected(link);
- else
- return false;
-}
-
-void ax::NodeEditor::ClearSelection()
-{
- s_Editor->ClearSelection();
-}
-
-void ax::NodeEditor::SelectNode(NodeId nodeId, bool append)
-{
- if (auto node = s_Editor->FindNode(nodeId))
- {
- if (append)
- s_Editor->SelectObject(node);
- else
- s_Editor->SetSelectedObject(node);
- }
-}
-
-void ax::NodeEditor::SelectLink(LinkId linkId, bool append)
-{
- if (auto link = s_Editor->FindLink(linkId))
- {
- if (append)
- s_Editor->SelectObject(link);
- else
- s_Editor->SetSelectedObject(link);
- }
-}
-
-void ax::NodeEditor::DeselectNode(NodeId nodeId)
-{
- if (auto node = s_Editor->FindNode(nodeId))
- s_Editor->DeselectObject(node);
-}
-
-void ax::NodeEditor::DeselectLink(LinkId linkId)
-{
- if (auto link = s_Editor->FindLink(linkId))
- s_Editor->DeselectObject(link);
-}
-
-bool ax::NodeEditor::DeleteNode(NodeId nodeId)
-{
- if (auto node = s_Editor->FindNode(nodeId))
- return s_Editor->GetItemDeleter().Add(node);
- else
- return false;
-}
-
-bool ax::NodeEditor::DeleteLink(LinkId linkId)
-{
- if (auto link = s_Editor->FindLink(linkId))
- return s_Editor->GetItemDeleter().Add(link);
- else
- return false;
-}
-
-bool ax::NodeEditor::HasAnyLinks(NodeId nodeId)
-{
- return s_Editor->HasAnyLinks(nodeId);
-}
-
-bool ax::NodeEditor::HasAnyLinks(PinId pinId)
-{
- return s_Editor->HasAnyLinks(pinId);
-}
-
-int ax::NodeEditor::BreakLinks(NodeId nodeId)
-{
- return s_Editor->BreakLinks(nodeId);
-}
-
-int ax::NodeEditor::BreakLinks(PinId pinId)
-{
- return s_Editor->BreakLinks(pinId);
-}
-
-void ax::NodeEditor::NavigateToContent(float duration)
-{
- s_Editor->NavigateTo(s_Editor->GetContentBounds(), true, duration);
-}
-
-void ax::NodeEditor::NavigateToSelection(bool zoomIn, float duration)
-{
- s_Editor->NavigateTo(s_Editor->GetSelectionBounds(), zoomIn, duration);
-}
-
-bool ax::NodeEditor::ShowNodeContextMenu(NodeId* nodeId)
-{
- return s_Editor->GetContextMenu().ShowNodeContextMenu(nodeId);
-}
-
-bool ax::NodeEditor::ShowPinContextMenu(PinId* pinId)
-{
- return s_Editor->GetContextMenu().ShowPinContextMenu(pinId);
-}
-
-bool ax::NodeEditor::ShowLinkContextMenu(LinkId* linkId)
-{
- return s_Editor->GetContextMenu().ShowLinkContextMenu(linkId);
-}
-
-bool ax::NodeEditor::ShowBackgroundContextMenu()
-{
- return s_Editor->GetContextMenu().ShowBackgroundContextMenu();
-}
-
-void ax::NodeEditor::EnableShortcuts(bool enable)
-{
- s_Editor->EnableShortcuts(enable);
-}
-
-bool ax::NodeEditor::AreShortcutsEnabled()
-{
- return s_Editor->AreShortcutsEnabled();
-}
-
-bool ax::NodeEditor::BeginShortcut()
-{
- return s_Editor->GetShortcut().Begin();
-}
-
-bool ax::NodeEditor::AcceptCut()
-{
- return s_Editor->GetShortcut().AcceptCut();
-}
-
-bool ax::NodeEditor::AcceptCopy()
-{
- return s_Editor->GetShortcut().AcceptCopy();
-}
-
-bool ax::NodeEditor::AcceptPaste()
-{
- return s_Editor->GetShortcut().AcceptPaste();
-}
-
-bool ax::NodeEditor::AcceptDuplicate()
-{
- return s_Editor->GetShortcut().AcceptDuplicate();
-}
-
-bool ax::NodeEditor::AcceptCreateNode()
-{
- return s_Editor->GetShortcut().AcceptCreateNode();
-}
-
-int ax::NodeEditor::GetActionContextSize()
-{
- return static_cast<int>(s_Editor->GetShortcut().m_Context.size());
-}
-
-int ax::NodeEditor::GetActionContextNodes(NodeId* nodes, int size)
-{
- return BuildIdList(s_Editor->GetSelectedObjects(), nodes, size, [](auto object)
- {
- return object->AsNode() != nullptr;
- });
-}
-
-int ax::NodeEditor::GetActionContextLinks(LinkId* links, int size)
-{
- return BuildIdList(s_Editor->GetSelectedObjects(), links, size, [](auto object)
- {
- return object->AsLink() != nullptr;
- });
-}
-
-void ax::NodeEditor::EndShortcut()
-{
- return s_Editor->GetShortcut().End();
-}
-
-float ax::NodeEditor::GetCurrentZoom()
-{
- return s_Editor->GetView().InvScale;
-}
-
-ax::NodeEditor::NodeId ax::NodeEditor::GetHoveredNode()
-{
- return s_Editor->GetHoveredNode();
-}
-
-ax::NodeEditor::PinId ax::NodeEditor::GetHoveredPin()
-{
- return s_Editor->GetHoveredPin();
-}
-
-ax::NodeEditor::LinkId ax::NodeEditor::GetHoveredLink()
-{
- return s_Editor->GetHoveredLink();
-}
-
-ax::NodeEditor::NodeId ax::NodeEditor::GetDoubleClickedNode()
-{
- return s_Editor->GetDoubleClickedNode();
-}
-
-ax::NodeEditor::PinId ax::NodeEditor::GetDoubleClickedPin()
-{
- return s_Editor->GetDoubleClickedPin();
-}
-
-ax::NodeEditor::LinkId ax::NodeEditor::GetDoubleClickedLink()
-{
- return s_Editor->GetDoubleClickedLink();
-}
-
-bool ax::NodeEditor::IsBackgroundClicked()
-{
- return s_Editor->IsBackgroundClicked();
-}
-
-bool ax::NodeEditor::IsBackgroundDoubleClicked()
-{
- return s_Editor->IsBackgroundDoubleClicked();
-}
-
-bool ax::NodeEditor::GetLinkPins(LinkId linkId, PinId* startPinId, PinId* endPinId)
-{
- auto link = s_Editor->FindLink(linkId);
- if (!link)
- return false;
-
- if (startPinId)
- *startPinId = link->m_StartPin->m_ID;
- if (endPinId)
- *endPinId = link->m_EndPin->m_ID;
-
- return true;
-}
-
-bool ax::NodeEditor::PinHadAnyLinks(PinId pinId)
-{
- return s_Editor->PinHadAnyLinks(pinId);
-}
-
-ImVec2 ax::NodeEditor::GetScreenSize()
-{
- return s_Editor->GetRect().GetSize();
-}
-
-ImVec2 ax::NodeEditor::ScreenToCanvas(const ImVec2& pos)
-{
- return s_Editor->ToCanvas(pos);
-}
-
-ImVec2 ax::NodeEditor::CanvasToScreen(const ImVec2& pos)
-{
- return s_Editor->ToScreen(pos);
-}
-
-int ax::NodeEditor::GetNodeCount()
-{
- return s_Editor->CountLiveNodes();
-}
-
-int ax::NodeEditor::GetOrderedNodeIds(NodeId* nodes, int size)
-{
- return s_Editor->GetNodeIds(nodes, size);
-}
diff --git a/3rdparty/imgui-node-editor/imgui_node_editor_internal.h b/3rdparty/imgui-node-editor/imgui_node_editor_internal.h
deleted file mode 100644
index 90fc885..0000000
--- a/3rdparty/imgui-node-editor/imgui_node_editor_internal.h
+++ /dev/null
@@ -1,1536 +0,0 @@
-//------------------------------------------------------------------------------
-// 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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-//------------------------------------------------------------------------------
-# ifndef __IMGUI_NODE_EDITOR_INTERNAL_H__
-# define __IMGUI_NODE_EDITOR_INTERNAL_H__
-# pragma once
-
-
-//------------------------------------------------------------------------------
-# include "imgui_node_editor.h"
-
-
-//------------------------------------------------------------------------------
-# include <imgui.h>
-# define IMGUI_DEFINE_MATH_OPERATORS
-# include <imgui_internal.h>
-# include "imgui_extra_math.h"
-# include "imgui_bezier_math.h"
-# include "imgui_canvas.h"
-
-# include "crude_json.h"
-
-# include <vector>
-# include <string>
-
-
-//------------------------------------------------------------------------------
-namespace ax {
-namespace NodeEditor {
-namespace Detail {
-
-
-//------------------------------------------------------------------------------
-namespace ed = ax::NodeEditor::Detail;
-namespace json = crude_json;
-
-
-//------------------------------------------------------------------------------
-using std::vector;
-using std::string;
-
-
-//------------------------------------------------------------------------------
-void Log(const char* fmt, ...);
-
-
-//------------------------------------------------------------------------------
-//inline ImRect ToRect(const ax::rectf& rect);
-//inline ImRect ToRect(const ax::rect& rect);
-inline ImRect ImGui_GetItemRect();
-
-
-//------------------------------------------------------------------------------
-// https://stackoverflow.com/a/36079786
-# define DECLARE_HAS_MEMBER(__trait_name__, __member_name__) \
- \
- template <typename __boost_has_member_T__> \
- class __trait_name__ \
- { \
- using check_type = ::std::remove_const_t<__boost_has_member_T__>; \
- struct no_type {char x[2];}; \
- using yes_type = char; \
- \
- struct base { void __member_name__() {}}; \
- struct mixin : public base, public check_type {}; \
- \
- template <void (base::*)()> struct aux {}; \
- \
- template <typename U> static no_type test(aux<&U::__member_name__>*); \
- template <typename U> static yes_type test(...); \
- \
- public: \
- \
- static constexpr bool value = (sizeof(yes_type) == sizeof(test<mixin>(0))); \
- }
-
-DECLARE_HAS_MEMBER(HasFringeScale, _FringeScale);
-
-# undef DECLARE_HAS_MEMBER
-
-struct FringeScaleRef
-{
- // Overload is present when ImDrawList does have _FringeScale member variable.
- template <typename T>
- static float& Get(typename std::enable_if<HasFringeScale<T>::value, T>::type* drawList)
- {
- return drawList->_FringeScale;
- }
-
- // Overload is present when ImDrawList does not have _FringeScale member variable.
- template <typename T>
- static float& Get(typename std::enable_if<!HasFringeScale<T>::value, T>::type*)
- {
- static float placeholder = 1.0f;
- return placeholder;
- }
-};
-
-static inline float& ImFringeScaleRef(ImDrawList* drawList)
-{
- return FringeScaleRef::Get<ImDrawList>(drawList);
-}
-
-struct FringeScaleScope
-{
-
- FringeScaleScope(float scale)
- : m_LastFringeScale(ImFringeScaleRef(ImGui::GetWindowDrawList()))
- {
- ImFringeScaleRef(ImGui::GetWindowDrawList()) = scale;
- }
-
- ~FringeScaleScope()
- {
- ImFringeScaleRef(ImGui::GetWindowDrawList()) = m_LastFringeScale;
- }
-
-private:
- float m_LastFringeScale;
-};
-
-
-//------------------------------------------------------------------------------
-enum class ObjectType
-{
- None,
- Node,
- Link,
- Pin
-};
-
-using ax::NodeEditor::PinKind;
-using ax::NodeEditor::StyleColor;
-using ax::NodeEditor::StyleVar;
-using ax::NodeEditor::SaveReasonFlags;
-
-using ax::NodeEditor::NodeId;
-using ax::NodeEditor::PinId;
-using ax::NodeEditor::LinkId;
-
-struct ObjectId final: Details::SafePointerType<ObjectId>
-{
- using Super = Details::SafePointerType<ObjectId>;
- using Super::Super;
-
- ObjectId(): Super(Invalid), m_Type(ObjectType::None) {}
- ObjectId(PinId pinId): Super(pinId.AsPointer()), m_Type(ObjectType::Pin) {}
- ObjectId(NodeId nodeId): Super(nodeId.AsPointer()), m_Type(ObjectType::Node) {}
- ObjectId(LinkId linkId): Super(linkId.AsPointer()), m_Type(ObjectType::Link) {}
-
- explicit operator PinId() const { return AsPinId(); }
- explicit operator NodeId() const { return AsNodeId(); }
- explicit operator LinkId() const { return AsLinkId(); }
-
- PinId AsPinId() const { IM_ASSERT(IsPinId()); return PinId(AsPointer()); }
- NodeId AsNodeId() const { IM_ASSERT(IsNodeId()); return NodeId(AsPointer()); }
- LinkId AsLinkId() const { IM_ASSERT(IsLinkId()); return LinkId(AsPointer()); }
-
- bool IsPinId() const { return m_Type == ObjectType::Pin; }
- bool IsNodeId() const { return m_Type == ObjectType::Node; }
- bool IsLinkId() const { return m_Type == ObjectType::Link; }
-
- ObjectType Type() const { return m_Type; }
-
-private:
- ObjectType m_Type;
-};
-
-struct EditorContext;
-
-struct Node;
-struct Pin;
-struct Link;
-
-template <typename T, typename Id = typename T::IdType>
-struct ObjectWrapper
-{
- Id m_ID;
- T* m_Object;
-
- T* operator->() { return m_Object; }
- const T* operator->() const { return m_Object; }
-
- operator T*() { return m_Object; }
- operator const T*() const { return m_Object; }
-
- bool operator<(const ObjectWrapper& rhs) const
- {
- return m_ID.AsPointer() < rhs.m_ID.AsPointer();
- }
-};
-
-struct Object
-{
- enum DrawFlags
- {
- None = 0,
- Hovered = 1,
- Selected = 2
- };
-
- inline friend DrawFlags operator|(DrawFlags lhs, DrawFlags rhs) { return static_cast<DrawFlags>(static_cast<int>(lhs) | static_cast<int>(rhs)); }
- inline friend DrawFlags operator&(DrawFlags lhs, DrawFlags rhs) { return static_cast<DrawFlags>(static_cast<int>(lhs) & static_cast<int>(rhs)); }
- inline friend DrawFlags& operator|=(DrawFlags& lhs, DrawFlags rhs) { lhs = lhs | rhs; return lhs; }
- inline friend DrawFlags& operator&=(DrawFlags& lhs, DrawFlags rhs) { lhs = lhs & rhs; return lhs; }
-
- EditorContext* const Editor;
-
- bool m_IsLive;
-
- Object(EditorContext* editor)
- : Editor(editor)
- , m_IsLive(true)
- {
- }
-
- virtual ~Object() = default;
-
- virtual ObjectId ID() = 0;
-
- bool IsVisible() const
- {
- if (!m_IsLive)
- return false;
-
- const auto bounds = GetBounds();
-
- return ImGui::IsRectVisible(bounds.Min, bounds.Max);
- }
-
- virtual void Reset() { m_IsLive = false; }
-
- virtual void Draw(ImDrawList* drawList, DrawFlags flags = None) = 0;
-
- virtual bool AcceptDrag() { return false; }
- virtual void UpdateDrag(const ImVec2& offset) { IM_UNUSED(offset); }
- virtual bool EndDrag() { return false; }
- virtual ImVec2 DragStartLocation() { return GetBounds().Min; }
-
- virtual bool IsDraggable() { bool result = AcceptDrag(); EndDrag(); return result; }
- virtual bool IsSelectable() { return false; }
-
- virtual bool TestHit(const ImVec2& point, float extraThickness = 0.0f) const
- {
- if (!m_IsLive)
- return false;
-
- auto bounds = GetBounds();
- if (extraThickness > 0)
- bounds.Expand(extraThickness);
-
- return bounds.Contains(point);
- }
-
- virtual bool TestHit(const ImRect& rect, bool allowIntersect = true) const
- {
- if (!m_IsLive)
- return false;
-
- const auto bounds = GetBounds();
-
- return !ImRect_IsEmpty(bounds) && (allowIntersect ? bounds.Overlaps(rect) : rect.Contains(bounds));
- }
-
- virtual ImRect GetBounds() const = 0;
-
- virtual Node* AsNode() { return nullptr; }
- virtual Pin* AsPin() { return nullptr; }
- virtual Link* AsLink() { return nullptr; }
-};
-
-struct Pin final: Object
-{
- using IdType = PinId;
-
- PinId m_ID;
- PinKind m_Kind;
- Node* m_Node;
- ImRect m_Bounds;
- ImRect m_Pivot;
- Pin* m_PreviousPin;
- ImU32 m_Color;
- ImU32 m_BorderColor;
- float m_BorderWidth;
- float m_Rounding;
- int m_Corners;
- ImVec2 m_Dir;
- float m_Strength;
- float m_Radius;
- float m_ArrowSize;
- float m_ArrowWidth;
- bool m_HasConnection;
- bool m_HadConnection;
-
- Pin(EditorContext* editor, PinId id, PinKind kind)
- : Object(editor)
- , m_ID(id)
- , m_Kind(kind)
- , m_Node(nullptr)
- , m_Bounds()
- , m_PreviousPin(nullptr)
- , m_Color(IM_COL32_WHITE)
- , m_BorderColor(IM_COL32_BLACK)
- , m_BorderWidth(0)
- , m_Rounding(0)
- , m_Corners(0)
- , m_Dir(0, 0)
- , m_Strength(0)
- , m_Radius(0)
- , m_ArrowSize(0)
- , m_ArrowWidth(0)
- , m_HasConnection(false)
- , m_HadConnection(false)
- {
- }
-
- virtual ObjectId ID() override { return m_ID; }
-
- virtual void Reset() override final
- {
- m_HadConnection = m_HasConnection && m_IsLive;
- m_HasConnection = false;
-
- Object::Reset();
- }
-
- virtual void Draw(ImDrawList* drawList, DrawFlags flags = None) override final;
-
- ImVec2 GetClosestPoint(const ImVec2& p) const;
- ImLine GetClosestLine(const Pin* pin) const;
-
- virtual ImRect GetBounds() const override final { return m_Bounds; }
-
- virtual Pin* AsPin() override final { return this; }
-};
-
-enum class NodeType
-{
- Node,
- Group
-};
-
-enum class NodeRegion : uint8_t
-{
- None = 0x00,
- Top = 0x01,
- Bottom = 0x02,
- Left = 0x04,
- Right = 0x08,
- Center = 0x10,
- Header = 0x20,
- TopLeft = Top | Left,
- TopRight = Top | Right,
- BottomLeft = Bottom | Left,
- BottomRight = Bottom | Right,
-};
-
-inline NodeRegion operator |(NodeRegion lhs, NodeRegion rhs) { return static_cast<NodeRegion>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs)); }
-inline NodeRegion operator &(NodeRegion lhs, NodeRegion rhs) { return static_cast<NodeRegion>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs)); }
-
-
-struct Node final: Object
-{
- using IdType = NodeId;
-
- NodeId m_ID;
- NodeType m_Type;
- ImRect m_Bounds;
- float m_ZPosition;
- int m_Channel;
- Pin* m_LastPin;
- ImVec2 m_DragStart;
-
- ImU32 m_Color;
- ImU32 m_BorderColor;
- float m_BorderWidth;
- float m_Rounding;
-
- ImU32 m_GroupColor;
- ImU32 m_GroupBorderColor;
- float m_GroupBorderWidth;
- float m_GroupRounding;
- ImRect m_GroupBounds;
-
- bool m_RestoreState;
- bool m_CenterOnScreen;
-
- Node(EditorContext* editor, NodeId id)
- : Object(editor)
- , m_ID(id)
- , m_Type(NodeType::Node)
- , m_Bounds()
- , m_ZPosition(0.0f)
- , m_Channel(0)
- , m_LastPin(nullptr)
- , m_DragStart()
- , m_Color(IM_COL32_WHITE)
- , m_BorderColor(IM_COL32_BLACK)
- , m_BorderWidth(0)
- , m_Rounding(0)
- , m_GroupBounds()
- , m_RestoreState(false)
- , m_CenterOnScreen(false)
- {
- }
-
- virtual ObjectId ID() override { return m_ID; }
-
- bool AcceptDrag() override;
- void UpdateDrag(const ImVec2& offset) override;
- bool EndDrag() override; // return true, when changed
- ImVec2 DragStartLocation() override { return m_DragStart; }
-
- virtual bool IsSelectable() override { return true; }
-
- virtual void Draw(ImDrawList* drawList, DrawFlags flags = None) override final;
- void DrawBorder(ImDrawList* drawList, ImU32 color, float thickness = 1.0f);
-
- void GetGroupedNodes(std::vector<Node*>& result, bool append = false);
-
- void CenterOnScreenInNextFrame() { m_CenterOnScreen = true; }
-
- ImRect GetRegionBounds(NodeRegion region) const;
- NodeRegion GetRegion(const ImVec2& point) const;
-
- virtual ImRect GetBounds() const override final { return m_Bounds; }
-
- virtual Node* AsNode() override final { return this; }
-};
-
-struct Link final: Object
-{
- using IdType = LinkId;
-
- LinkId m_ID;
- Pin* m_StartPin;
- Pin* m_EndPin;
- ImU32 m_Color;
- float m_Thickness;
- ImVec2 m_Start;
- ImVec2 m_End;
-
- Link(EditorContext* editor, LinkId id)
- : Object(editor)
- , m_ID(id)
- , m_StartPin(nullptr)
- , m_EndPin(nullptr)
- , m_Color(IM_COL32_WHITE)
- , m_Thickness(1.0f)
- {
- }
-
- virtual ObjectId ID() override { return m_ID; }
-
- virtual bool IsSelectable() override { return true; }
-
- virtual void Draw(ImDrawList* drawList, DrawFlags flags = None) override final;
- void Draw(ImDrawList* drawList, ImU32 color, float extraThickness = 0.0f) const;
-
- void UpdateEndpoints();
-
- ImCubicBezierPoints GetCurve() const;
-
- virtual bool TestHit(const ImVec2& point, float extraThickness = 0.0f) const override final;
- virtual bool TestHit(const ImRect& rect, bool allowIntersect = true) const override final;
-
- virtual ImRect GetBounds() const override final;
-
- virtual Link* AsLink() override final { return this; }
-};
-
-struct NodeSettings
-{
- NodeId m_ID;
- ImVec2 m_Location;
- ImVec2 m_Size;
- ImVec2 m_GroupSize;
- bool m_WasUsed;
-
- bool m_Saved;
- bool m_IsDirty;
- SaveReasonFlags m_DirtyReason;
-
- NodeSettings(NodeId id)
- : m_ID(id)
- , m_Location(0, 0)
- , m_Size(0, 0)
- , m_GroupSize(0, 0)
- , m_WasUsed(false)
- , m_Saved(false)
- , m_IsDirty(false)
- , m_DirtyReason(SaveReasonFlags::None)
- {
- }
-
- void ClearDirty();
- void MakeDirty(SaveReasonFlags reason);
-
- json::value Serialize();
-
- static bool Parse(const std::string& string, NodeSettings& settings);
- static bool Parse(const json::value& data, NodeSettings& result);
-};
-
-struct Settings
-{
- bool m_IsDirty;
- SaveReasonFlags m_DirtyReason;
-
- vector<NodeSettings> m_Nodes;
- vector<ObjectId> m_Selection;
- ImVec2 m_ViewScroll;
- float m_ViewZoom;
- ImRect m_VisibleRect;
-
- Settings()
- : m_IsDirty(false)
- , m_DirtyReason(SaveReasonFlags::None)
- , m_ViewScroll(0, 0)
- , m_ViewZoom(1.0f)
- , m_VisibleRect()
- {
- }
-
- NodeSettings* AddNode(NodeId id);
- NodeSettings* FindNode(NodeId id);
- void RemoveNode(NodeId id);
-
- void ClearDirty(Node* node = nullptr);
- void MakeDirty(SaveReasonFlags reason, Node* node = nullptr);
-
- std::string Serialize();
-
- static bool Parse(const std::string& string, Settings& settings);
-};
-
-struct Control
-{
- Object* HotObject;
- Object* ActiveObject;
- Object* ClickedObject;
- Object* DoubleClickedObject;
- Node* HotNode;
- Node* ActiveNode;
- Node* ClickedNode;
- Node* DoubleClickedNode;
- Pin* HotPin;
- Pin* ActivePin;
- Pin* ClickedPin;
- Pin* DoubleClickedPin;
- Link* HotLink;
- Link* ActiveLink;
- Link* ClickedLink;
- Link* DoubleClickedLink;
- bool BackgroundHot;
- bool BackgroundActive;
- bool BackgroundClicked;
- bool BackgroundDoubleClicked;
-
- Control()
- : Control(nullptr, nullptr, nullptr, nullptr, false, false, false, false)
- {
- }
-
- Control(Object* hotObject, Object* activeObject, Object* clickedObject, Object* doubleClickedObject,
- bool backgroundHot, bool backgroundActive, bool backgroundClicked, bool backgroundDoubleClicked)
- : HotObject(hotObject)
- , ActiveObject(activeObject)
- , ClickedObject(clickedObject)
- , DoubleClickedObject(doubleClickedObject)
- , HotNode(nullptr)
- , ActiveNode(nullptr)
- , ClickedNode(nullptr)
- , DoubleClickedNode(nullptr)
- , HotPin(nullptr)
- , ActivePin(nullptr)
- , ClickedPin(nullptr)
- , DoubleClickedPin(nullptr)
- , HotLink(nullptr)
- , ActiveLink(nullptr)
- , ClickedLink(nullptr)
- , DoubleClickedLink(nullptr)
- , BackgroundHot(backgroundHot)
- , BackgroundActive(backgroundActive)
- , BackgroundClicked(backgroundClicked)
- , BackgroundDoubleClicked(backgroundDoubleClicked)
- {
- if (hotObject)
- {
- HotNode = hotObject->AsNode();
- HotPin = hotObject->AsPin();
- HotLink = hotObject->AsLink();
-
- if (HotPin)
- HotNode = HotPin->m_Node;
- }
-
- if (activeObject)
- {
- ActiveNode = activeObject->AsNode();
- ActivePin = activeObject->AsPin();
- ActiveLink = activeObject->AsLink();
- }
-
- if (clickedObject)
- {
- ClickedNode = clickedObject->AsNode();
- ClickedPin = clickedObject->AsPin();
- ClickedLink = clickedObject->AsLink();
- }
-
- if (doubleClickedObject)
- {
- DoubleClickedNode = doubleClickedObject->AsNode();
- DoubleClickedPin = doubleClickedObject->AsPin();
- DoubleClickedLink = doubleClickedObject->AsLink();
- }
- }
-};
-
-struct NavigateAction;
-struct SizeAction;
-struct DragAction;
-struct SelectAction;
-struct CreateItemAction;
-struct DeleteItemsAction;
-struct ContextMenuAction;
-struct ShortcutAction;
-
-struct AnimationController;
-struct FlowAnimationController;
-
-struct Animation
-{
- enum State
- {
- Playing,
- Stopped
- };
-
- EditorContext* Editor;
- State m_State;
- float m_Time;
- float m_Duration;
-
- Animation(EditorContext* editor);
- virtual ~Animation();
-
- void Play(float duration);
- void Stop();
- void Finish();
- void Update();
-
- bool IsPlaying() const { return m_State == Playing; }
-
- float GetProgress() const { return m_Time / m_Duration; }
-
-protected:
- virtual void OnPlay() {}
- virtual void OnFinish() {}
- virtual void OnStop() {}
-
- virtual void OnUpdate(float progress) { IM_UNUSED(progress); }
-};
-
-struct NavigateAnimation final: Animation
-{
- NavigateAction& Action;
- ImRect m_Start;
- ImRect m_Target;
-
- NavigateAnimation(EditorContext* editor, NavigateAction& scrollAction);
-
- void NavigateTo(const ImRect& target, float duration);
-
-private:
- void OnUpdate(float progress) override final;
- void OnStop() override final;
- void OnFinish() override final;
-};
-
-struct FlowAnimation final: Animation
-{
- FlowAnimationController* Controller;
- Link* m_Link;
- float m_Speed;
- float m_MarkerDistance;
- float m_Offset;
-
- FlowAnimation(FlowAnimationController* controller);
-
- void Flow(Link* link, float markerDistance, float speed, float duration);
-
- void Draw(ImDrawList* drawList);
-
-private:
- struct CurvePoint
- {
- float Distance;
- ImVec2 Point;
- };
-
- ImVec2 m_LastStart;
- ImVec2 m_LastEnd;
- float m_PathLength;
- vector<CurvePoint> m_Path;
-
- bool IsLinkValid() const;
- bool IsPathValid() const;
- void UpdatePath();
- void ClearPath();
-
- ImVec2 SamplePath(float distance) const;
-
- void OnUpdate(float progress) override final;
- void OnStop() override final;
-};
-
-struct AnimationController
-{
- EditorContext* Editor;
-
- AnimationController(EditorContext* editor)
- : Editor(editor)
- {
- }
-
- virtual ~AnimationController()
- {
- }
-
- virtual void Draw(ImDrawList* drawList)
- {
- IM_UNUSED(drawList);
- }
-};
-
-struct FlowAnimationController final : AnimationController
-{
- FlowAnimationController(EditorContext* editor);
- virtual ~FlowAnimationController();
-
- void Flow(Link* link, FlowDirection direction = FlowDirection::Forward);
-
- virtual void Draw(ImDrawList* drawList) override final;
-
- void Release(FlowAnimation* animation);
-
-private:
- FlowAnimation* GetOrCreate(Link* link);
-
- vector<FlowAnimation*> m_Animations;
- vector<FlowAnimation*> m_FreePool;
-};
-
-struct EditorAction
-{
- enum AcceptResult { False, True, Possible };
-
- EditorAction(EditorContext* editor)
- : Editor(editor)
- {
- }
-
- virtual ~EditorAction() {}
-
- virtual const char* GetName() const = 0;
-
- virtual AcceptResult Accept(const Control& control) = 0;
- virtual bool Process(const Control& control) = 0;
- virtual void Reject() {} // celled when Accept return 'Possible' and was rejected
-
- virtual ImGuiMouseCursor GetCursor() { return ImGuiMouseCursor_Arrow; }
-
- virtual bool IsDragging() { return false; }
-
- virtual void ShowMetrics() {}
-
- virtual NavigateAction* AsNavigate() { return nullptr; }
- virtual SizeAction* AsSize() { return nullptr; }
- virtual DragAction* AsDrag() { return nullptr; }
- virtual SelectAction* AsSelect() { return nullptr; }
- virtual CreateItemAction* AsCreateItem() { return nullptr; }
- virtual DeleteItemsAction* AsDeleteItems() { return nullptr; }
- virtual ContextMenuAction* AsContextMenu() { return nullptr; }
- virtual ShortcutAction* AsCutCopyPaste() { return nullptr; }
-
- EditorContext* Editor;
-};
-
-struct NavigateAction final: EditorAction
-{
- enum class ZoomMode
- {
- None,
- Exact,
- WithMargin
- };
-
- enum class NavigationReason
- {
- Unknown,
- MouseZoom,
- Selection,
- Object,
- Content,
- Edge
- };
-
- bool m_IsActive;
- float m_Zoom;
- ImRect m_VisibleRect;
- ImVec2 m_Scroll;
- ImVec2 m_ScrollStart;
- ImVec2 m_ScrollDelta;
-
- NavigateAction(EditorContext* editor, ImGuiEx::Canvas& canvas);
-
- virtual const char* GetName() const override final { return "Navigate"; }
-
- virtual AcceptResult Accept(const Control& control) override final;
- virtual bool Process(const Control& control) override final;
-
- virtual void ShowMetrics() override final;
-
- virtual NavigateAction* AsNavigate() override final { return this; }
-
- void NavigateTo(const ImRect& bounds, ZoomMode zoomMode, float duration = -1.0f, NavigationReason reason = NavigationReason::Unknown);
- void StopNavigation();
- void FinishNavigation();
-
- bool MoveOverEdge(const ImVec2& canvasSize);
- void StopMoveOverEdge();
- bool IsMovingOverEdge() const { return m_MovingOverEdge; }
- ImVec2 GetMoveScreenOffset() const { return m_MoveScreenOffset; }
-
- void SetWindow(ImVec2 position, ImVec2 size);
- ImVec2 GetWindowScreenPos() const { return m_WindowScreenPos; };
- ImVec2 GetWindowScreenSize() const { return m_WindowScreenSize; };
-
- ImGuiEx::CanvasView GetView() const;
- ImVec2 GetViewOrigin() const;
- float GetViewScale() const;
-
- void SetViewRect(const ImRect& rect);
- ImRect GetViewRect() const;
-
-private:
- ImGuiEx::Canvas& m_Canvas;
- ImVec2 m_WindowScreenPos;
- ImVec2 m_WindowScreenSize;
-
- NavigateAnimation m_Animation;
- NavigationReason m_Reason;
- uint64_t m_LastSelectionId;
- Object* m_LastObject;
- bool m_MovingOverEdge;
- ImVec2 m_MoveScreenOffset;
-
- bool HandleZoom(const Control& control);
-
- void NavigateTo(const ImRect& target, float duration = -1.0f, NavigationReason reason = NavigationReason::Unknown);
-
- float MatchZoom(int steps, float fallbackZoom);
- int MatchZoomIndex(int direction);
-
- static const float s_ZoomLevels[];
- static const int s_ZoomLevelCount;
-};
-
-struct SizeAction final: EditorAction
-{
- bool m_IsActive;
- bool m_Clean;
- Node* m_SizedNode;
-
- SizeAction(EditorContext* editor);
-
- virtual const char* GetName() const override final { return "Size"; }
-
- virtual AcceptResult Accept(const Control& control) override final;
- virtual bool Process(const Control& control) override final;
-
- virtual ImGuiMouseCursor GetCursor() override final { return m_Cursor; }
-
- virtual void ShowMetrics() override final;
-
- virtual SizeAction* AsSize() override final { return this; }
-
- virtual bool IsDragging() override final { return m_IsActive; }
-
- const ImRect& GetStartGroupBounds() const { return m_StartGroupBounds; }
-
-private:
- NodeRegion GetRegion(Node* node);
- ImGuiMouseCursor ChooseCursor(NodeRegion region);
-
- ImRect m_StartBounds;
- ImRect m_StartGroupBounds;
- ImVec2 m_LastSize;
- ImVec2 m_MinimumSize;
- ImVec2 m_LastDragOffset;
- ed::NodeRegion m_Pivot;
- ImGuiMouseCursor m_Cursor;
-};
-
-struct DragAction final: EditorAction
-{
- bool m_IsActive;
- bool m_Clear;
- Object* m_DraggedObject;
- vector<Object*> m_Objects;
-
- DragAction(EditorContext* editor);
-
- virtual const char* GetName() const override final { return "Drag"; }
-
- virtual AcceptResult Accept(const Control& control) override final;
- virtual bool Process(const Control& control) override final;
-
- virtual ImGuiMouseCursor GetCursor() override final { return ImGuiMouseCursor_ResizeAll; }
-
- virtual bool IsDragging() override final { return m_IsActive; }
-
- virtual void ShowMetrics() override final;
-
- virtual DragAction* AsDrag() override final { return this; }
-};
-
-struct SelectAction final: EditorAction
-{
- bool m_IsActive;
-
- bool m_SelectGroups;
- bool m_SelectLinkMode;
- bool m_CommitSelection;
- ImVec2 m_StartPoint;
- ImVec2 m_EndPoint;
- vector<Object*> m_CandidateObjects;
- vector<Object*> m_SelectedObjectsAtStart;
-
- Animation m_Animation;
-
- SelectAction(EditorContext* editor);
-
- virtual const char* GetName() const override final { return "Select"; }
-
- virtual AcceptResult Accept(const Control& control) override final;
- virtual bool Process(const Control& control) override final;
-
- virtual void ShowMetrics() override final;
-
- virtual bool IsDragging() override final { return m_IsActive; }
-
- virtual SelectAction* AsSelect() override final { return this; }
-
- void Draw(ImDrawList* drawList);
-};
-
-struct ContextMenuAction final: EditorAction
-{
- enum Menu { None, Node, Pin, Link, Background };
-
- Menu m_CandidateMenu;
- Menu m_CurrentMenu;
- ObjectId m_ContextId;
-
- ContextMenuAction(EditorContext* editor);
-
- virtual const char* GetName() const override final { return "Context Menu"; }
-
- virtual AcceptResult Accept(const Control& control) override final;
- virtual bool Process(const Control& control) override final;
- virtual void Reject() override final;
-
- virtual void ShowMetrics() override final;
-
- virtual ContextMenuAction* AsContextMenu() override final { return this; }
-
- bool ShowNodeContextMenu(NodeId* nodeId);
- bool ShowPinContextMenu(PinId* pinId);
- bool ShowLinkContextMenu(LinkId* linkId);
- bool ShowBackgroundContextMenu();
-};
-
-struct ShortcutAction final: EditorAction
-{
- enum Action { None, Cut, Copy, Paste, Duplicate, CreateNode };
-
- bool m_IsActive;
- bool m_InAction;
- Action m_CurrentAction;
- vector<Object*> m_Context;
-
- ShortcutAction(EditorContext* editor);
-
- virtual const char* GetName() const override final { return "Shortcut"; }
-
- virtual AcceptResult Accept(const Control& control) override final;
- virtual bool Process(const Control& control) override final;
- virtual void Reject() override final;
-
- virtual void ShowMetrics() override final;
-
- virtual ShortcutAction* AsCutCopyPaste() override final { return this; }
-
- bool Begin();
- void End();
-
- bool AcceptCut();
- bool AcceptCopy();
- bool AcceptPaste();
- bool AcceptDuplicate();
- bool AcceptCreateNode();
-};
-
-struct CreateItemAction final : EditorAction
-{
- enum Stage
- {
- None,
- Possible,
- Create
- };
-
- enum Action
- {
- Unknown,
- UserReject,
- UserAccept
- };
-
- enum Type
- {
- NoItem,
- Node,
- Link
- };
-
- enum Result
- {
- True,
- False,
- Indeterminate
- };
-
- bool m_InActive;
- Stage m_NextStage;
-
- Stage m_CurrentStage;
- Type m_ItemType;
- Action m_UserAction;
- ImU32 m_LinkColor;
- float m_LinkThickness;
- Pin* m_LinkStart;
- Pin* m_LinkEnd;
-
- bool m_IsActive;
- Pin* m_DraggedPin;
-
- int m_LastChannel = -1;
-
-
- CreateItemAction(EditorContext* editor);
-
- virtual const char* GetName() const override final { return "Create Item"; }
-
- virtual AcceptResult Accept(const Control& control) override final;
- virtual bool Process(const Control& control) override final;
-
- virtual ImGuiMouseCursor GetCursor() override final { return ImGuiMouseCursor_Arrow; }
-
- virtual void ShowMetrics() override final;
-
- virtual bool IsDragging() override final { return m_IsActive; }
-
- virtual CreateItemAction* AsCreateItem() override final { return this; }
-
- void SetStyle(ImU32 color, float thickness);
-
- bool Begin();
- void End();
-
- Result RejectItem();
- Result AcceptItem();
-
- Result QueryLink(PinId* startId, PinId* endId);
- Result QueryNode(PinId* pinId);
-
-private:
- bool m_IsInGlobalSpace;
-
- void DragStart(Pin* startPin);
- void DragEnd();
- void DropPin(Pin* endPin);
- void DropNode();
- void DropNothing();
-};
-
-struct DeleteItemsAction final: EditorAction
-{
- bool m_IsActive;
- bool m_InInteraction;
-
- DeleteItemsAction(EditorContext* editor);
-
- virtual const char* GetName() const override final { return "Delete Items"; }
-
- virtual AcceptResult Accept(const Control& control) override final;
- virtual bool Process(const Control& control) override final;
-
- virtual void ShowMetrics() override final;
-
- virtual DeleteItemsAction* AsDeleteItems() override final { return this; }
-
- bool Add(Object* object);
-
- bool Begin();
- void End();
-
- bool QueryLink(LinkId* linkId, PinId* startId = nullptr, PinId* endId = nullptr);
- bool QueryNode(NodeId* nodeId);
-
- bool AcceptItem(bool deleteDependencies);
- void RejectItem();
-
-private:
- enum IteratorType { Unknown, Link, Node };
- enum UserAction { Undetermined, Accepted, Rejected };
-
- void DeleteDeadLinks(NodeId nodeId);
-
- bool QueryItem(ObjectId* itemId, IteratorType itemType);
- void RemoveItem(bool deleteDependencies);
-
- vector<Object*> m_ManuallyDeletedObjects;
-
- IteratorType m_CurrentItemType;
- UserAction m_UserAction;
- vector<Object*> m_CandidateObjects;
- int m_CandidateItemIndex;
-};
-
-struct NodeBuilder
-{
- EditorContext* const Editor;
-
- Node* m_CurrentNode;
- Pin* m_CurrentPin;
-
- ImRect m_NodeRect;
-
- ImRect m_PivotRect;
- ImVec2 m_PivotAlignment;
- ImVec2 m_PivotSize;
- ImVec2 m_PivotScale;
- bool m_ResolvePinRect;
- bool m_ResolvePivot;
-
- ImRect m_GroupBounds;
- bool m_IsGroup;
-
- ImDrawListSplitter m_Splitter;
- ImDrawListSplitter m_PinSplitter;
-
- NodeBuilder(EditorContext* editor);
- ~NodeBuilder();
-
- void Begin(NodeId nodeId);
- void End();
-
- void BeginPin(PinId pinId, PinKind kind);
- void EndPin();
-
- void PinRect(const ImVec2& a, const ImVec2& b);
- void PinPivotRect(const ImVec2& a, const ImVec2& b);
- void PinPivotSize(const ImVec2& size);
- void PinPivotScale(const ImVec2& scale);
- void PinPivotAlignment(const ImVec2& alignment);
-
- void Group(const ImVec2& size);
-
- ImDrawList* GetUserBackgroundDrawList() const;
- ImDrawList* GetUserBackgroundDrawList(Node* node) const;
-};
-
-struct HintBuilder
-{
- EditorContext* const Editor;
- bool m_IsActive;
- Node* m_CurrentNode;
- float m_LastFringe = 1.0f;
- int m_LastChannel = 0;
-
- HintBuilder(EditorContext* editor);
-
- bool Begin(NodeId nodeId);
- void End();
-
- ImVec2 GetGroupMin();
- ImVec2 GetGroupMax();
-
- ImDrawList* GetForegroundDrawList();
- ImDrawList* GetBackgroundDrawList();
-};
-
-struct Style: ax::NodeEditor::Style
-{
- void PushColor(StyleColor colorIndex, const ImVec4& color);
- void PopColor(int count = 1);
-
- void PushVar(StyleVar varIndex, float value);
- void PushVar(StyleVar varIndex, const ImVec2& value);
- void PushVar(StyleVar varIndex, const ImVec4& value);
- void PopVar(int count = 1);
-
- const char* GetColorName(StyleColor colorIndex) const;
-
-private:
- struct ColorModifier
- {
- StyleColor Index;
- ImVec4 Value;
- };
-
- struct VarModifier
- {
- StyleVar Index;
- ImVec4 Value;
- };
-
- float* GetVarFloatAddr(StyleVar idx);
- ImVec2* GetVarVec2Addr(StyleVar idx);
- ImVec4* GetVarVec4Addr(StyleVar idx);
-
- vector<ColorModifier> m_ColorStack;
- vector<VarModifier> m_VarStack;
-};
-
-struct Config: ax::NodeEditor::Config
-{
- Config(const ax::NodeEditor::Config* config);
-
- std::string Load();
- std::string LoadNode(NodeId nodeId);
-
- void BeginSave();
- bool Save(const std::string& data, SaveReasonFlags flags);
- bool SaveNode(NodeId nodeId, const std::string& data, SaveReasonFlags flags);
- void EndSave();
-};
-
-enum class SuspendFlags : uint8_t
-{
- None = 0,
- KeepSplitter = 1
-};
-
-inline SuspendFlags operator |(SuspendFlags lhs, SuspendFlags rhs) { return static_cast<SuspendFlags>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs)); }
-inline SuspendFlags operator &(SuspendFlags lhs, SuspendFlags rhs) { return static_cast<SuspendFlags>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs)); }
-
-
-struct EditorContext
-{
- EditorContext(const ax::NodeEditor::Config* config = nullptr);
- ~EditorContext();
-
- const Config& GetConfig() const { return m_Config; }
-
- Style& GetStyle() { return m_Style; }
-
- void Begin(const char* id, const ImVec2& size = ImVec2(0, 0));
- void End();
-
- bool DoLink(LinkId id, PinId startPinId, PinId endPinId, ImU32 color, float thickness);
-
-
- NodeBuilder& GetNodeBuilder() { return m_NodeBuilder; }
- HintBuilder& GetHintBuilder() { return m_HintBuilder; }
-
- EditorAction* GetCurrentAction() { return m_CurrentAction; }
-
- CreateItemAction& GetItemCreator() { return m_CreateItemAction; }
- DeleteItemsAction& GetItemDeleter() { return m_DeleteItemsAction; }
- ContextMenuAction& GetContextMenu() { return m_ContextMenuAction; }
- ShortcutAction& GetShortcut() { return m_ShortcutAction; }
-
- const ImGuiEx::CanvasView& GetView() const { return m_Canvas.View(); }
- const ImRect& GetViewRect() const { return m_Canvas.ViewRect(); }
- const ImRect& GetRect() const { return m_Canvas.Rect(); }
-
- void SetNodePosition(NodeId nodeId, const ImVec2& screenPosition);
- void SetGroupSize(NodeId nodeId, const ImVec2& size);
- ImVec2 GetNodePosition(NodeId nodeId);
- ImVec2 GetNodeSize(NodeId nodeId);
-
- void SetNodeZPosition(NodeId nodeId, float z);
- float GetNodeZPosition(NodeId nodeId);
-
- void MarkNodeToRestoreState(Node* node);
- void UpdateNodeState(Node* node);
-
- void RemoveSettings(Object* object);
-
- void ClearSelection();
- void SelectObject(Object* object);
- void DeselectObject(Object* object);
- void SetSelectedObject(Object* object);
- void ToggleObjectSelection(Object* object);
- bool IsSelected(Object* object);
- const vector<Object*>& GetSelectedObjects();
- bool IsAnyNodeSelected();
- bool IsAnyLinkSelected();
- bool HasSelectionChanged();
- uint64_t GetSelectionId() const { return m_SelectionId; }
-
- Node* FindNodeAt(const ImVec2& p);
- void FindNodesInRect(const ImRect& r, vector<Node*>& result, bool append = false, bool includeIntersecting = true);
- void FindLinksInRect(const ImRect& r, vector<Link*>& result, bool append = false);
-
- bool HasAnyLinks(NodeId nodeId) const;
- bool HasAnyLinks(PinId pinId) const;
-
- int BreakLinks(NodeId nodeId);
- int BreakLinks(PinId pinId);
-
- void FindLinksForNode(NodeId nodeId, vector<Link*>& result, bool add = false);
-
- bool PinHadAnyLinks(PinId pinId);
-
- ImVec2 ToCanvas(const ImVec2& point) const { return m_Canvas.ToLocal(point); }
- ImVec2 ToScreen(const ImVec2& point) const { return m_Canvas.FromLocal(point); }
-
- void NotifyLinkDeleted(Link* link);
-
- void Suspend(SuspendFlags flags = SuspendFlags::None);
- void Resume(SuspendFlags flags = SuspendFlags::None);
- bool IsSuspended();
-
- bool IsFocused();
- bool IsHovered() const;
- bool IsHoveredWithoutOverlapp() const;
- bool CanAcceptUserInput() const;
-
- void MakeDirty(SaveReasonFlags reason);
- void MakeDirty(SaveReasonFlags reason, Node* node);
-
- int CountLiveNodes() const;
- int CountLivePins() const;
- int CountLiveLinks() const;
-
- Pin* CreatePin(PinId id, PinKind kind);
- Node* CreateNode(NodeId id);
- Link* CreateLink(LinkId id);
-
- Node* FindNode(NodeId id);
- Pin* FindPin(PinId id);
- Link* FindLink(LinkId id);
- Object* FindObject(ObjectId id);
-
- Node* GetNode(NodeId id);
- Pin* GetPin(PinId id, PinKind kind);
- Link* GetLink(LinkId id);
-
- Link* FindLinkAt(const ImVec2& p);
-
- template <typename T>
- ImRect GetBounds(const std::vector<T*>& objects)
- {
- ImRect bounds(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
-
- for (auto object : objects)
- if (object->m_IsLive)
- bounds.Add(object->GetBounds());
-
- if (ImRect_IsEmpty(bounds))
- bounds = ImRect();
-
- return bounds;
- }
-
- template <typename T>
- ImRect GetBounds(const std::vector<ObjectWrapper<T>>& objects)
- {
- ImRect bounds(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
-
- for (auto object : objects)
- if (object.m_Object->m_IsLive)
- bounds.Add(object.m_Object->GetBounds());
-
- if (ImRect_IsEmpty(bounds))
- bounds = ImRect();
-
- return bounds;
- }
-
- ImRect GetSelectionBounds() { return GetBounds(m_SelectedObjects); }
- ImRect GetContentBounds() { return GetBounds(m_Nodes); }
-
- ImU32 GetColor(StyleColor colorIndex) const;
- ImU32 GetColor(StyleColor colorIndex, float alpha) const;
-
- int GetNodeIds(NodeId* nodes, int size) const;
-
- void NavigateTo(const ImRect& bounds, bool zoomIn = false, float duration = -1)
- {
- auto zoomMode = zoomIn ? NavigateAction::ZoomMode::WithMargin : NavigateAction::ZoomMode::None;
- m_NavigateAction.NavigateTo(bounds, zoomMode, duration);
- }
-
- void RegisterAnimation(Animation* animation);
- void UnregisterAnimation(Animation* animation);
-
- void Flow(Link* link, FlowDirection direction);
-
- void SetUserContext(bool globalSpace = false);
-
- void EnableShortcuts(bool enable);
- bool AreShortcutsEnabled();
-
- NodeId GetHoveredNode() const { return m_HoveredNode; }
- PinId GetHoveredPin() const { return m_HoveredPin; }
- LinkId GetHoveredLink() const { return m_HoveredLink; }
- NodeId GetDoubleClickedNode() const { return m_DoubleClickedNode; }
- PinId GetDoubleClickedPin() const { return m_DoubleClickedPin; }
- LinkId GetDoubleClickedLink() const { return m_DoubleClickedLink; }
- bool IsBackgroundClicked() const { return m_BackgroundClicked; }
- bool IsBackgroundDoubleClicked() const { return m_BackgroundDoubleClicked; }
-
- float AlignPointToGrid(float p) const
- {
- if (!ImGui::GetIO().KeyAlt)
- return p - ImFmod(p, 16.0f);
- else
- return p;
- }
-
- ImVec2 AlignPointToGrid(const ImVec2& p) const
- {
- return ImVec2(AlignPointToGrid(p.x), AlignPointToGrid(p.y));
- }
-
- ImDrawList* GetDrawList() { return m_DrawList; }
-
-private:
- void LoadSettings();
- void SaveSettings();
-
- Control BuildControl(bool allowOffscreen);
-
- void ShowMetrics(const Control& control);
-
- void UpdateAnimations();
-
- bool m_IsFirstFrame;
- bool m_IsFocused;
- bool m_IsHovered;
- bool m_IsHoveredWithoutOverlapp;
-
- bool m_ShortcutsEnabled;
-
- Style m_Style;
-
- vector<ObjectWrapper<Node>> m_Nodes;
- vector<ObjectWrapper<Pin>> m_Pins;
- vector<ObjectWrapper<Link>> m_Links;
-
- vector<Object*> m_SelectedObjects;
-
- vector<Object*> m_LastSelectedObjects;
- uint64_t m_SelectionId;
-
- Link* m_LastActiveLink;
-
- vector<Animation*> m_LiveAnimations;
- vector<Animation*> m_LastLiveAnimations;
-
- ImGuiEx::Canvas m_Canvas;
- bool m_IsCanvasVisible;
-
- NodeBuilder m_NodeBuilder;
- HintBuilder m_HintBuilder;
-
- EditorAction* m_CurrentAction;
- NavigateAction m_NavigateAction;
- SizeAction m_SizeAction;
- DragAction m_DragAction;
- SelectAction m_SelectAction;
- ContextMenuAction m_ContextMenuAction;
- ShortcutAction m_ShortcutAction;
- CreateItemAction m_CreateItemAction;
- DeleteItemsAction m_DeleteItemsAction;
-
- vector<AnimationController*> m_AnimationControllers;
- FlowAnimationController m_FlowAnimationController;
-
- NodeId m_HoveredNode;
- PinId m_HoveredPin;
- LinkId m_HoveredLink;
- NodeId m_DoubleClickedNode;
- PinId m_DoubleClickedPin;
- LinkId m_DoubleClickedLink;
- bool m_BackgroundClicked;
- bool m_BackgroundDoubleClicked;
-
- bool m_IsInitialized;
- Settings m_Settings;
-
- Config m_Config;
-
- ImDrawList* m_DrawList;
- int m_ExternalChannel;
- ImDrawListSplitter m_Splitter;
-};
-
-
-//------------------------------------------------------------------------------
-} // namespace Detail
-} // namespace Editor
-} // namespace ax
-
-
-//------------------------------------------------------------------------------
-# include "imgui_node_editor_internal.inl"
-
-
-//------------------------------------------------------------------------------
-# endif // __IMGUI_NODE_EDITOR_INTERNAL_H__
diff --git a/3rdparty/imgui-node-editor/imgui_node_editor_internal.inl b/3rdparty/imgui-node-editor/imgui_node_editor_internal.inl
deleted file mode 100644
index 7280fa1..0000000
--- a/3rdparty/imgui-node-editor/imgui_node_editor_internal.inl
+++ /dev/null
@@ -1,57 +0,0 @@
-//------------------------------------------------------------------------------
-// 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,
-// publish, and distribute this file as you see fit.
-//
-// CREDITS
-// Written by Michal Cichon
-//------------------------------------------------------------------------------
-# ifndef __IMGUI_NODE_EDITOR_INTERNAL_INL__
-# define __IMGUI_NODE_EDITOR_INTERNAL_INL__
-# pragma once
-
-
-//------------------------------------------------------------------------------
-# include "imgui_node_editor_internal.h"
-
-
-//------------------------------------------------------------------------------
-namespace ax {
-namespace NodeEditor {
-namespace Detail {
-
-
-//------------------------------------------------------------------------------
-//inline ImRect ToRect(const ax::rectf& rect)
-//{
-// return ImRect(
-// to_imvec(rect.top_left()),
-// to_imvec(rect.bottom_right())
-// );
-//}
-//
-//inline ImRect ToRect(const ax::rect& rect)
-//{
-// return ImRect(
-// to_imvec(rect.top_left()),
-// to_imvec(rect.bottom_right())
-// );
-//}
-
-inline ImRect ImGui_GetItemRect()
-{
- return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
-}
-
-
-//------------------------------------------------------------------------------
-} // namespace Detail
-} // namespace Editor
-} // namespace ax
-
-
-//------------------------------------------------------------------------------
-# endif // __IMGUI_NODE_EDITOR_INTERNAL_INL__
diff --git a/3rdparty/imgui-node-editor/thedmd-imgui-node-editor.LICENSE.txt b/3rdparty/imgui-node-editor/thedmd-imgui-node-editor.LICENSE.txt
deleted file mode 100644
index 0c8aa6a..0000000
--- a/3rdparty/imgui-node-editor/thedmd-imgui-node-editor.LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2019 Michał Cichoń
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE. \ No newline at end of file
diff --git a/3rdparty/imgui-node-editor/thedmd-imgui-node-editor.stamp b/3rdparty/imgui-node-editor/thedmd-imgui-node-editor.stamp
deleted file mode 100644
index c47e4cc..0000000
--- a/3rdparty/imgui-node-editor/thedmd-imgui-node-editor.stamp
+++ /dev/null
@@ -1,2 +0,0 @@
-# This file labels the commit which our source is from
-612eaea68977c0dda2b334c46784136e6f4f819a