#pragma once #include "../commons.h" #include "../utilities/node_renderer_base.h" #include #include #include #include #include // Pin icon offset constants namespace BlockPinOffsets { // Y offset for input parameter pins (moves pins higher on top edge) static constexpr float INPUT_PARAM_Y = -8.0f; // Y offset for output parameter pins (moves pins lower on bottom edge) static constexpr float OUTPUT_PARAM_Y = 8; // Negated (12.0f) // Parameter node specific output offset (can be different from general blocks) static constexpr float PARAM_NODE_OUTPUT_Y = 0.0f; // Combined ImVec2 offsets for convenience static const ImVec2 INPUT_PARAM(0.0f, -15); static const ImVec2 OUTPUT_PARAM(0.0f, OUTPUT_PARAM_Y); static const ImVec2 PARAM_NODE_OUTPUT(0.0f, PARAM_NODE_OUTPUT_Y); static const ImVec2 GROUP_INPUT_PARAM(0.0f, -15.0f); } // Block style constants namespace BlockStyle { // Node appearance constants static constexpr float ROUNDING = 1.0f; static constexpr float BORDER_WIDTH = 1.0f; static constexpr float PADDING = 0.0f; // Group block specific (more rounded, slightly thicker border) static constexpr float GROUP_ROUNDING = 1.0f; static constexpr float GROUP_BORDER_WIDTH = 1.0f; // Parameter node constants (standardized across all display modes) static constexpr float PARAM_ROUNDING = 0.0f; static constexpr float PARAM_BORDER_WIDTH = 1.0f; static constexpr float PARAM_BORDER_WIDTH_SOURCE = 2.0f; // Thicker for source nodes static constexpr float PARAM_BORDER_WIDTH_NAME_AND_VALUE = 1.5f; // Slightly thicker for name+value mode static constexpr float PARAM_BORDER_WIDTH_SOURCE_NAME_AND_VALUE = 2.5f; // Source in name+value mode // Parameter node padding (ImVec4 for per-edge control) static const ImVec4 PARAM_PADDING_NAME_ONLY(4.0f, 2.0f, 4.0f, 2.0f); static const ImVec4 PARAM_PADDING_NAME_AND_VALUE(8.0f, 4.0f, 8.0f, 4.0f); static const ImVec4 PARAM_PADDING_SMALL_BOX(2.0f, 2.0f, 2.0f, 2.0f); static const ImVec4 PARAM_PADDING_MINIMAL(4.0f, 4.0f, 4.0f, 4.0f); } // Forward declarations class App; class Container; namespace crude_json { struct value; } class Block { public: Block(int id, const char* name) : m_ID(id) , m_Name(name) , m_Type(NodeType::Blueprint) , m_Color(ImColor(255, 255, 255)) , m_bFlags(NHBEHAVIOR_NONE) { } virtual ~Block() = default; // Core identification int GetID() const { return m_ID; } const char* GetName() const { return m_Name.c_str(); } const char* GetTypeName() const { return m_TypeName.c_str(); } NH_BEHAVIOR_FLAGS GetFlags() const { return m_bFlags; } // Node building (like NHBehavior's CreateInput/CreateOutput) virtual void Build(Node& node, App* app) = 0; // Rendering (each block renders itself) virtual void Render(Node& node, App* app, Pin* newLinkPin) = 0; // Serialization support virtual const char* GetBlockType() const = 0; // Unique type identifier // State save/load callbacks (optional - subclasses can override to save/load custom state) // These are called from App::SaveGraph() / App::LoadGraph() virtual void SaveState(Node& node, crude_json::value& nodeData, const Container* container, App* app) {} virtual void LoadState(Node& node, const crude_json::value& nodeData, Container* container, App* app) {} // Parameter management (like NHBehavior) virtual int GetInputParameterCount() const { return 0; } virtual int GetOutputParameterCount() const { return 0; } virtual int GetInputCount() const { return 0; } // Flow inputs (triggers) virtual int GetOutputCount() const { return 0; } // Flow outputs (events) // Execution (stub: returns E_OK = 0) virtual int Run(Node& node, App* app) { return E_OK; } // Activation API (for flow control) virtual void ActivateOutput(int pos, bool active = true); virtual bool IsOutputActive(int pos) const; virtual void ActivateInput(int pos, bool active = true); virtual bool IsInputActive(int pos) const; // Context menu hook - add custom menu items virtual void OnMenu(Node& node, App* app) {} // Edit dialog UI hook - add custom UI elements to block edit dialog // Called from RenderBlockEditDialog() to allow blocks to append their own settings virtual void RenderEditUI(Node& node, App* app) {} // Flow handling virtual bool ShouldAutoActivateDefaultOutput() const { return true; } protected: // Activation state (stored per-block instance) std::vector m_OutputActive; // Output activation states std::vector m_InputActive; // Input activation states int m_ID; std::string m_Name; std::string m_TypeName; NodeType m_Type; ImColor m_Color; NH_BEHAVIOR_FLAGS m_bFlags; // Behavior flags }; // Extended block with parameters - like NHBehavior with params class ParameterizedBlock : public Block, public ax::NodeRendering::NodeRendererBase { public: ParameterizedBlock(int id, const char* name) : Block(id, name) { } virtual ~ParameterizedBlock() = default; // Parameter creation helpers (like NHBehavior::CreateInputParameter) void AddInputParameter(App* app, Node& node, const char* name, PinType type); void AddOutputParameter(App* app, Node& node, const char* name, PinType type); // I/O creation (flow control) void AddInput(App* app, Node& node, const char* name); void AddOutput(App* app, Node& node, const char* name); int GetInputParameterCount() const override { return (int)m_InputParams.size(); } int GetOutputParameterCount() const override { return (int)m_OutputParams.size(); } int GetInputCount() const override { return (int)m_Inputs.size(); } int GetOutputCount() const override { return (int)m_Outputs.size(); } // Default Virtools-style rendering void Render(Node& node, App* app, Pin* newLinkPin) override; // Context menu hook - default implementation for parameterized blocks void OnMenu(Node& node, App* app) override; // State save/load - override to save/load unconnected parameter input values void SaveState(Node& node, crude_json::value& nodeData, const Container* container, App* app) override; void LoadState(Node& node, const crude_json::value& nodeData, Container* container, App* app) override; protected: // Parameter value helpers (for use in Run() implementations) // Get input parameter value - reads from connected parameter node or default value static int GetInputParamValueInt(const Pin& pin, Node& node, App* app, int defaultValue = 0); static float GetInputParamValueFloat(const Pin& pin, Node& node, App* app, float defaultValue = 0.0f); static bool GetInputParamValueBool(const Pin& pin, Node& node, App* app, bool defaultValue = false); static std::string GetInputParamValueString(const Pin& pin, Node& node, App* app, const std::string& defaultValue = ""); // Set output parameter value - stores value and propagates to connected parameter nodes static void SetOutputParamValueInt(const Pin& pin, Node& node, App* app, int value); static void SetOutputParamValueFloat(const Pin& pin, Node& node, App* app, float value); static void SetOutputParamValueBool(const Pin& pin, Node& node, App* app, bool value); static void SetOutputParamValueString(const Pin& pin, Node& node, App* app, const std::string& value); std::vector m_InputParams; // Parameter pin IDs (top) std::vector m_OutputParams; // Parameter pin IDs (bottom) std::vector m_Inputs; // Flow input IDs (left) std::vector m_Outputs; // Flow output IDs (right) }; // Block factory function signature using BlockFactory = std::function; // Block registry - like Virtools' behavior manager class BlockRegistry { public: static BlockRegistry& Instance() { static BlockRegistry instance; return instance; } void RegisterBlock(const char* typeName, BlockFactory factory) { m_Factories[typeName] = factory; } Block* CreateBlock(const char* typeName, int id) { auto it = m_Factories.find(typeName); if (it != m_Factories.end()) return it->second(id); return nullptr; } std::vector GetRegisteredTypes() const { std::vector types; for (const auto& pair : m_Factories) types.push_back(pair.first); return types; } private: BlockRegistry() = default; std::map m_Factories; }; // Helper macro for auto-registration #define REGISTER_BLOCK(ClassName, TypeName) \ namespace { \ struct ClassName##_Registrar { \ ClassName##_Registrar() { \ BlockRegistry::Instance().RegisterBlock(TypeName, \ [](int id) -> Block* { return new ClassName(id); }); \ } \ }; \ static ClassName##_Registrar g_##ClassName##_Registrar; \ }