feat: a backwards wire re-sorts the graph instead of being refused

The evaluator walks the node list in order, which used to make the order the
user's problem -- an input of an earlier node was not even drawn as
connectable. `math_connect()` runs Kahn's algorithm over the trial edge set,
with ties broken by the current index so a graph already in order is not
permuted, and remaps every index the dialog holds in one block. A self wire
and a cycle are refused with a message and change nothing.
This commit is contained in:
Martino Ferrari committed 2026-10-07 02:14:10 +02:00
1 parent 4c726adb54
commit 5ca762031d
3 files changed
+169 -8

No files matched your search

+9 -4
View File
@@ -215,15 +215,15 @@ double math_step(const MathChannel& channel, MathRuntime& rt, const float* value
return rts[static_cast<std::size_t>(out)].value;
}
bool math_channel_valid(const MathChannel& channel, std::string* why) {
const std::size_t n = channel.nodes.size();
bool math_channel_valid_nodes(const std::vector<MathNode>& nodes, int output, std::string* why) {
const std::size_t n = nodes.size();
const auto fail = [&](const std::string& text) {
if (why != nullptr) *why = text;
return false;
};
if (n == 0) return fail("empty graph");
for (std::size_t i = 0; i < n; ++i) {
const MathNode& node = channel.nodes[i];
const MathNode& node = nodes[i];
if (node.op == MathOp::Source && node.source.empty()) {
return fail("node " + std::to_string(i + 1) + ": no channel chosen");
}
@@ -238,10 +238,15 @@ bool math_channel_valid(const MathChannel& channel, std::string* why) {
}
}
}
if (channel.output < 0 || static_cast<std::size_t>(channel.output) >= n) {
if (output < 0 || static_cast<std::size_t>(output) >= n) {
return fail("no output chosen");
}
if (why != nullptr) why->clear();
return true;
}
bool math_channel_valid(const MathChannel& channel, std::string* why) {
return math_channel_valid_nodes(channel.nodes, channel.output, why);
}
} // namespace udpscope