diff options
Diffstat (limited to '3rdparty/imgui-node-editor')
-rw-r--r-- | 3rdparty/imgui-node-editor/CMakeLists.txt | 13 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/crude_json.cpp | 890 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/crude_json.h | 250 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_bezier_math.h | 144 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_bezier_math.inl | 675 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_canvas.cpp | 550 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_canvas.h | 268 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_extra_math.h | 73 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_extra_math.inl | 189 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_node_editor.cpp | 5629 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_node_editor.h | 481 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_node_editor_api.cpp | 734 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_node_editor_internal.h | 1536 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/imgui_node_editor_internal.inl | 57 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/thedmd-imgui-node-editor.LICENSE.txt | 21 | ||||
-rw-r--r-- | 3rdparty/imgui-node-editor/thedmd-imgui-node-editor.stamp | 2 |
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 |