From f7e7302f4439a873d88bf4fa5d8b7389af5542db Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 10 Jul 2024 23:21:02 +0200 Subject: [PATCH] Add logic operation node (#2990) --- .../utility/math/logic_operation.py | 112 ++++++++++++++++++ .../components/PaneNodeSearchMenu.tsx | 7 +- 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 backend/src/packages/chaiNNer_standard/utility/math/logic_operation.py diff --git a/backend/src/packages/chaiNNer_standard/utility/math/logic_operation.py b/backend/src/packages/chaiNNer_standard/utility/math/logic_operation.py new file mode 100644 index 000000000..4aed4c09e --- /dev/null +++ b/backend/src/packages/chaiNNer_standard/utility/math/logic_operation.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +from enum import Enum + +from api import Lazy, SpecialSuggestion +from nodes.groups import if_enum_group +from nodes.properties.inputs import BoolInput, EnumInput +from nodes.properties.outputs import BoolOutput + +from .. import math_group + + +class LogicOperation(Enum): + AND = "and" + OR = "or" + XOR = "xor" + NOT = "not" + + +OP_LABEL: dict[LogicOperation, str] = { + LogicOperation.AND: "AND: a & b", + LogicOperation.OR: "OR: a | b", + LogicOperation.XOR: "XOR: a ^ b", + LogicOperation.NOT: "NOT: !a", +} + + +@math_group.register( + schema_id="chainner:utility:logic_operation", + name="Logic Operation", + description="Perform logic operations on conditions.", + see_also=[ + "chainner:utility:conditional", + ], + icon="MdCalculate", + inputs=[ + EnumInput( + LogicOperation, + "Logic Operation", + option_labels=OP_LABEL, + label_style="hidden", + ).with_id(0), + BoolInput("A", has_handle=True).with_id(1), + if_enum_group(0, (LogicOperation.AND, LogicOperation.OR, LogicOperation.XOR))( + BoolInput("B", has_handle=True).with_id(2).make_lazy(), + ), + ], + outputs=[ + BoolOutput( + label="Result", + output_type=""" + let a = Input1; + let b = Input2; + + match Input0 { + LogicOperation::And => a and b, + LogicOperation::Or => a or b, + LogicOperation::Xor => a != b, + LogicOperation::Not => not a, + } + """, + ) + .suggest() + .as_passthrough_of(1), + ], + suggestions=[ + SpecialSuggestion( + "AND", + name="Logic Operation: AND", + inputs={0: LogicOperation.AND}, + ), + SpecialSuggestion( + "&", + name="Logic Operation: AND", + inputs={0: LogicOperation.AND}, + ), + SpecialSuggestion( + "OR", + name="Logic Operation: OR", + inputs={0: LogicOperation.OR}, + ), + SpecialSuggestion( + "|", + name="Logic Operation: OR", + inputs={0: LogicOperation.OR}, + ), + SpecialSuggestion( + "XOR", + name="Logic Operation: XOR", + inputs={0: LogicOperation.XOR}, + ), + SpecialSuggestion( + "NOT", + name="Logic Operation: NOT", + inputs={0: LogicOperation.NOT}, + ), + SpecialSuggestion( + "!", + name="Logic Operation: NOT", + inputs={0: LogicOperation.NOT}, + ), + ], +) +def logic_operation_node(op: LogicOperation, a: bool, b: Lazy[bool]) -> bool: + if op == LogicOperation.AND: + return a and b.value + if op == LogicOperation.OR: + return a or b.value + if op == LogicOperation.XOR: + return a != b.value + if op == LogicOperation.NOT: + return not a diff --git a/src/renderer/components/PaneNodeSearchMenu.tsx b/src/renderer/components/PaneNodeSearchMenu.tsx index 7f82635a6..86f7c4f3b 100644 --- a/src/renderer/components/PaneNodeSearchMenu.tsx +++ b/src/renderer/components/PaneNodeSearchMenu.tsx @@ -226,11 +226,16 @@ function* getSpecialSuggestions( schemata: readonly NodeSchema[], searchQuery: string ): Iterable { + const equalIgnoreCase = (a: string, b: string) => { + // the length check isn't 100% correct, but it's good enough for our mostly-ASCII suggestions + return a.length === b.length && a.toLowerCase() === b.toLowerCase(); + }; + const parse = ( s: SpecialSuggestion, schema: NodeSchema ): { inputs: Partial } | undefined => { - if (searchQuery === s.query) { + if (equalIgnoreCase(searchQuery, s.query)) { return { inputs: s.inputs }; } if (s.parseInput != null && searchQuery.startsWith(s.query)) {