diff options
Diffstat (limited to 'core/src/Model/Workflow')
28 files changed, 0 insertions, 2973 deletions
diff --git a/core/src/Model/Workflow/Evaluation.cpp b/core/src/Model/Workflow/Evaluation.cpp deleted file mode 100644 index 7035bf9..0000000 --- a/core/src/Model/Workflow/Evaluation.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include "Evaluation.hpp" - -#include <queue> - -const char* WorkflowEvaluationError::FormatMessageType(enum MessageType messageType) -{ - switch (messageType) { - case Error: return "Error"; - case Warning: return "Warning"; - } -} - -const char* WorkflowEvaluationError::FormatPinType(enum PinType pinType) -{ - switch (pinType) { - case NoPin: return nullptr; - case InputPin: return "Input pin"; - case OutputPin: return "Output pin"; - } -} - -std::string WorkflowEvaluationError::Format() const -{ - // TODO convert to std::format - - std::string result; - result += FormatMessageType(this->Type); - result += " at "; - result += NodeId; - if (auto pinText = FormatPinType(this->PinType)) { - result += "/"; - result += pinText; - result += " "; - result += PinId; - } - result += ": "; - result += this->Message; - - return result; -} - -struct WorkflowEvaluationContext::RuntimeNode -{ - enum EvaluationStatus - { - ST_Unevaluated, - ST_Success, - ST_Failed, - }; - - EvaluationStatus Status = ST_Unevaluated; -}; - -struct WorkflowEvaluationContext::RuntimeConnection -{ - std::unique_ptr<BaseValue> Value; - - bool IsAvailableValue() const - { - return Value != nullptr; - } -}; - -WorkflowEvaluationContext::WorkflowEvaluationContext(Workflow& workflow) - : mWorkflow{ &workflow } -{ - mRuntimeNodes.resize(workflow.mNodes.size()); - mRuntimeConnections.resize(workflow.mConnections.size()); -} - -BaseValue* WorkflowEvaluationContext::GetConnectionValue(size_t id, bool constant) -{ - if (constant) { - return mWorkflow->GetConstantById(id); - } else { - return mRuntimeConnections[id].Value.get(); - } -} - -BaseValue* WorkflowEvaluationContext::GetConnectionValue(const WorkflowNode::InputPin& inputPin) -{ - if (inputPin.IsConnected()) { - return GetConnectionValue(inputPin.Connection, inputPin.IsConstantConnection()); - } else { - return nullptr; - } -} - -void WorkflowEvaluationContext::SetConnectionValue(size_t id, std::unique_ptr<BaseValue> value) -{ - mRuntimeConnections[id].Value = std::move(value); -} - -void WorkflowEvaluationContext::SetConnectionValue(const WorkflowNode::OutputPin& outputPin, std::unique_ptr<BaseValue> value) -{ - if (outputPin.IsConnected()) { - SetConnectionValue(outputPin.Connection, std::move(value)); - } -} - -void WorkflowEvaluationContext::Run() -{ - int evaluatedCount = 0; - int erroredCount = 0; - - for (auto& depthGroup : mWorkflow->GetDepthGroups()) { - for (size_t idx : depthGroup) { - auto& rn = mRuntimeNodes[idx]; - auto& n = *mWorkflow->mNodes[idx]; - - // TODO - - int preEvalErrors = mErrors.size(); - n.Evaluate(*this); - if (preEvalErrors != mErrors.size()) { - erroredCount++; - } else { - evaluatedCount++; - } - } - } - - for (size_t i = 0; i < mRuntimeNodes.size(); ++i) { - auto& rn = mRuntimeNodes[i]; - auto& n = *mWorkflow->mNodes[i]; - if (n.GetType() == WorkflowNode::OutputType) { - // TODO record outputs - } - } -} - -void WorkflowEvaluationContext::ReportError(std::string message, const WorkflowNode& node, int pinId, bool inputPin) -{ - mErrors.push_back(WorkflowEvaluationError{ - .Message = std::move(message), - .NodeId = node.GetId(), - .PinId = pinId, - .PinType = inputPin ? WorkflowEvaluationError::InputPin : WorkflowEvaluationError::OutputPin, - .Type = WorkflowEvaluationError::Error, - }); -} - -void WorkflowEvaluationContext::ReportError(std::string message, const WorkflowNode& node) -{ - mErrors.push_back(WorkflowEvaluationError{ - .Message = std::move(message), - .NodeId = node.GetId(), - .PinId = -1, - .PinType = WorkflowEvaluationError::NoPin, - .Type = WorkflowEvaluationError::Error, - }); -} - -void WorkflowEvaluationContext::ReportWarning(std::string message, const WorkflowNode& node, int pinId, bool inputPin) -{ - mErrors.push_back(WorkflowEvaluationError{ - .Message = std::move(message), - .NodeId = node.GetId(), - .PinId = pinId, - .PinType = inputPin ? WorkflowEvaluationError::InputPin : WorkflowEvaluationError::OutputPin, - .Type = WorkflowEvaluationError::Warning, - }); -} - -void WorkflowEvaluationContext::ReportWarning(std::string message, const WorkflowNode& node) -{ - mErrors.push_back(WorkflowEvaluationError{ - .Message = std::move(message), - .NodeId = node.GetId(), - .PinId = -1, - .PinType = WorkflowEvaluationError::NoPin, - .Type = WorkflowEvaluationError::Warning, - }); -} diff --git a/core/src/Model/Workflow/Evaluation.hpp b/core/src/Model/Workflow/Evaluation.hpp deleted file mode 100644 index 4d78872..0000000 --- a/core/src/Model/Workflow/Evaluation.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include "Model/Workflow/Workflow.hpp" - -#include <cstddef> -#include <cstdint> -#include <string> -#include <vector> - -class WorkflowEvaluationError -{ -public: - enum MessageType : int16_t - { - Error, - Warning, - }; - - enum PinType : int16_t - { - NoPin, - InputPin, - OutputPin, - }; - -public: - std::string Message; - size_t NodeId; - int PinId; - PinType PinType; - MessageType Type; - -public: - static const char* FormatMessageType(enum MessageType messageType); - static const char* FormatPinType(enum PinType pinType); - - std::string Format() const; -}; - -class WorkflowEvaluationContext -{ -private: - struct RuntimeNode; - struct RuntimeConnection; - - Workflow* mWorkflow; - std::vector<RuntimeNode> mRuntimeNodes; - std::vector<RuntimeConnection> mRuntimeConnections; - std::vector<WorkflowEvaluationError> mErrors; - std::vector<WorkflowEvaluationError> mWarnings; - -public: - WorkflowEvaluationContext(Workflow& workflow); - - BaseValue* GetConnectionValue(size_t id, bool constant); - BaseValue* GetConnectionValue(const WorkflowNode::InputPin& inputPin); - void SetConnectionValue(size_t id, std::unique_ptr<BaseValue> value); - void SetConnectionValue(const WorkflowNode::OutputPin& outputPin, std::unique_ptr<BaseValue> value); - - void ReportError(std::string message, const WorkflowNode& node, int pinId, bool inputPin); - void ReportError(std::string message, const WorkflowNode& node); - void ReportWarning(std::string message, const WorkflowNode& node, int pinId, bool inputPin); - void ReportWarning(std::string message, const WorkflowNode& node); - - /// Run until all possible paths have been evaluated. - void Run(); -}; diff --git a/core/src/Model/Workflow/Nodes/DocumentNodes.cpp b/core/src/Model/Workflow/Nodes/DocumentNodes.cpp deleted file mode 100644 index 6729c63..0000000 --- a/core/src/Model/Workflow/Nodes/DocumentNodes.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "DocumentNodes.hpp" - -#include "Model/Workflow/Evaluation.hpp" -#include "Model/Workflow/Values/Basic.hpp" - -bool DocumentTemplateExpansionNode::IsInstance(const WorkflowNode* node) -{ - return node->GetKind() == KD_DocumentTemplateExpansion; -} - -DocumentTemplateExpansionNode::DocumentTemplateExpansionNode() - : WorkflowNode(KD_DocumentTemplateExpansion, false) -{ -} - -void DocumentTemplateExpansionNode::Evaluate(WorkflowEvaluationContext& ctx) -{ -} diff --git a/core/src/Model/Workflow/Nodes/DocumentNodes.hpp b/core/src/Model/Workflow/Nodes/DocumentNodes.hpp deleted file mode 100644 index 85bba9e..0000000 --- a/core/src/Model/Workflow/Nodes/DocumentNodes.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Model/Workflow/Workflow.hpp" - -class DocumentTemplateExpansionNode : public WorkflowNode -{ -public: - static bool IsInstance(const WorkflowNode* node); - DocumentTemplateExpansionNode(); - - // TODO - virtual void Evaluate(WorkflowEvaluationContext& ctx) override; -}; diff --git a/core/src/Model/Workflow/Nodes/NumericNodes.cpp b/core/src/Model/Workflow/Nodes/NumericNodes.cpp deleted file mode 100644 index 3a81979..0000000 --- a/core/src/Model/Workflow/Nodes/NumericNodes.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "NumericNodes.hpp" - -#include "Model/Workflow/Evaluation.hpp" -#include "Model/Workflow/Values/Basic.hpp" -#include "Utils/I18n.hpp" -#include "Utils/Macros.hpp" -#include "Utils/RTTI.hpp" - -#include <cassert> -#include <utility> - -WorkflowNode::Kind NumericOperationNode::OperationTypeToNodeKind(OperationType type) -{ - switch (type) { - case Addition: return KD_NumericAddition; - case Subtraction: return KD_NumericSubtraction; - case Multiplication: return KD_NumericMultiplication; - case Division: return KD_NumericDivision; - default: return InvalidKind; - } -} - -NumericOperationNode::OperationType NumericOperationNode::NodeKindToOperationType(Kind kind) -{ - switch (kind) { - case KD_NumericAddition: return Addition; - case KD_NumericSubtraction: return Subtraction; - case KD_NumericMultiplication: return Multiplication; - case KD_NumericDivision: return Division; - default: return InvalidType; - } -} - -bool NumericOperationNode::IsInstance(const WorkflowNode* node) -{ - return node->GetKind() >= KD_NumericAddition && node->GetKind() <= KD_NumericDivision; -} - -NumericOperationNode::NumericOperationNode(OperationType type) - : WorkflowNode(OperationTypeToNodeKind(type), false) - , mType{ type } -{ - mInputs.resize(2); - mInputs[0].MatchingType = BaseValue::KD_Numeric; - mInputs[1].MatchingType = BaseValue::KD_Numeric; - - mOutputs.resize(1); - mOutputs[0].MatchingType = BaseValue::KD_Numeric; -} - -void NumericOperationNode::Evaluate(WorkflowEvaluationContext& ctx) -{ - auto lhsVal = dyn_cast<NumericValue>(ctx.GetConnectionValue(mInputs[0])); - if (!lhsVal) return; - double lhs = lhsVal->GetValue(); - - auto rhsVal = dyn_cast<NumericValue>(ctx.GetConnectionValue(mInputs[1])); - if (!rhsVal) return; - double rhs = rhsVal->GetValue(); - - double res; - switch (mType) { - case Addition: res = lhs + rhs; break; - case Subtraction: res = lhs - rhs; break; - case Multiplication: res = lhs * rhs; break; - case Division: { - if (rhs == 0.0) { - ctx.ReportError(I18N_TEXT("Error: division by 0", L10N_WORKFLOW_RTERROR_DIV_BY_0), *this); - return; - } - res = lhs / rhs; - } break; - - default: return; - } - - auto value = std::make_unique<NumericValue>(); - value->SetValue(res); - ctx.SetConnectionValue(mOutputs[0], std::move(value)); -} - -bool NumericExpressionNode::IsInstance(const WorkflowNode* node) -{ - return node->GetKind() == KD_NumericExpression; -} - -NumericExpressionNode::NumericExpressionNode() - : WorkflowNode(KD_NumericExpression, false) -{ -} - -void NumericExpressionNode::Evaluate(WorkflowEvaluationContext& ctx) -{ -} diff --git a/core/src/Model/Workflow/Nodes/NumericNodes.hpp b/core/src/Model/Workflow/Nodes/NumericNodes.hpp deleted file mode 100644 index 56c0313..0000000 --- a/core/src/Model/Workflow/Nodes/NumericNodes.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "Model/Workflow/Workflow.hpp" - -#include <cstddef> -#include <memory> -#include <variant> -#include <vector> - -class NumericOperationNode : public WorkflowNode -{ -public: - enum OperationType - { - Addition, - Subtraction, - Multiplication, - Division, - - InvalidType, - TypeCount = InvalidType, - }; - -private: - OperationType mType; - -public: - static Kind OperationTypeToNodeKind(OperationType type); - static OperationType NodeKindToOperationType(Kind kind); - static bool IsInstance(const WorkflowNode* node); - NumericOperationNode(OperationType type); - - virtual void Evaluate(WorkflowEvaluationContext& ctx) override; -}; - -class NumericExpressionNode : public WorkflowNode -{ -public: - static bool IsInstance(const WorkflowNode* node); - NumericExpressionNode(); - - // TODO - virtual void Evaluate(WorkflowEvaluationContext& ctx) override; -};
\ No newline at end of file diff --git a/core/src/Model/Workflow/Nodes/TextNodes.cpp b/core/src/Model/Workflow/Nodes/TextNodes.cpp deleted file mode 100644 index 4628dd3..0000000 --- a/core/src/Model/Workflow/Nodes/TextNodes.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include "TextNodes.hpp" - -#include "Model/Workflow/Evaluation.hpp" -#include "Model/Workflow/Values/Basic.hpp" -#include "Utils/Macros.hpp" -#include "Utils/RTTI.hpp" -#include "Utils/Variant.hpp" - -#include <cassert> -#include <utility> -#include <variant> -#include <vector> - -class TextFormatterNode::Impl -{ -public: - template <class TFunction> - static void ForArguments(std::vector<Element>::iterator begin, std::vector<Element>::iterator end, const TFunction& func) - { - for (auto it = begin; it != end; ++it) { - auto& elm = *it; - if (auto arg = std::get_if<Argument>(&elm)) { - func(*arg); - } - } - } - - /// Find the pin index that the \c elmIdx -th element should have, based on the elements coming before it. - static int FindPinForElement(const std::vector<Element>& vec, int elmIdx) - { - for (int i = elmIdx; i >= 0; --i) { - auto& elm = vec[i]; - if (auto arg = std::get_if<Argument>(&elm)) { - return arg->PinIdx + 1; - } - } - return 0; - } -}; - -BaseValue::Kind TextFormatterNode::ArgumentTypeToValueKind(TextFormatterNode::ArgumentType arg) -{ - switch (arg) { - case NumericArgument: return BaseValue::KD_Numeric; - case TextArgument: return BaseValue::KD_Text; - case DateTimeArgument: return BaseValue::KD_DateTime; - } -} - -bool TextFormatterNode::IsInstance(const WorkflowNode* node) -{ - return node->GetKind() == KD_TextFormatting; -} - -TextFormatterNode::TextFormatterNode() - : WorkflowNode(KD_TextFormatting, false) -{ -} - -int TextFormatterNode::GetElementCount() const -{ - return mElements.size(); -} - -const TextFormatterNode::Element& TextFormatterNode::GetElement(int idx) const -{ - return mElements[idx]; -} - -void TextFormatterNode::SetElement(int idx, std::string text) -{ - assert(idx >= 0 && idx < mElements.size()); - - std::visit( - Overloaded{ - [&](const std::string& original) { mMinOutputChars -= original.size(); }, - [&](const Argument& original) { PreRemoveElement(idx); }, - }, - mElements[idx]); - - mMinOutputChars += text.size(); - mElements[idx] = std::move(text); -} - -void TextFormatterNode::SetElement(int idx, ArgumentType argument) -{ - assert(idx >= 0 && idx < mElements.size()); - - std::visit( - Overloaded{ - [&](const std::string& original) { - mMinOutputChars -= original.size(); - - mElements[idx] = Argument{ - .Type = argument, - .PinIdx = Impl::FindPinForElement(mElements, idx), - }; - /* `original` is invalid from this point */ - }, - [&](const Argument& original) { - int pinIdx = original.PinIdx; - - // Create pin - auto& pin = mInputs[pinIdx]; - pin.MatchingType = ArgumentTypeToValueKind(argument); - - // Create element - mElements[idx] = Argument{ - .Type = argument, - .PinIdx = pinIdx, - }; - /* `original` is invalid from this point */ - }, - }, - mElements[idx]); -} - -void TextFormatterNode::InsertElement(int idx, std::string text) -{ - assert(idx >= 0); - if (idx >= mElements.size()) AppendElement(std::move(text)); - - mMinOutputChars += text.size(); - mElements.insert(mElements.begin() + idx, std::move(text)); -} - -void TextFormatterNode::InsertElement(int idx, ArgumentType argument) -{ - assert(idx >= 0); - if (idx >= mElements.size()) AppendElement(argument); - - int pinIdx = Impl::FindPinForElement(mElements, idx); - - // Create pin - auto& pin = InsertInputPin(pinIdx); - pin.MatchingType = ArgumentTypeToValueKind(argument); - - // Create element - mElements.insert( - mElements.begin() + idx, - Argument{ - .Type = argument, - .PinIdx = pinIdx, - }); -} - -void TextFormatterNode::AppendElement(std::string text) -{ - mMinOutputChars += text.size(); - mElements.push_back(std::move(text)); -} - -void TextFormatterNode::AppendElement(ArgumentType argument) -{ - int pinIdx = mInputs.size(); - // Create pin - mInputs.push_back(InputPin{}); - mInputs.back().MatchingType = ArgumentTypeToValueKind(argument); - // Creat eelement - mElements.push_back(Argument{ - .Type = argument, - .PinIdx = pinIdx, - }); -} - -void TextFormatterNode::RemoveElement(int idx) -{ - assert(idx >= 0 && idx < mElements.size()); - - PreRemoveElement(idx); - if (auto arg = std::get_if<Argument>(&mElements[idx])) { - RemoveInputPin(arg->PinIdx); - } - mElements.erase(mElements.begin() + idx); -} - -void TextFormatterNode::Evaluate(WorkflowEvaluationContext& ctx) -{ - std::string result; - result.reserve((size_t)(mMinOutputChars * 1.5f)); - - auto HandleText = [&](const std::string& str) { - result += str; - }; - auto HandleArgument = [&](const Argument& arg) { - switch (arg.Type) { - case NumericArgument: { - if (auto val = dyn_cast<NumericValue>(ctx.GetConnectionValue(mInputs[arg.PinIdx]))) { - result += val->GetString(); - } else { - // TODO localize - ctx.ReportError("Non-numeric value connected to a numeric text format parameter.", *this); - } - } break; - case TextArgument: { - if (auto val = dyn_cast<TextValue>(ctx.GetConnectionValue(mInputs[arg.PinIdx]))) { - result += val->GetValue(); - } else { - // TODO localize - ctx.ReportError("Non-text value connected to a textual text format parameter.", *this); - } - } break; - case DateTimeArgument: { - if (auto val = dyn_cast<DateTimeValue>(ctx.GetConnectionValue(mInputs[arg.PinIdx]))) { - result += val->GetString(); - } else { - // TODO localize - ctx.ReportError("Non-date/time value connected to a date/time text format parameter.", *this); - } - } break; - } - }; - - for (auto& elm : mElements) { - std::visit(Overloaded{ HandleText, HandleArgument }, elm); - } -} - -void TextFormatterNode::PreRemoveElement(int idx) -{ - auto& elm = mElements[idx]; - if (auto arg = std::get_if<Argument>(&elm)) { - RemoveInputPin(arg->PinIdx); - Impl::ForArguments( - mElements.begin() + idx + 1, - mElements.end(), - [&](Argument& arg) { - arg.PinIdx--; - }); - } -} diff --git a/core/src/Model/Workflow/Nodes/TextNodes.hpp b/core/src/Model/Workflow/Nodes/TextNodes.hpp deleted file mode 100644 index c33854c..0000000 --- a/core/src/Model/Workflow/Nodes/TextNodes.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "Model/Workflow/Workflow.hpp" - -#include <cstddef> -#include <memory> -#include <variant> -#include <vector> - -class TextFormatterNode : public WorkflowNode -{ -public: - enum ArgumentType - { - NumericArgument, - TextArgument, - DateTimeArgument, - }; - -private: - class Impl; - - struct Argument - { - ArgumentType Type; - int PinIdx; - }; - using Element = std::variant<std::string, Argument>; - - std::vector<Element> mElements; - int mMinOutputChars; - -public: - static BaseValue::Kind ArgumentTypeToValueKind(ArgumentType arg); - static bool IsInstance(const WorkflowNode* node); - TextFormatterNode(); - - int GetElementCount() const; - const Element& GetElement(int idx) const; - - void SetElement(int idx, std::string text); - void SetElement(int idx, ArgumentType argument); - void InsertElement(int idx, std::string text); - void InsertElement(int idx, ArgumentType argument); - void AppendElement(std::string text); - void AppendElement(ArgumentType argument); - void RemoveElement(int idx); - - virtual void Evaluate(WorkflowEvaluationContext& ctx) override; - -private: - void PreRemoveElement(int idx); -}; diff --git a/core/src/Model/Workflow/Nodes/UserInputNodes.cpp b/core/src/Model/Workflow/Nodes/UserInputNodes.cpp deleted file mode 100644 index 0b6d471..0000000 --- a/core/src/Model/Workflow/Nodes/UserInputNodes.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "UserInputNodes.hpp" - -#include "Model/Workflow/Evaluation.hpp" -#include "Model/Workflow/Values/Basic.hpp" - -bool FormInputNode::IsInstance(const WorkflowNode* node) -{ - return node->GetKind() == KD_FormInput; -} - -FormInputNode::FormInputNode() - : WorkflowNode(KD_FormInput, false) -{ -} - -void FormInputNode::Evaluate(WorkflowEvaluationContext& ctx) -{ -} - -bool DatabaseRowsInputNode::IsInstance(const WorkflowNode* node) -{ - return node->GetKind() == KD_DatabaseRowsInput; -} - -DatabaseRowsInputNode::DatabaseRowsInputNode() - : WorkflowNode(KD_DatabaseRowsInput, false) -{ -} - -void DatabaseRowsInputNode::Evaluate(WorkflowEvaluationContext& ctx) -{ -} diff --git a/core/src/Model/Workflow/Nodes/UserInputNodes.hpp b/core/src/Model/Workflow/Nodes/UserInputNodes.hpp deleted file mode 100644 index 10ea95d..0000000 --- a/core/src/Model/Workflow/Nodes/UserInputNodes.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "Model/Workflow/Workflow.hpp" - -class FormInputNode : public WorkflowNode -{ -public: - static bool IsInstance(const WorkflowNode* node); - FormInputNode(); - - // TODO - virtual void Evaluate(WorkflowEvaluationContext& ctx) override; -}; - -class DatabaseRowsInputNode : public WorkflowNode -{ -public: - static bool IsInstance(const WorkflowNode* node); - DatabaseRowsInputNode(); - - // TODO - virtual void Evaluate(WorkflowEvaluationContext& ctx) override; -}; diff --git a/core/src/Model/Workflow/Nodes/fwd.hpp b/core/src/Model/Workflow/Nodes/fwd.hpp deleted file mode 100644 index 4153825..0000000 --- a/core/src/Model/Workflow/Nodes/fwd.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -// DocumentNodes.hpp -class DocumentTemplateExpansionNode; - -// InputNodes.hpp -class FormInputNode; -class DatabaseRowsInputNode; - -// NumericNodes.hpp -class NumericOperationNode; -class NumericExpressionNode; - -// TextNodes.hpp -class TextFormatterNode; diff --git a/core/src/Model/Workflow/Value.hpp b/core/src/Model/Workflow/Value.hpp deleted file mode 100644 index 2198674..0000000 --- a/core/src/Model/Workflow/Value.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once - -#include "Utils/Color.hpp" -#include "cplt_fwd.hpp" - -#include <iosfwd> -#include <memory> -#include <string> -#include <vector> - -class BaseValue -{ -public: - enum Kind - { - KD_Numeric, - KD_Text, - KD_DateTime, - KD_DatabaseRowId, - KD_List, - KD_Dictionary, - - KD_BaseObject, - KD_SaleDatabaseRow, - KD_PurchaseDatabaseRow, - KD_BaseObjectLast = KD_PurchaseDatabaseRow, - - /// An unspecified type, otherwise known as "any" in some contexts. - InvalidKind, - KindCount = InvalidKind, - }; - - struct KindInfo - { - ImGui::IconType PinIcon; - RgbaColor PinColor; - }; - -private: - Kind mKind; - -public: - static const KindInfo& QueryInfo(Kind kind); - static const char* Format(Kind kind); - static std::unique_ptr<BaseValue> CreateByKind(Kind kind); - - static bool IsInstance(const BaseValue* value); - - BaseValue(Kind kind); - virtual ~BaseValue() = default; - - BaseValue(const BaseValue&) = delete; - BaseValue& operator=(const BaseValue&) = delete; - BaseValue(BaseValue&&) = default; - BaseValue& operator=(BaseValue&&) = default; - - Kind GetKind() const; - - // TODO get constant editor - - /// The functions \c ReadFrom, \c WriteTo will only be valid to call if this function returns true. - virtual bool SupportsConstant() const; - virtual void ReadFrom(std::istream& stream); - virtual void WriteTo(std::ostream& stream); -}; - -class BaseObjectDescription -{ -public: - struct Property - { - std::string Name; - BaseValue::Kind Kind; - bool Mutatable = true; - }; - -public: - std::vector<Property> Properties; -}; - -class BaseObjectValue : public BaseValue -{ -public: - /// \param kind A value kind enum, within the range of KD_BaseObject and KD_BaseObjectLast (both inclusive). - static const BaseObjectDescription& QueryObjectInfo(Kind kind); - - static bool IsInstance(const BaseValue* value); - BaseObjectValue(Kind kind); - - const BaseObjectDescription& GetObjectDescription() const; - - virtual const BaseValue* GetProperty(int idx) const = 0; - virtual bool SetProperty(int idx, std::unique_ptr<BaseValue> value) = 0; -}; diff --git a/core/src/Model/Workflow/ValueInternals.hpp b/core/src/Model/Workflow/ValueInternals.hpp deleted file mode 100644 index 49981f0..0000000 --- a/core/src/Model/Workflow/ValueInternals.hpp +++ /dev/null @@ -1,21 +0,0 @@ -// This file contains utility classes and macros for implementing values -// As consumers, you should not include this header as it contains unnecessary symbols and can pollute your files -// for this reason, classes here aren't forward-declared in fwd.hpp either. - -#pragma once - -#include "Utils/RTTI.hpp" - -#include <utility> - -#define CHECK_VALUE_TYPE(Type, value) \ - if (!is_a<Type>(value)) { \ - return false; \ - } - -#define CHECK_VALUE_TYPE_AND_MOVE(Type, dest, value) \ - if (auto ptr = dyn_cast<Type>(value)) { \ - dest = std::move(*ptr); \ - } else { \ - return false; \ - } diff --git a/core/src/Model/Workflow/Value_Main.cpp b/core/src/Model/Workflow/Value_Main.cpp deleted file mode 100644 index ca972c4..0000000 --- a/core/src/Model/Workflow/Value_Main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "Value.hpp" - -BaseValue::BaseValue(Kind kind) - : mKind{ kind } -{ -} - -BaseValue::Kind BaseValue::GetKind() const -{ - return mKind; -} - -bool BaseValue::SupportsConstant() const -{ - return false; -} - -void BaseValue::ReadFrom(std::istream& stream) -{ -} - -void BaseValue::WriteTo(std::ostream& stream) -{ -} - -BaseObjectValue::BaseObjectValue(Kind kind) - : BaseValue(kind) -{ - assert(kind >= KD_BaseObject && kind <= KD_BaseObjectLast); -} - -const BaseObjectDescription& BaseObjectValue::GetObjectDescription() const -{ - return QueryObjectInfo(this->GetKind()); -} diff --git a/core/src/Model/Workflow/Value_RTTI.cpp b/core/src/Model/Workflow/Value_RTTI.cpp deleted file mode 100644 index 0561239..0000000 --- a/core/src/Model/Workflow/Value_RTTI.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include "Value.hpp" - -#include "Model/Workflow/Values/Basic.hpp" -#include "Model/Workflow/Values/Database.hpp" -#include "Model/Workflow/Values/Dictionary.hpp" -#include "Model/Workflow/Values/List.hpp" -#include "UI/UI.hpp" -#include "Utils/I18n.hpp" - -constexpr BaseValue::KindInfo kEmptyInfo{ - .PinIcon = ImGui::IconType::Circle, - .PinColor = RgbaColor(), -}; - -constexpr BaseValue::KindInfo kNumericInfo{ - .PinIcon = ImGui::IconType::Circle, - .PinColor = RgbaColor(147, 226, 74), -}; - -constexpr BaseValue::KindInfo kTextInfo{ - .PinIcon = ImGui::IconType::Circle, - .PinColor = RgbaColor(124, 21, 153), -}; - -constexpr BaseValue::KindInfo kDateTimeInfo{ - .PinIcon = ImGui::IconType::Circle, - .PinColor = RgbaColor(147, 226, 74), -}; - -constexpr BaseValue::KindInfo kDatabaseRowIdInfo{ - .PinIcon = ImGui::IconType::Circle, - .PinColor = RgbaColor(216, 42, 221), -}; - -constexpr BaseValue::KindInfo kListInfo{ - .PinIcon = ImGui::IconType::Diamond, - .PinColor = RgbaColor(58, 154, 214), -}; - -constexpr BaseValue::KindInfo kDictionaryInfo{ - .PinIcon = ImGui::IconType::Diamond, - .PinColor = RgbaColor(240, 240, 34), -}; - -constexpr BaseValue::KindInfo kDatabaseRowInfo{ - .PinIcon = ImGui::IconType::Square, - .PinColor = RgbaColor(15, 124, 196), -}; - -constexpr BaseValue::KindInfo kObjectInfo{ - .PinIcon = ImGui::IconType::Square, - .PinColor = RgbaColor(161, 161, 161), -}; - -const BaseValue::KindInfo& BaseValue::QueryInfo(BaseValue::Kind kind) -{ - switch (kind) { - case KD_Numeric: return kNumericInfo; - case KD_Text: return kTextInfo; - case KD_DateTime: return kDateTimeInfo; - case KD_DatabaseRowId: return kDatabaseRowIdInfo; - case KD_List: return kListInfo; - case KD_Dictionary: return kDictionaryInfo; - - case KD_BaseObject: return kObjectInfo; - case KD_SaleDatabaseRow: - case KD_PurchaseDatabaseRow: - return kDatabaseRowInfo; - - case InvalidKind: break; - } - return kEmptyInfo; -} - -const char* BaseValue::Format(Kind kind) -{ - switch (kind) { - case KD_Numeric: return I18N_TEXT("Numeric", L10N_VALUE_NUMERIC); - case KD_Text: return I18N_TEXT("Text", L10N_VALUE_TEXT); - case KD_DateTime: return I18N_TEXT("Date/time", L10N_VALUE_DATE_TIME); - case KD_DatabaseRowId: return I18N_TEXT("Row id", L10N_VALUE_ROW_ID); - case KD_List: return I18N_TEXT("List", L10N_VALUE_LIST); - case KD_Dictionary: return I18N_TEXT("Dictionary", L10N_VALUE_DICT); - - case KD_BaseObject: return I18N_TEXT("Object", L10N_VALUE_OBJECT); - case KD_SaleDatabaseRow: return I18N_TEXT("Sale record", L10N_VALUE_SALE_RECORD); - case KD_PurchaseDatabaseRow: return I18N_TEXT("Purchase record", L10N_VALUE_PURCHASE_RECORD); - - case InvalidKind: break; - } - return ""; -} - -std::unique_ptr<BaseValue> BaseValue::CreateByKind(BaseValue::Kind kind) -{ - switch (kind) { - case KD_Numeric: return std::make_unique<NumericValue>(); - case KD_Text: return std::make_unique<TextValue>(); - case KD_DateTime: return std::make_unique<DateTimeValue>(); - case KD_DatabaseRowId: return std::make_unique<DatabaseRowIdValue>(); - case KD_List: return std::make_unique<ListValue>(); - case KD_Dictionary: return std::make_unique<DictionaryValue>(); - - case KD_BaseObject: return nullptr; - case KD_SaleDatabaseRow: return std::make_unique<SaleDatabaseRowValue>(); - case KD_PurchaseDatabaseRow: return std::make_unique<PurchaseDatabaseRowValue>(); - - case InvalidKind: break; - } - return nullptr; -} - -bool BaseValue::IsInstance(const BaseValue* value) -{ - return true; -} - -const BaseObjectDescription kEmptyObjectInfo{ - .Properties = {}, -}; - -const BaseObjectDescription kSaleDbRowObject{ - .Properties = { - { - .Name = I18N_TEXT("Customer", L10N_VALUE_PROPERTY_CUSTOMER), - .Kind = BaseValue::KD_Text, - .Mutatable = false, - }, - { - .Name = I18N_TEXT("Deadline", L10N_VALUE_PROPERTY_DEADLINE), - .Kind = BaseValue::KD_DateTime, - }, - { - .Name = I18N_TEXT("Delivery time", L10N_VALUE_PROPERTY_DELIVERY_TIME), - .Kind = BaseValue::KD_DateTime, - }, - }, -}; - -const BaseObjectDescription kPurchaseDbRowObject{ - .Properties = { - { - .Name = I18N_TEXT("Factory", L10N_VALUE_PROPERTY_FACTORY), - .Kind = BaseValue::KD_Text, - .Mutatable = false, - }, - { - .Name = I18N_TEXT("Order time", L10N_VALUE_PROPERTY_ORDER_TIME), - .Kind = BaseValue::KD_DateTime, - }, - { - .Name = I18N_TEXT("Delivery time", L10N_VALUE_PROPERTY_DELIVERY_TIME), - .Kind = BaseValue::KD_DateTime, - }, - }, -}; - -const BaseObjectDescription& BaseObjectValue::QueryObjectInfo(Kind kind) -{ - switch (kind) { - case KD_BaseObject: return kEmptyObjectInfo; - case KD_SaleDatabaseRow: return kSaleDbRowObject; - case KD_PurchaseDatabaseRow: return kPurchaseDbRowObject; - - default: break; - } - return kEmptyObjectInfo; -} - -bool BaseObjectValue::IsInstance(const BaseValue* value) -{ - return value->GetKind() >= KD_BaseObject && - value->GetKind() <= KD_BaseObjectLast; -} diff --git a/core/src/Model/Workflow/Values/Basic.cpp b/core/src/Model/Workflow/Values/Basic.cpp deleted file mode 100644 index 198387c..0000000 --- a/core/src/Model/Workflow/Values/Basic.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "Basic.hpp" - -#include <charconv> -#include <cmath> -#include <limits> - -bool NumericValue::IsInstance(const BaseValue* value) -{ - return value->GetKind() == KD_Numeric; -} - -NumericValue::NumericValue() - : BaseValue(BaseValue::KD_Numeric) -{ -} - -template <class T, int kMaxSize> -static std::string NumberToString(T value) -{ - char buf[kMaxSize]; - auto res = std::to_chars(buf, buf + kMaxSize, value); - if (res.ec == std::errc()) { - return std::string(buf, res.ptr); - } else { - return "<err>"; - } -} - -std::string NumericValue::GetTruncatedString() const -{ - constexpr auto kMaxSize = std::numeric_limits<int64_t>::digits10; - return ::NumberToString<int64_t, kMaxSize>((int64_t)mValue); -} - -std::string NumericValue::GetRoundedString() const -{ - constexpr auto kMaxSize = std::numeric_limits<int64_t>::digits10; - return ::NumberToString<int64_t, kMaxSize>((int64_t)std::round(mValue)); -} - -std::string NumericValue::GetString() const -{ - constexpr auto kMaxSize = std::numeric_limits<double>::max_digits10; - return ::NumberToString<double, kMaxSize>(mValue); -} - -int64_t NumericValue::GetInt() const -{ - return static_cast<int64_t>(mValue); -} - -double NumericValue::GetValue() const -{ - return mValue; -} - -void NumericValue::SetValue(double value) -{ - mValue = value; -} - -bool TextValue::IsInstance(const BaseValue* value) -{ - return value->GetKind() == KD_Text; -} - -TextValue::TextValue() - : BaseValue(BaseValue::KD_Text) -{ -} - -const std::string& TextValue::GetValue() const -{ - return mValue; -} - -void TextValue::SetValue(const std::string& value) -{ - mValue = value; -} - -bool DateTimeValue::IsInstance(const BaseValue* value) -{ - return value->GetKind() == KD_DateTime; -} - -DateTimeValue::DateTimeValue() - : BaseValue(BaseValue::KD_DateTime) -{ -} - -std::string DateTimeValue::GetString() const -{ - namespace chrono = std::chrono; - auto t = chrono::system_clock::to_time_t(mValue); - - char data[32]; - std::strftime(data, sizeof(data), "%Y-%m-%d %H:%M:%S", std::localtime(&t)); - - return std::string(data); -} - -const std::chrono::time_point<std::chrono::system_clock>& DateTimeValue::GetValue() const -{ - return mValue; -} - -void DateTimeValue::SetValue(const std::chrono::time_point<std::chrono::system_clock>& value) -{ - mValue = value; -} diff --git a/core/src/Model/Workflow/Values/Basic.hpp b/core/src/Model/Workflow/Values/Basic.hpp deleted file mode 100644 index 38e0531..0000000 --- a/core/src/Model/Workflow/Values/Basic.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include "Model/Workflow/Value.hpp" - -#include <chrono> -#include <cstdint> -#include <string> - -class NumericValue : public BaseValue -{ -private: - double mValue; - -public: - static bool IsInstance(const BaseValue* value); - NumericValue(); - - NumericValue(const NumericValue&) = delete; - NumericValue& operator=(const NumericValue&) = delete; - NumericValue(NumericValue&&) = default; - NumericValue& operator=(NumericValue&&) = default; - - std::string GetTruncatedString() const; - std::string GetRoundedString() const; - std::string GetString() const; - - int64_t GetInt() const; - double GetValue() const; - void SetValue(double value); -}; - -class TextValue : public BaseValue -{ -private: - std::string mValue; - -public: - static bool IsInstance(const BaseValue* value); - TextValue(); - - TextValue(const TextValue&) = delete; - TextValue& operator=(const TextValue&) = delete; - TextValue(TextValue&&) = default; - TextValue& operator=(TextValue&&) = default; - - const std::string& GetValue() const; - void SetValue(const std::string& value); -}; - -class DateTimeValue : public BaseValue -{ -private: - std::chrono::time_point<std::chrono::system_clock> mValue; - -public: - static bool IsInstance(const BaseValue* value); - DateTimeValue(); - - DateTimeValue(const DateTimeValue&) = delete; - DateTimeValue& operator=(const DateTimeValue&) = delete; - DateTimeValue(DateTimeValue&&) = default; - DateTimeValue& operator=(DateTimeValue&&) = default; - - std::string GetString() const; - const std::chrono::time_point<std::chrono::system_clock>& GetValue() const; - void SetValue(const std::chrono::time_point<std::chrono::system_clock>& value); -}; diff --git a/core/src/Model/Workflow/Values/Database.cpp b/core/src/Model/Workflow/Values/Database.cpp deleted file mode 100644 index cdc2b4f..0000000 --- a/core/src/Model/Workflow/Values/Database.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "Database.hpp" - -#include "Model/Database.hpp" -#include "Model/Workflow/ValueInternals.hpp" - -#include <limits> - -TableKind DatabaseRowIdValue::GetTable() const -{ - return mTable; -} - -int64_t DatabaseRowIdValue::GetRowId() const -{ - return mRowId; -} - -bool DatabaseRowIdValue::IsInstance(const BaseValue* value) -{ - return value->GetKind() == KD_DatabaseRowId; -} - -DatabaseRowIdValue::DatabaseRowIdValue() - : BaseValue(KD_DatabaseRowId) - , mTable{ TableKind::Sales } - , mRowId{ std::numeric_limits<int64_t>::max() } -{ -} - -bool SaleDatabaseRowValue::IsInstance(const BaseValue* value) -{ - return value->GetKind() == KD_SaleDatabaseRow; -} - -SaleDatabaseRowValue::SaleDatabaseRowValue() - : BaseObjectValue(KD_SaleDatabaseRow) -{ -} - -const BaseValue* SaleDatabaseRowValue::GetProperty(int idx) const -{ - switch (idx) { - case 0: return &mCustomerName; - case 1: return &mDeadline; - case 2: return &mDeliveryTime; - default: return nullptr; - } -} - -bool SaleDatabaseRowValue::SetProperty(int idx, std::unique_ptr<BaseValue> value) -{ - switch (idx) { - case 0: return false; - case 1: CHECK_VALUE_TYPE_AND_MOVE(DateTimeValue, mDeadline, value.get()); break; - case 2: CHECK_VALUE_TYPE_AND_MOVE(DateTimeValue, mDeliveryTime, value.get()); break; - } - return true; -} - -bool PurchaseDatabaseRowValue::IsInstance(const BaseValue* value) -{ - return value->GetKind() == KD_PurchaseDatabaseRow; -} - -PurchaseDatabaseRowValue::PurchaseDatabaseRowValue() - : BaseObjectValue(KD_PurchaseDatabaseRow) -{ -} - -const BaseValue* PurchaseDatabaseRowValue::GetProperty(int idx) const -{ - switch (idx) { - case 0: return &mFactoryName; - case 1: return &mOrderTime; - case 2: return &mDeliveryTime; - default: return nullptr; - } -} - -bool PurchaseDatabaseRowValue::SetProperty(int idx, std::unique_ptr<BaseValue> value) -{ - switch (idx) { - case 0: return false; - case 1: CHECK_VALUE_TYPE_AND_MOVE(DateTimeValue, mOrderTime, value.get()); break; - case 2: CHECK_VALUE_TYPE_AND_MOVE(DateTimeValue, mDeliveryTime, value.get()); break; - } - return true; -} diff --git a/core/src/Model/Workflow/Values/Database.hpp b/core/src/Model/Workflow/Values/Database.hpp deleted file mode 100644 index e8a4f83..0000000 --- a/core/src/Model/Workflow/Values/Database.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "Model/Workflow/Value.hpp" -#include "Model/Workflow/Values/Basic.hpp" -#include "cplt_fwd.hpp" - -class DatabaseRowIdValue : public BaseValue -{ -private: - TableKind mTable; - int64_t mRowId; - -public: - static bool IsInstance(const BaseValue* value); - DatabaseRowIdValue(); - - TableKind GetTable() const; - int64_t GetRowId() const; -}; - -class SaleDatabaseRowValue : public BaseObjectValue -{ -private: - int mCustomerId; - TextValue mCustomerName; - DateTimeValue mDeadline; - DateTimeValue mDeliveryTime; - -public: - static bool IsInstance(const BaseValue* value); - SaleDatabaseRowValue(); - - virtual const BaseValue* GetProperty(int idx) const; - virtual bool SetProperty(int idx, std::unique_ptr<BaseValue> value); -}; - -class PurchaseDatabaseRowValue : public BaseObjectValue -{ -private: - int mFactoryId; - TextValue mFactoryName; - DateTimeValue mOrderTime; - DateTimeValue mDeliveryTime; - -public: - static bool IsInstance(const BaseValue* value); - PurchaseDatabaseRowValue(); - - virtual const BaseValue* GetProperty(int idx) const; - virtual bool SetProperty(int idx, std::unique_ptr<BaseValue> value); -}; diff --git a/core/src/Model/Workflow/Values/Dictionary.cpp b/core/src/Model/Workflow/Values/Dictionary.cpp deleted file mode 100644 index 106e48d..0000000 --- a/core/src/Model/Workflow/Values/Dictionary.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "Dictionary.hpp" - -#include "Utils/Macros.hpp" - -bool DictionaryValue::IsInstance(const BaseValue* value) -{ - return value->GetKind() == KD_Dictionary; -} - -DictionaryValue::DictionaryValue() - : BaseValue(KD_Dictionary) -{ -} - -int DictionaryValue::GetCount() const -{ - return mElements.size(); -} - -BaseValue* DictionaryValue::Find(std::string_view key) -{ - auto iter = mElements.find(key); - if (iter != mElements.end()) { - return iter.value().get(); - } else { - return nullptr; - } -} - -BaseValue* DictionaryValue::Insert(std::string_view key, std::unique_ptr<BaseValue>& value) -{ - auto [iter, success] = mElements.insert(key, std::move(value)); - if (success) { - return iter.value().get(); - } else { - return nullptr; - } -} - -BaseValue& DictionaryValue::InsertOrReplace(std::string_view key, std::unique_ptr<BaseValue> value) -{ - auto [iter, DISCARD] = mElements.emplace(key, std::move(value)); - return *iter.value(); -} - -void DictionaryValue::Remove(std::string_view key) -{ - mElements.erase(mElements.find(key)); -} diff --git a/core/src/Model/Workflow/Values/Dictionary.hpp b/core/src/Model/Workflow/Values/Dictionary.hpp deleted file mode 100644 index 65ea82f..0000000 --- a/core/src/Model/Workflow/Values/Dictionary.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "Model/Workflow/Value.hpp" - -#include <tsl/array_map.h> -#include <memory> -#include <string> -#include <string_view> - -class DictionaryValue : public BaseValue -{ -private: - tsl::array_map<char, std::unique_ptr<BaseValue>> mElements; - -public: - static bool IsInstance(const BaseValue* value); - DictionaryValue(); - - int GetCount() const; - BaseValue* Find(std::string_view key); - - BaseValue* Insert(std::string_view key, std::unique_ptr<BaseValue>& value); - BaseValue& InsertOrReplace(std::string_view key, std::unique_ptr<BaseValue> value); - void Remove(std::string_view key); -}; diff --git a/core/src/Model/Workflow/Values/List.cpp b/core/src/Model/Workflow/Values/List.cpp deleted file mode 100644 index 9fd6bfd..0000000 --- a/core/src/Model/Workflow/Values/List.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "List.hpp" - -#include <utility> - -BaseValue* ListValue::Iterator::operator*() const -{ - return mIter->get(); -} - -BaseValue* ListValue::Iterator::operator->() const -{ - return mIter->get(); -} - -ListValue::Iterator& ListValue::Iterator::operator++() -{ - ++mIter; - return *this; -} - -ListValue::Iterator ListValue::Iterator::operator++(int) const -{ - return Iterator(mIter + 1); -} - -ListValue::Iterator& ListValue::Iterator::operator--() -{ - --mIter; - return *this; -} - -ListValue::Iterator ListValue::Iterator::operator--(int) const -{ - return Iterator(mIter - 1); -} - -bool operator==(const ListValue::Iterator& a, const ListValue::Iterator& b) -{ - return a.mIter == b.mIter; -} - -ListValue::Iterator::Iterator(decltype(mIter) iter) - : mIter{ iter } -{ -} - -bool ListValue::IsInstance(const BaseValue* value) -{ - return value->GetKind() == KD_List; -} - -ListValue::ListValue() - : BaseValue(KD_List) -{ -} - -int ListValue::GetCount() const -{ - return mElements.size(); -} - -BaseValue* ListValue::GetElement(int i) const -{ - return mElements[i].get(); -} - -void ListValue::Append(std::unique_ptr<BaseValue> element) -{ - mElements.push_back(std::move(element)); -} - -void ListValue::Insert(int i, std::unique_ptr<BaseValue> element) -{ - mElements.insert(mElements.begin() + i, std::move(element)); -} - -void ListValue::Insert(Iterator iter, std::unique_ptr<BaseValue> element) -{ - mElements.insert(iter.mIter, std::move(element)); -} - -void ListValue::Remove(int i) -{ - mElements.erase(mElements.begin() + i); -} - -void ListValue::Remove(Iterator iter) -{ - mElements.erase(iter.mIter); -} - -ListValue::Iterator ListValue::begin() -{ - return Iterator(mElements.begin()); -} - -ListValue::Iterator ListValue::end() -{ - return Iterator(mElements.end()); -} diff --git a/core/src/Model/Workflow/Values/List.hpp b/core/src/Model/Workflow/Values/List.hpp deleted file mode 100644 index 706a95c..0000000 --- a/core/src/Model/Workflow/Values/List.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "Model/Workflow/Value.hpp" - -#include <memory> -#include <vector> - -class ListValue : public BaseValue -{ -public: - class Iterator - { - private: - std::vector<std::unique_ptr<BaseValue>>::iterator mIter; - - public: - BaseValue* operator*() const; - BaseValue* operator->() const; - - Iterator& operator++(); - Iterator operator++(int) const; - Iterator& operator--(); - Iterator operator--(int) const; - - friend bool operator==(const Iterator& a, const Iterator& b); - - private: - friend class ListValue; - Iterator(decltype(mIter) iter); - }; - -private: - std::vector<std::unique_ptr<BaseValue>> mElements; - -public: - static bool IsInstance(const BaseValue* value); - ListValue(); - - int GetCount() const; - BaseValue* GetElement(int i) const; - - void Append(std::unique_ptr<BaseValue> element); - void Insert(int i, std::unique_ptr<BaseValue> element); - void Insert(Iterator iter, std::unique_ptr<BaseValue> element); - void Remove(int i); - void Remove(Iterator iter); - - Iterator begin(); - Iterator end(); -}; diff --git a/core/src/Model/Workflow/Values/fwd.hpp b/core/src/Model/Workflow/Values/fwd.hpp deleted file mode 100644 index 51a04e9..0000000 --- a/core/src/Model/Workflow/Values/fwd.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -// Basic.hpp -class NumericValue; -class TextValue; -class DateTimeValue; - -// Database.hpp -class DatabaseRowIdValue; -class SaleDatabaseRowValue; -class PurchaseDatabaseRowValue; - -// Dictionary.hpp -class DictionaryValue; - -// List.hpp -class ListValue; diff --git a/core/src/Model/Workflow/Workflow.hpp b/core/src/Model/Workflow/Workflow.hpp deleted file mode 100644 index 3c4d320..0000000 --- a/core/src/Model/Workflow/Workflow.hpp +++ /dev/null @@ -1,316 +0,0 @@ -#pragma once - -#include "Model/Assets.hpp" -#include "Model/Workflow/Value.hpp" -#include "Utils/Vector.hpp" -#include "cplt_fwd.hpp" - -#include <imgui_node_editor.h> -#include <cstddef> -#include <cstdint> -#include <filesystem> -#include <functional> -#include <iosfwd> -#include <limits> -#include <memory> -#include <span> -#include <string> -#include <variant> -#include <vector> - -namespace ImNodes = ax::NodeEditor; - -class WorkflowConnection -{ -public: - static constexpr auto kInvalidId = std::numeric_limits<uint32_t>::max(); - - uint32_t Id; - uint32_t SourceNode; - uint32_t SourcePin; - uint32_t DestinationNode; - uint32_t DestinationPin; - -public: - WorkflowConnection(); - - bool IsValid() const; - - /// Used for `LinkId` when interfacing with imgui node editor. Runtime only (not saved to disk and generated when loading). - ImNodes::LinkId GetLinkId() const; - - void DrawDebugInfo() const; - void ReadFrom(std::istream& stream); - void WriteTo(std::ostream& stream) const; -}; - -class WorkflowNode -{ -public: - static constexpr auto kInvalidId = std::numeric_limits<uint32_t>::max(); - static constexpr auto kInvalidPinId = std::numeric_limits<uint32_t>::max(); - - enum Type - { - InputType, - TransformType, - OutputType, - }; - - enum Kind - { - KD_NumericAddition, - KD_NumericSubtraction, - KD_NumericMultiplication, - KD_NumericDivision, - KD_NumericExpression, - KD_TextFormatting, - KD_DocumentTemplateExpansion, - KD_FormInput, - KD_DatabaseRowsInput, - - InvalidKind, - KindCount = InvalidKind, - }; - - enum Category - { - CG_Numeric, - CG_Text, - CG_Document, - CG_UserInput, - CG_SystemInput, - CG_Output, - - InvalidCategory, - CategoryCount = InvalidCategory, - }; - - struct InputPin - { - uint32_t Connection = WorkflowConnection::kInvalidId; - BaseValue::Kind MatchingType = BaseValue::InvalidKind; - bool ConnectionToConst = false; - - /// A constant connection connects from a user-specified constant value, feeding to a valid \c DestinationNode and \c DestinationPin (i.e. input pins). - bool IsConstantConnection() const; - bool IsConnected() const; - BaseValue::Kind GetMatchingType() const; - }; - - struct OutputPin - { - uint32_t Connection = WorkflowConnection::kInvalidId; - BaseValue::Kind MatchingType = BaseValue::InvalidKind; - - bool IsConnected() const; - BaseValue::Kind GetMatchingType() const; - }; - -protected: - friend class Workflow; - friend class WorkflowEvaluationContext; - - Workflow* mWorkflow; - std::vector<InputPin> mInputs; - std::vector<OutputPin> mOutputs; - Vec2i mPosition; - uint32_t mId; - Kind mKind; - int mDepth; - bool mLocked; - -public: - static const char* FormatKind(Kind kind); - static const char* FormatCategory(Category category); - static const char* FormatType(Type type); - static Category QueryCategory(Kind kind); - static std::span<const Kind> QueryCategoryMembers(Category category); - static std::unique_ptr<WorkflowNode> CreateByKind(Kind kind); - - static bool IsInstance(const WorkflowNode* node); - - WorkflowNode(Kind kind, bool locked); - virtual ~WorkflowNode() = default; - - WorkflowNode(const WorkflowNode&) = delete; - WorkflowNode& operator=(const WorkflowNode&) = delete; - WorkflowNode(WorkflowNode&&) = default; - WorkflowNode& operator=(WorkflowNode&&) = default; - - void SetPosition(const Vec2i& position); - Vec2i GetPosition() const; - - uint32_t GetId() const; - /// Used for `NodeId` when interfacing with imgui node editor. Runtime only (not saved to disk and generated when loading). - ImNodes::NodeId GetNodeId() const; - Kind GetKind() const; - int GetDepth() const; - bool IsLocked() const; - - Type GetType() const; - bool IsInputNode() const; - bool IsOutputNode() const; - - void ConnectInput(uint32_t pinId, WorkflowNode& srcNode, uint32_t srcPinId); - void DisconnectInput(uint32_t pinId); - - void DrawInputPinDebugInfo(uint32_t pinId) const; - const InputPin& GetInputPin(uint32_t pinId) const; - ImNodes::PinId GetInputPinUniqueId(uint32_t pinId) const; - - void ConnectOutput(uint32_t pinId, WorkflowNode& dstNode, uint32_t dstPinId); - void DisconnectOutput(uint32_t pinId); - - void DrawOutputPinDebugInfo(uint32_t pinId) const; - const OutputPin& GetOutputPin(uint32_t pinId) const; - ImNodes::PinId GetOutputPinUniqueId(uint32_t pinId) const; - - virtual void Evaluate(WorkflowEvaluationContext& ctx) = 0; - - void Draw(); - virtual void DrawExtra() {} - - void DrawDebugInfo() const; - virtual void DrawExtraDebugInfo() const {} - - virtual void ReadFrom(std::istream& istream); - virtual void WriteTo(std::ostream& ostream); - -protected: - InputPin& InsertInputPin(int atIdx); - void RemoveInputPin(int pin); - void SwapInputPin(int a, int b); - OutputPin& InsertOutputPin(int atIdx); - void RemoveOutputPin(int pin); - void SwapOutputPin(int a, int b); - - /* For \c Workflow to invoke, override by implementations */ - - void OnAttach(Workflow& workflow, uint32_t newId); - void OnDetach(); -}; - -class Workflow : public Asset -{ - friend class WorkflowNode; - friend class WorkflowEvaluationContext; - class Private; - -public: - using CategoryType = WorkflowAssetList; - static constinit const WorkflowAssetList Category; - -private: - std::vector<WorkflowConnection> mConnections; - std::vector<std::unique_ptr<WorkflowNode>> mNodes; - std::vector<std::unique_ptr<BaseValue>> mConstants; - std::vector<std::vector<uint32_t>> mDepthGroups; - int mConnectionCount; - int mNodeCount; - int mConstantCount; - bool mDepthsDirty = true; - -public: - /* Graph access */ - - const std::vector<WorkflowConnection>& GetConnections() const; - std::vector<WorkflowConnection>& GetConnections(); - const std::vector<std::unique_ptr<WorkflowNode>>& GetNodes() const; - std::vector<std::unique_ptr<WorkflowNode>>& GetNodes(); - const std::vector<std::unique_ptr<BaseValue>>& GetConstants() const; - std::vector<std::unique_ptr<BaseValue>>& GetConstants(); - - WorkflowConnection* GetConnectionById(uint32_t id); - WorkflowConnection* GetConnectionByLinkId(ImNodes::LinkId linkId); - WorkflowNode* GetNodeById(uint32_t id); - WorkflowNode* GetNodeByNodeId(ImNodes::NodeId nodeId); - BaseValue* GetConstantById(uint32_t id); - - struct GlobalPinId - { - WorkflowNode* Node; - uint32_t PinId; - /// true => input pin - /// false => output pin - bool IsOutput; - }; - - /// `pinId` should be the `UniqueId` of a pin from a node that's within this workflow. - GlobalPinId DisassembleGlobalPinId(ImNodes::PinId id); - ImNodes::PinId FabricateGlobalPinId(const WorkflowNode& node, uint32_t pinId, bool isOutput) const; - - const std::vector<std::vector<uint32_t>>& GetDepthGroups() const; - bool DoesDepthNeedsUpdate() const; - - /* Graph mutation */ - - void AddNode(std::unique_ptr<WorkflowNode> step); - void RemoveNode(uint32_t id); - - void RemoveConnection(uint32_t id); - - bool Connect(WorkflowNode& sourceNode, uint32_t sourcePin, WorkflowNode& destinationNode, uint32_t destinationPin); - bool DisconnectBySource(WorkflowNode& sourceNode, uint32_t sourcePin); - bool DisconnectByDestination(WorkflowNode& destinationNode, uint32_t destinationPin); - - /* Graph rebuild */ - - enum GraphUpdateResult - { - /// Successfully rebuilt graph dependent data. - /// Details: nothing is written. - GUR_Success, - /// Nothing has changed since last time UpdateGraph() was called. - /// Details: nothing is written. - GUR_NoWorkToDo, - /// Details: list of nodes is written. - GUR_UnsatisfiedDependencies, - /// Details: list of nodes is written. - GUR_UnreachableNodes, - }; - - using GraphUpdateDetails = std::variant< - // Case: nothing - std::monostate, - // Case: list of nodes (ids) - std::vector<uint32_t>>; - - GraphUpdateResult UpdateGraph(GraphUpdateDetails* details = nullptr); - - /* Serialization */ - - void ReadFromDataStream(InputDataStream& stream); - void WriteToDataStream(OutputDataStream& stream) const; - -private: - std::pair<WorkflowConnection&, uint32_t> AllocWorkflowConnection(); - std::pair<std::unique_ptr<WorkflowNode>&, uint32_t> AllocWorkflowStep(); -}; - -class WorkflowAssetList final : public AssetListTyped<Workflow> -{ -private: - // AC = Asset Creator - std::string mACNewName; - NameSelectionError mACNewNameError = NameSelectionError::Empty; - -public: - // Inherit constructors - using AssetListTyped::AssetListTyped; - -protected: - void DiscoverFiles(const std::function<void(SavedAsset)>& callback) const override; - - std::string RetrieveNameFromFile(const std::filesystem::path& file) const override; - uuids::uuid RetrieveUuidFromFile(const std::filesystem::path& file) const override; - std::filesystem::path RetrievePathFromAsset(const SavedAsset& asset) const override; - - bool SaveInstance(const SavedAsset& assetInfo, const Asset* asset) const override; - Workflow* LoadInstance(const SavedAsset& assetInfo) const override; - Workflow* CreateInstance(const SavedAsset& assetInfo) const override; - bool RenameInstanceOnDisk(const SavedAsset& assetInfo, std::string_view oldName) const override; - - void DisplayAssetCreator(ListState& state) override; - void DisplayDetailsTable(ListState& state) const override; -}; diff --git a/core/src/Model/Workflow/Workflow_Main.cpp b/core/src/Model/Workflow/Workflow_Main.cpp deleted file mode 100644 index 3be2d4d..0000000 --- a/core/src/Model/Workflow/Workflow_Main.cpp +++ /dev/null @@ -1,846 +0,0 @@ -#include "Workflow.hpp" - -#include "Model/GlobalStates.hpp" -#include "Model/Project.hpp" -#include "UI/UI.hpp" -#include "Utils/I18n.hpp" -#include "Utils/IO/Archive.hpp" -#include "Utils/UUID.hpp" - -#include <imgui.h> -#include <imgui_node_editor.h> -#include <imgui_stdlib.h> -#include <tsl/robin_set.h> -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <fstream> -#include <iostream> -#include <queue> -#include <utility> - -using namespace std::literals::string_view_literals; -namespace fs = std::filesystem; -namespace ImNodes = ax::NodeEditor; - -WorkflowConnection::WorkflowConnection() - : Id{ 0 } - , SourceNode{ WorkflowNode::kInvalidId } - , SourcePin{ WorkflowNode::kInvalidPinId } - , DestinationNode{ WorkflowNode::kInvalidId } - , DestinationPin{ WorkflowNode::kInvalidPinId } -{ -} - -bool WorkflowConnection::IsValid() const -{ - return Id != 0; -} - -ImNodes::LinkId WorkflowConnection::GetLinkId() const -{ - // Our id is 0-based (represents an index directly) - // but imgui-node-editor uses the value 0 to represent a null id, so we need to offset by 1 - return Id + 1; -} - -void WorkflowConnection::DrawDebugInfo() const -{ - ImGui::Text("Source (node with output pin):"); - ImGui::Text("{ Node = %u, Pin = %u }", SourceNode, SourcePin); - ImGui::Text("Destination (node with input pin):"); - ImGui::Text("{ Node = %u, Pin = %u }", DestinationNode, DestinationPin); -} - -void WorkflowConnection::ReadFrom(std::istream& stream) -{ - stream >> SourceNode >> SourcePin; - stream >> DestinationNode >> DestinationPin; -} - -void WorkflowConnection::WriteTo(std::ostream& stream) const -{ - stream << SourceNode << SourcePin; - stream << DestinationNode << DestinationPin; -} - -bool WorkflowNode::InputPin::IsConstantConnection() const -{ - return ConnectionToConst && IsConnected(); -} - -bool WorkflowNode::InputPin::IsConnected() const -{ - return Connection != WorkflowConnection::kInvalidId; -} - -BaseValue::Kind WorkflowNode::InputPin::GetMatchingType() const -{ - return MatchingType; -} - -bool WorkflowNode::OutputPin::IsConnected() const -{ - return Connection != WorkflowConnection::kInvalidId; -} - -BaseValue::Kind WorkflowNode::OutputPin::GetMatchingType() const -{ - return MatchingType; -} - -WorkflowNode::WorkflowNode(Kind kind, bool locked) - : mKind{ kind } - , mDepth{ -1 } - , mLocked(locked) -{ -} - -Vec2i WorkflowNode::GetPosition() const -{ - return mPosition; -} - -void WorkflowNode::SetPosition(const Vec2i& position) -{ - mPosition = position; -} - -uint32_t WorkflowNode::GetId() const -{ - return mId; -} - -ImNodes::NodeId WorkflowNode::GetNodeId() const -{ - // See WorkflowConnection::GetLinkId for the rationale - return mId + 1; -} - -WorkflowNode::Kind WorkflowNode::GetKind() const -{ - return mKind; -} - -int WorkflowNode::GetDepth() const -{ - return mDepth; -} - -bool WorkflowNode::IsLocked() const -{ - return mLocked; -} - -WorkflowNode::Type WorkflowNode::GetType() const -{ - if (IsInputNode()) { - return InputType; - } else if (IsOutputNode()) { - return OutputType; - } else { - return TransformType; - } -} - -bool WorkflowNode::IsInputNode() const -{ - return mInputs.size() == 0; -} - -bool WorkflowNode::IsOutputNode() const -{ - return mOutputs.size() == 0; -} - -void WorkflowNode::ConnectInput(uint32_t pinId, WorkflowNode& srcNode, uint32_t srcPinId) -{ - mWorkflow->Connect(*this, pinId, srcNode, srcPinId); -} - -void WorkflowNode::DisconnectInput(uint32_t pinId) -{ - mWorkflow->DisconnectByDestination(*this, pinId); -} - -void WorkflowNode::DrawInputPinDebugInfo(uint32_t pinId) const -{ - ImGui::Text("Node ID: %d", mId); - ImGui::Text("Pin ID: (input) %d", pinId); -} - -const WorkflowNode::InputPin& WorkflowNode::GetInputPin(uint32_t pinId) const -{ - return mInputs[pinId]; -} - -ImNodes::PinId WorkflowNode::GetInputPinUniqueId(uint32_t pinId) const -{ - return mWorkflow->FabricateGlobalPinId(*this, pinId, false); -} - -void WorkflowNode::ConnectOutput(uint32_t pinId, WorkflowNode& dstNode, uint32_t dstPinId) -{ - mWorkflow->Connect(dstNode, dstPinId, *this, pinId); -} - -void WorkflowNode::DisconnectOutput(uint32_t pinId) -{ - mWorkflow->DisconnectBySource(*this, pinId); -} - -void WorkflowNode::DrawOutputPinDebugInfo(uint32_t pinId) const -{ - ImGui::Text("Node ID: %d", mId); - ImGui::Text("Pin ID: (output) %d", pinId); -} - -const WorkflowNode::OutputPin& WorkflowNode::GetOutputPin(uint32_t pinId) const -{ - return mOutputs[pinId]; -} - -ImNodes::PinId WorkflowNode::GetOutputPinUniqueId(uint32_t pinId) const -{ - return mWorkflow->FabricateGlobalPinId(*this, pinId, true); -} - -void WorkflowNode::Draw() -{ - for (uint32_t i = 0; i < mInputs.size(); ++i) { - auto& pin = mInputs[i]; - auto& typeInfo = BaseValue::QueryInfo(pin.MatchingType); - ImNodes::BeginPin(GetInputPinUniqueId(i), ImNodes::PinKind::Input); - // TODO - ImNodes::EndPin(); - } - for (uint32_t i = 0; i < mOutputs.size(); ++i) { - auto& pin = mOutputs[i]; - auto& typeInfo = BaseValue::QueryInfo(pin.MatchingType); - ImNodes::BeginPin(GetOutputPinUniqueId(i), ImNodes::PinKind::Output); - // TODO - ImNodes::EndPin(); - } -} - -void WorkflowNode::DrawDebugInfo() const -{ - ImGui::Text("Node kind: %s", FormatKind(mKind)); - ImGui::Text("Node type: %s", FormatType(GetType())); - ImGui::Text("Node ID: %u", mId); - ImGui::Text("Depth: %d", mDepth); - DrawExtraDebugInfo(); -} - -void WorkflowNode::ReadFrom(std::istream& stream) -{ - stream >> mId; - stream >> mPosition.x >> mPosition.y; -} - -void WorkflowNode::WriteTo(std::ostream& stream) -{ - stream << mId; - stream << mPosition.x << mPosition.y; -} - -WorkflowNode::InputPin& WorkflowNode::InsertInputPin(int atIdx) -{ - assert(atIdx >= 0 && atIdx < mInputs.size()); - - mInputs.push_back(InputPin{}); - for (int i = (int)mInputs.size() - 1, end = atIdx + 1; i >= end; --i) { - SwapInputPin(i, i + 1); - } - - return mInputs[atIdx]; -} - -void WorkflowNode::RemoveInputPin(int pin) -{ - DisconnectInput(pin); - for (int i = 0, end = (int)mInputs.size() - 1; i < end; ++i) { - SwapInputPin(i, i + 1); - } - mInputs.resize(mInputs.size() - 1); -} - -void WorkflowNode::SwapInputPin(int a, int b) -{ - auto& pinA = mInputs[a]; - auto& pinB = mInputs[b]; - - if (mWorkflow) { - if (pinA.IsConnected() && !pinA.IsConstantConnection()) { - auto& conn = *mWorkflow->GetConnectionById(pinA.Connection); - conn.DestinationPin = b; - } - if (pinB.IsConnected() && !pinB.IsConstantConnection()) { - auto& conn = *mWorkflow->GetConnectionById(pinB.Connection); - conn.DestinationPin = a; - } - } - - std::swap(pinA, pinB); -} - -WorkflowNode::OutputPin& WorkflowNode::InsertOutputPin(int atIdx) -{ - assert(atIdx >= 0 && atIdx < mOutputs.size()); - - mOutputs.push_back(OutputPin{}); - for (int i = (int)mOutputs.size() - 1, end = atIdx + 1; i >= end; --i) { - SwapOutputPin(i, i + 1); - } - - return mOutputs[atIdx]; -} - -void WorkflowNode::RemoveOutputPin(int pin) -{ - DisconnectOutput(pin); - for (int i = 0, end = (int)mOutputs.size() - 1; i < end; ++i) { - SwapInputPin(i, i + 1); - } - mOutputs.resize(mOutputs.size() - 1); -} - -void WorkflowNode::SwapOutputPin(int a, int b) -{ - auto& pinA = mOutputs[a]; - auto& pinB = mOutputs[b]; - - if (mWorkflow) { - if (pinA.IsConnected()) { - auto& conn = *mWorkflow->GetConnectionById(pinA.Connection); - conn.SourcePin = b; - } - if (pinB.IsConnected()) { - auto& conn = *mWorkflow->GetConnectionById(pinB.Connection); - conn.SourcePin = a; - } - } - - std::swap(pinA, pinB); -} - -void WorkflowNode::OnAttach(Workflow& workflow, uint32_t newId) -{ -} - -void WorkflowNode::OnDetach() -{ -} - -const std::vector<WorkflowConnection>& Workflow::GetConnections() const -{ - return mConnections; -} - -std::vector<WorkflowConnection>& Workflow::GetConnections() -{ - return mConnections; -} - -const std::vector<std::unique_ptr<WorkflowNode>>& Workflow::GetNodes() const -{ - return mNodes; -} - -std::vector<std::unique_ptr<WorkflowNode>>& Workflow::GetNodes() -{ - return mNodes; -} - -const std::vector<std::unique_ptr<BaseValue>>& Workflow::GetConstants() const -{ - return mConstants; -} - -std::vector<std::unique_ptr<BaseValue>>& Workflow::GetConstants() -{ - return mConstants; -} - -WorkflowConnection* Workflow::GetConnectionById(uint32_t id) -{ - return &mConnections[id]; -} - -WorkflowConnection* Workflow::GetConnectionByLinkId(ImNodes::LinkId id) -{ - return &mConnections[(uint32_t)(size_t)id - 1]; -} - -WorkflowNode* Workflow::GetNodeById(uint32_t id) -{ - return mNodes[id].get(); -} - -WorkflowNode* Workflow::GetNodeByNodeId(ImNodes::NodeId id) -{ - return mNodes[(uint32_t)(size_t)id - 1].get(); -} - -BaseValue* Workflow::GetConstantById(uint32_t id) -{ - return mConstants[id].get(); -} - -Workflow::GlobalPinId Workflow::DisassembleGlobalPinId(ImNodes::PinId pinId) -{ - // imgui-node-editor requires all pins to have a global, unique id - // but in our model the pin are typed (input vs output) and associated with a node: there is no built-in global id - // Therefore we encode one ourselves - - // Global pin id format - // nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn Tppppppp ppppppppp pppppppp pppppppp - // <------- (32 bits) node id -------> ^<------ (31 bits) pin id --------> - // | (1 bit) input (false) vs output (true) - - // 1 is added to pin id to prevent the 0th node's 0th input pin resulting in a 0 global pin id - // (this is problematic because imgui-node-editor use 0 to represent null) - - auto id = static_cast<uint64_t>(pinId); - GlobalPinId result; - - result.Node = mNodes[id >> 32].get(); - result.PinId = (uint32_t)(id & 0x000000001FFFFFFF) - 1; - result.IsOutput = id >> 31; - - return result; -} - -ImNodes::PinId Workflow::FabricateGlobalPinId(const WorkflowNode& node, uint32_t pinId, bool isOutput) const -{ - // See this->DisassembleGlobalPinId for format details and rationale - - uint64_t id = 0; - id |= ((uint64_t)node.GetId() << 32); - id |= (isOutput << 31); - id |= ((pinId + 1) & 0x1FFFFFFF); - - return id; -} - -const std::vector<std::vector<uint32_t>>& Workflow::GetDepthGroups() const -{ - return mDepthGroups; -} - -bool Workflow::DoesDepthNeedsUpdate() const -{ - return mDepthsDirty; -} - -void Workflow::AddNode(std::unique_ptr<WorkflowNode> step) -{ - auto [storage, id] = AllocWorkflowStep(); - storage = std::move(step); - storage->OnAttach(*this, id); - storage->mWorkflow = this; - storage->mId = id; -} - -void Workflow::RemoveNode(uint32_t id) -{ - auto& step = mNodes[id]; - if (step == nullptr) return; - - step->OnDetach(); - step->mWorkflow = nullptr; - step->mId = WorkflowNode::kInvalidId; -} - -void Workflow::RemoveConnection(uint32_t id) -{ - auto& conn = mConnections[id]; - if (!conn.IsValid()) return; - - mNodes[conn.SourceNode]->mInputs[conn.SourcePin].Connection = WorkflowNode::kInvalidId; - mNodes[conn.DestinationNode]->mInputs[conn.DestinationPin].Connection = WorkflowNode::kInvalidId; - - conn = {}; - mDepthsDirty = true; -} - -bool Workflow::Connect(WorkflowNode& sourceNode, uint32_t sourcePin, WorkflowNode& destinationNode, uint32_t destinationPin) -{ - auto& src = sourceNode.mOutputs[sourcePin]; - auto& dst = destinationNode.mInputs[destinationPin]; - - // TODO report error to user? - if (src.GetMatchingType() != dst.GetMatchingType()) { - return false; - } - - if (src.IsConnected()) { - DisconnectBySource(sourceNode, sourcePin); - } - - auto [conn, id] = AllocWorkflowConnection(); - conn.SourceNode = sourceNode.GetId(); - conn.SourcePin = sourcePin; - conn.DestinationNode = destinationNode.GetId(); - conn.DestinationPin = destinationPin; - - src.Connection = id; - dst.Connection = id; - - mDepthsDirty = true; - return true; -} - -bool Workflow::DisconnectBySource(WorkflowNode& sourceNode, uint32_t sourcePin) -{ - auto& sn = sourceNode.mOutputs[sourcePin]; - if (!sn.IsConnected()) return false; - - auto& conn = mConnections[sn.Connection]; - auto& dn = mNodes[conn.DestinationNode]->mInputs[conn.DestinationPin]; - - sn.Connection = WorkflowConnection::kInvalidId; - dn.Connection = WorkflowConnection::kInvalidId; - conn = {}; - - mDepthsDirty = true; - return true; -} - -bool Workflow::DisconnectByDestination(WorkflowNode& destinationNode, uint32_t destinationPin) -{ - auto& dn = destinationNode.mOutputs[destinationPin]; - if (!dn.IsConnected()) return false; - - auto& conn = mConnections[dn.Connection]; - auto& sn = mNodes[conn.SourceNode]->mInputs[conn.SourcePin]; - - sn.Connection = WorkflowConnection::kInvalidId; - dn.Connection = WorkflowConnection::kInvalidId; - conn = {}; - - mDepthsDirty = true; - return true; -} - -Workflow::GraphUpdateResult Workflow::UpdateGraph(GraphUpdateDetails* details) -{ - if (!mDepthsDirty) { - return GUR_NoWorkToDo; - } - - // Terminology: - // - Dependency = nodes its input pins are connected to - // - Dependents = nodes its output pins are connected to - - struct WorkingNode - { - // The max depth out of all dependency nodes, maintained during the traversal and committed as the actual depth - // when all dependencies of this node has been resolved. Add 1 to get the depth that will be assigned to the node. - int MaximumDepth = 0; - int FulfilledInputCount = 0; - }; - - std::vector<WorkingNode> workingNodes; - std::queue<uint32_t> q; - - // Check if all dependencies of this node is satisfied - auto CheckNodeDependencies = [&](WorkflowNode& node) -> bool { - for (auto& pin : node.mInputs) { - if (!pin.IsConnected()) { - return false; - } - } - return true; - }; - - workingNodes.reserve(mNodes.size()); - { - std::vector<uint32_t> unsatisfiedNodes; - for (uint32_t i = 0; i < mNodes.size(); ++i) { - auto& node = mNodes[i]; - workingNodes.push_back(WorkingNode{}); - - if (!node) continue; - - if (!CheckNodeDependencies(*node)) { - unsatisfiedNodes.push_back(i); - } - - node->mDepth = -1; - - // Start traversing with the input nodes - if (node->GetType() == WorkflowNode::InputType) { - q.push(i); - } - } - - if (!unsatisfiedNodes.empty()) { - if (details) { - details->emplace<decltype(unsatisfiedNodes)>(std::move(unsatisfiedNodes)); - } - return GUR_UnsatisfiedDependencies; - } - } - - auto ProcessNode = [&](WorkflowNode& node) -> void { - for (auto& pin : node.mOutputs) { - if (!pin.IsConnected()) continue; - auto& conn = mConnections[pin.Connection]; - - auto& wn = workingNodes[conn.DestinationNode]; - auto& n = *mNodes[conn.DestinationPin].get(); - - wn.FulfilledInputCount++; - wn.MaximumDepth = std::max(node.mDepth, wn.MaximumDepth); - - // Node's dependency is fulfilled, we can process its dependents next - // We use >= here because for a many-to-one pin, the dependency is an "or" relation ship, i.e. any of the nodes firing before this will fulfill the requirement - if (n.mInputs.size() >= wn.FulfilledInputCount) { - n.mDepth = wn.MaximumDepth + 1; - } - } - }; - - int processedNodes = 0; - while (!q.empty()) { - auto& wn = workingNodes[q.front()]; - auto& n = *mNodes[q.front()]; - q.pop(); - processedNodes++; - - ProcessNode(n); - } - - if (processedNodes < mNodes.size()) { - // There is unreachable nodes, collect them and report to the caller - - std::vector<uint32_t> unreachableNodes; - for (uint32_t i = 0; i < mNodes.size(); ++i) { - auto& wn = workingNodes[i]; - auto& n = *mNodes[i]; - - // This is a reachable node - if (n.mDepth != -1) continue; - - unreachableNodes.push_back(i); - } - - if (details) { - details->emplace<decltype(unreachableNodes)>(std::move(unreachableNodes)); - } - return GUR_UnreachableNodes; - } - - return GUR_Success; -} - -class Workflow::Private -{ -public: - template <class TSelf, class TProxy> - static void OperateStream(TSelf& self, TProxy& proxy) - { - // TODO - } -}; - -void Workflow::ReadFromDataStream(InputDataStream& stream) -{ - Private::OperateStream(*this, stream); -} - -void Workflow::WriteToDataStream(OutputDataStream& stream) const -{ - Private::OperateStream(*this, stream); -} - -std::pair<WorkflowConnection&, uint32_t> Workflow::AllocWorkflowConnection() -{ - for (size_t idx = 0; idx < mConnections.size(); ++idx) { - auto& elm = mConnections[idx]; - if (!elm.IsValid()) { - return { elm, (uint32_t)idx }; - } - } - - auto id = (uint32_t)mConnections.size(); - auto& conn = mConnections.emplace_back(WorkflowConnection{}); - conn.Id = id; - - return { conn, id }; -} - -std::pair<std::unique_ptr<WorkflowNode>&, uint32_t> Workflow::AllocWorkflowStep() -{ - for (size_t idx = 0; idx < mNodes.size(); ++idx) { - auto& elm = mNodes[idx]; - if (elm == nullptr) { - return { elm, (uint32_t)idx }; - } - } - - auto id = (uint32_t)mNodes.size(); - auto& node = mNodes.emplace_back(std::unique_ptr<WorkflowNode>()); - - return { node, id }; -} - -void WorkflowAssetList::DiscoverFiles(const std::function<void(SavedAsset)>& callback) const -{ - auto dir = GetConnectedProject().GetWorkflowsDirectory(); - DiscoverFilesByExtension(callback, dir, ".cplt-workflow"sv); -} - -std::string WorkflowAssetList::RetrieveNameFromFile(const fs::path& file) const -{ - auto res = DataArchive::LoadFile(file); - if (!res) return ""; - auto& stream = res.value(); - - SavedAsset assetInfo; - stream.ReadObject(assetInfo); - - return assetInfo.Name; -} - -uuids::uuid WorkflowAssetList::RetrieveUuidFromFile(const fs::path& file) const -{ - return uuids::uuid::from_string(file.stem().string()); -} - -fs::path WorkflowAssetList::RetrievePathFromAsset(const SavedAsset& asset) const -{ - auto fileName = uuids::to_string(asset.Uuid); - return GetConnectedProject().GetWorkflowPath(fileName); -} - -bool WorkflowAssetList::SaveInstance(const SavedAsset& assetInfo, const Asset* asset) const -{ - auto path = RetrievePathFromAsset(assetInfo); - auto res = DataArchive::SaveFile(path); - if (!res) return false; - auto& stream = res.value(); - - stream.WriteObject(assetInfo); - // This cast is fine: calls to this class will always be wrapped in TypedAssetList<T>, which will ensure `asset` points to some Workflow - if (auto workflow = static_cast<const Workflow*>(asset)) { // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) - stream.WriteObject(*workflow); - } - - return true; -} - -static std::unique_ptr<Workflow> LoadWorkflowFromFile(const fs::path& path) -{ - auto res = DataArchive::LoadFile(path); - if (!res) return nullptr; - auto& stream = res.value(); - - // TODO this is currently unused - SavedAsset assetInfo; - stream.ReadObject(assetInfo); - - auto workflow = std::make_unique<Workflow>(); - stream.ReadObject(*workflow); - - return workflow; -} - -Workflow* WorkflowAssetList::LoadInstance(const SavedAsset& assetInfo) const -{ - return ::LoadWorkflowFromFile(RetrievePathFromAsset(assetInfo)).release(); -} - -Workflow* WorkflowAssetList::CreateInstance(const SavedAsset& assetInfo) const -{ - return new Workflow(); -} - -bool WorkflowAssetList::RenameInstanceOnDisk(const SavedAsset& assetInfo, std::string_view oldName) const -{ - auto path = RetrievePathFromAsset(assetInfo); - - auto workflow = ::LoadWorkflowFromFile(path); - if (!workflow) return false; - - SaveInstance(assetInfo, workflow.get()); - - return true; -} - -void WorkflowAssetList::DisplayAssetCreator(ListState& state) -{ - auto ValidateNewName = [&]() -> void { - if (mACNewName.empty()) { - mACNewNameError = NameSelectionError::Empty; - return; - } - - if (FindByName(mACNewName)) { - mACNewNameError = NameSelectionError::Duplicated; - return; - } - - mACNewNameError = NameSelectionError::None; - }; - - auto ShowNewNameErrors = [&]() -> void { - switch (mACNewNameError) { - case NameSelectionError::None: break; - case NameSelectionError::Duplicated: - ImGui::ErrorMessage(I18N_TEXT("Duplicate name", L10N_DUPLICATE_NAME_ERROR)); - break; - case NameSelectionError::Empty: - ImGui::ErrorMessage(I18N_TEXT("Name cannot be empty", L10N_EMPTY_NAME_ERROR)); - break; - } - }; - - auto IsInputValid = [&]() -> bool { - return mACNewNameError == NameSelectionError::None; - }; - - auto ResetState = [&]() -> void { - mACNewName.clear(); - ValidateNewName(); - }; - - if (ImGui::InputText(I18N_TEXT("Name", L10N_NAME), &mACNewName)) { - ValidateNewName(); - } - - ShowNewNameErrors(); - - if (ImGui::Button(I18N_TEXT("OK", L10N_CONFIRM), !IsInputValid())) { - ImGui::CloseCurrentPopup(); - - Create(SavedAsset{ - .Name = mACNewName, - }); - ResetState(); - } - ImGui::SameLine(); - if (ImGui::Button(I18N_TEXT("Cancel", L10N_CANCEL))) { - ImGui::CloseCurrentPopup(); - } -} - -void WorkflowAssetList::DisplayDetailsTable(ListState& state) const -{ - ImGui::BeginTable("AssetDetailsTable", 1, ImGuiTableFlags_Borders); - - ImGui::TableSetupColumn(I18N_TEXT("Name", L10N_NAME)); - ImGui::TableHeadersRow(); - - for (auto& asset : this->GetAssets()) { - ImGui::TableNextRow(); - - ImGui::TableNextColumn(); - if (ImGui::Selectable(asset.Name.c_str(), state.SelectedAsset == &asset, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_DontClosePopups)) { - state.SelectedAsset = &asset; - } - } - - ImGui::EndTable(); -} diff --git a/core/src/Model/Workflow/Workflow_RTTI.cpp b/core/src/Model/Workflow/Workflow_RTTI.cpp deleted file mode 100644 index cb66c69..0000000 --- a/core/src/Model/Workflow/Workflow_RTTI.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "Workflow.hpp" - -#include "Model/Workflow/Nodes/DocumentNodes.hpp" -#include "Model/Workflow/Nodes/NumericNodes.hpp" -#include "Model/Workflow/Nodes/TextNodes.hpp" -#include "Model/Workflow/Nodes/UserInputNodes.hpp" -#include "Utils/I18n.hpp" -#include "Utils/Macros.hpp" - -#include <memory> - -const char* WorkflowNode::FormatKind(Kind kind) -{ - switch (kind) { - case KD_NumericAddition: return I18N_TEXT("Add", L10N_WORKFLOW_ADD); - case KD_NumericSubtraction: return I18N_TEXT("Subtract", L10N_WORKFLOW_SUB); - case KD_NumericMultiplication: return I18N_TEXT("Multiply", L10N_WORKFLOW_MUL); - case KD_NumericDivision: return I18N_TEXT("Divide", L10N_WORKFLOW_DIV); - case KD_NumericExpression: return I18N_TEXT("Evaluate expression", L10N_WORKFLOW_EVAL); - case KD_TextFormatting: return I18N_TEXT("Format text", L10N_WORKFLOW_FMT); - case KD_DocumentTemplateExpansion: return I18N_TEXT("Expand template", L10N_WORKFLOW_INSTANTIATE_TEMPLATE); - case KD_FormInput: return I18N_TEXT("Form input", L10N_WORKFLOW_FORM_INPUT); - case KD_DatabaseRowsInput: return I18N_TEXT("Database input", L10N_WORKFLOW_DB_INPUT); - - case InvalidKind: break; - } - return ""; -} - -const char* WorkflowNode::FormatCategory(WorkflowNode::Category category) -{ - switch (category) { - case CG_Numeric: return I18N_TEXT("Numeric", L10N_WORKFLOW_CATEGORY_NUMERIC); - case CG_Text: return I18N_TEXT("Text", L10N_WORKFLOW_CATEGORY_TEXT); - case CG_Document: return I18N_TEXT("Document", L10N_WORKFLOW_CATEGORY_DOCUMENT); - case CG_UserInput: return I18N_TEXT("User input", L10N_WORKFLOW_CATEGORY_USER_INPUT); - case CG_SystemInput: return I18N_TEXT("System input", L10N_WORKFLOW_CATEGORY_SYS_INPUT); - case CG_Output: return I18N_TEXT("Output", L10N_WORKFLOW_CATEGORY_OUTPUT); - - case InvalidCategory: break; - } - return ""; -} - -const char* WorkflowNode::FormatType(Type type) -{ - switch (type) { - case InputType: return I18N_TEXT("Input", L10N_WORKFLOW_KIND_INPUT); - case TransformType: return I18N_TEXT("Transform", L10N_WORKFLOW_KIND_TRANSFORM); - case OutputType: return I18N_TEXT("Output", L10N_WORKFLOW_KIND_OUTPUT); - } - return ""; -} - -WorkflowNode::Category WorkflowNode::QueryCategory(Kind kind) -{ - switch (kind) { - case KD_NumericAddition: - case KD_NumericSubtraction: - case KD_NumericMultiplication: - case KD_NumericDivision: - case KD_NumericExpression: - return CG_Numeric; - case KD_TextFormatting: - return CG_Text; - case KD_DocumentTemplateExpansion: - return CG_Document; - case KD_FormInput: - case KD_DatabaseRowsInput: - return CG_UserInput; - - case InvalidKind: break; - } - return InvalidCategory; -} - -std::span<const WorkflowNode::Kind> WorkflowNode::QueryCategoryMembers(Category category) -{ - constexpr WorkflowNode::Kind kNumeric[] = { - KD_NumericAddition, - KD_NumericSubtraction, - KD_NumericMultiplication, - KD_NumericDivision, - KD_NumericExpression, - }; - - constexpr WorkflowNode::Kind kText[] = { - KD_TextFormatting, - }; - - constexpr WorkflowNode::Kind kDocument[] = { - KD_DocumentTemplateExpansion, - }; - - constexpr WorkflowNode::Kind kUserInput[] = { - KD_FormInput, - KD_DatabaseRowsInput, - }; - - // TODO remove invalid kinds after we have nodes of these categories - constexpr WorkflowNode::Kind kSystemInput[] = { - InvalidKind, - }; - - constexpr WorkflowNode::Kind kOutput[] = { - InvalidKind, - }; - - switch (category) { - case CG_Numeric: return kNumeric; - case CG_Text: return kText; - case CG_Document: return kDocument; - case CG_UserInput: return kUserInput; - case CG_SystemInput: return kSystemInput; - case CG_Output: return kOutput; - - case InvalidCategory: break; - } - return {}; -} - -std::unique_ptr<WorkflowNode> WorkflowNode::CreateByKind(WorkflowNode::Kind kind) -{ - switch (kind) { - case KD_NumericAddition: return std::make_unique<NumericOperationNode>(NumericOperationNode::Addition); - case KD_NumericSubtraction: return std::make_unique<NumericOperationNode>(NumericOperationNode::Subtraction); - case KD_NumericMultiplication: return std::make_unique<NumericOperationNode>(NumericOperationNode::Multiplication); - case KD_NumericDivision: return std::make_unique<NumericOperationNode>(NumericOperationNode::Division); - case KD_NumericExpression: return std::make_unique<NumericExpressionNode>(); - case KD_TextFormatting: return std::make_unique<TextFormatterNode>(); - case KD_DocumentTemplateExpansion: return std::make_unique<DocumentTemplateExpansionNode>(); - case KD_FormInput: return std::make_unique<FormInputNode>(); - case KD_DatabaseRowsInput: return std::make_unique<DatabaseRowsInputNode>(); - - case InvalidKind: break; - } - return nullptr; -} - -bool WorkflowNode::IsInstance(const WorkflowNode* node) -{ - return true; -} diff --git a/core/src/Model/Workflow/fwd.hpp b/core/src/Model/Workflow/fwd.hpp deleted file mode 100644 index ed39bdb..0000000 --- a/core/src/Model/Workflow/fwd.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "Model/Workflow/Nodes/fwd.hpp" -#include "Model/Workflow/Values/fwd.hpp" - -// Evaluation.hpp -class WorkflowEvaluationError; -class WorkflowEvaluationContext; - -// SavedWorkflow.hpp -class SavedWorkflowCache; -class SavedWorkflow; - -// Value.hpp -class BaseValue; -class BaseObjectValue; - -// Workflow.hpp -class WorkflowConnection; -class WorkflowNode; -class Workflow; -class WorkflowAssetList; |