From 7fe47a9d5b1727a61dc724523b530762f6d6ba19 Mon Sep 17 00:00:00 2001 From: rtk0c Date: Thu, 30 Jun 2022 21:38:53 -0700 Subject: Restructure project --- app/source/Cplt/Model/Workflow/Nodes/TextNodes.cpp | 231 +++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 app/source/Cplt/Model/Workflow/Nodes/TextNodes.cpp (limited to 'app/source/Cplt/Model/Workflow/Nodes/TextNodes.cpp') diff --git a/app/source/Cplt/Model/Workflow/Nodes/TextNodes.cpp b/app/source/Cplt/Model/Workflow/Nodes/TextNodes.cpp new file mode 100644 index 0000000..9b31f7a --- /dev/null +++ b/app/source/Cplt/Model/Workflow/Nodes/TextNodes.cpp @@ -0,0 +1,231 @@ +#include "TextNodes.hpp" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class TextFormatterNode::Impl +{ +public: + template + static void ForArguments(std::vector::iterator begin, std::vector::iterator end, const TFunction& func) + { + for (auto it = begin; it != end; ++it) { + auto& elm = *it; + if (auto arg = std::get_if(&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& vec, int elmIdx) + { + for (int i = elmIdx; i >= 0; --i) { + auto& elm = vec[i]; + if (auto arg = std::get_if(&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(&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(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(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(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(&elm)) { + RemoveInputPin(arg->PinIdx); + Impl::ForArguments( + mElements.begin() + idx + 1, + mElements.end(), + [&](Argument& arg) { + arg.PinIdx--; + }); + } +} -- cgit v1.2.3-70-g09d2