diff --git a/src/App.css b/src/App.css index a241d03..8e078f6 100644 --- a/src/App.css +++ b/src/App.css @@ -248,3 +248,11 @@ button.no-button { text-decoration: underline; } } + +.flex-center-x { + display: flex; + justify-content: center; /* horizontal centering */ + text-align: center; /* center multi-line text */ + width: 100%; /* allow it to stretch */ + flex-wrap: wrap; /* optional: let text wrap naturally */ +} \ No newline at end of file diff --git a/src/pages/VisProgPage/VisProg.module.css b/src/pages/VisProgPage/VisProg.module.css index 5f2aa78..14619c5 100644 --- a/src/pages/VisProgPage/VisProg.module.css +++ b/src/pages/VisProgPage/VisProg.module.css @@ -71,6 +71,11 @@ filter: drop-shadow(0 0 0.25rem red); } +.node-basic_belief { + outline: plum solid 2pt; + filter: drop-shadow(0 0 0.25rem plum); +} + .draggable-node { padding: 3px 10px; background-color: canvas; @@ -126,3 +131,11 @@ outline: red solid 2pt; filter: drop-shadow(0 0 0.25rem red); } + +.draggable-node-basic_belief { + padding: 3px 10px; + background-color: canvas; + border-radius: 5pt; + outline: plum solid 2pt; + filter: drop-shadow(0 0 0.25rem plum); +} \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/NodeRegistry.ts b/src/pages/VisProgPage/visualProgrammingUI/NodeRegistry.ts index 8812434..04dabf1 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/NodeRegistry.ts +++ b/src/pages/VisProgPage/visualProgrammingUI/NodeRegistry.ts @@ -10,6 +10,8 @@ import GoalNode, { GoalConnects, GoalReduce } from "./nodes/GoalNode"; import { GoalNodeDefaults } from "./nodes/GoalNode.default"; import TriggerNode, { TriggerConnects, TriggerReduce } from "./nodes/TriggerNode"; import { TriggerNodeDefaults } from "./nodes/TriggerNode.default"; +import BasicBeliefNode, { BasicBeliefConnects, BasicBeliefReduce } from "./nodes/BasicBeliefNode"; +import { BasicBeliefNodeDefaults } from "./nodes/BasicBeliefNode.default"; /** * Registered node types in the visual programming system. @@ -24,6 +26,7 @@ export const NodeTypes = { norm: NormNode, goal: GoalNode, trigger: TriggerNode, + basic_belief: BasicBeliefNode, }; /** @@ -38,6 +41,7 @@ export const NodeDefaults = { norm: NormNodeDefaults, goal: GoalNodeDefaults, trigger: TriggerNodeDefaults, + basic_belief: BasicBeliefNodeDefaults, }; @@ -54,6 +58,7 @@ export const NodeReduces = { norm: NormReduce, goal: GoalReduce, trigger: TriggerReduce, + basic_belief: BasicBeliefReduce, } @@ -69,6 +74,7 @@ export const NodeConnects = { norm: NormConnects, goal: GoalConnects, trigger: TriggerConnects, + basic_belief: BasicBeliefConnects, } /** @@ -79,7 +85,6 @@ export const NodeConnects = { export const NodeDeletes = { start: () => false, end: () => false, - test: () => false, // Used for coverage of universal/ undefined nodes } /** @@ -92,5 +97,5 @@ export const NodesInPhase = { start: () => false, end: () => false, phase: () => false, - test: () => false, // Used for coverage of universal/ undefined nodes + // basic_belief: () => false, } \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.default.ts b/src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.default.ts new file mode 100644 index 0000000..72066c4 --- /dev/null +++ b/src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.default.ts @@ -0,0 +1,12 @@ +import type { BasicBeliefNodeData } from "./BasicBeliefNode"; + + +/** + * Default data for this node + */ +export const BasicBeliefNodeDefaults: BasicBeliefNodeData = { + label: "Belief", + droppable: true, + belief: {type: "keyword", id: "help", value: "help", label: "Keyword said:"}, + hasReduce: true, +}; \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.tsx b/src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.tsx new file mode 100644 index 0000000..317a1eb --- /dev/null +++ b/src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.tsx @@ -0,0 +1,174 @@ +import { + Handle, + type NodeProps, + Position, + type Connection, + type Edge, + type Node, +} from '@xyflow/react'; +import { Toolbar } from '../components/NodeComponents'; +import styles from '../../VisProg.module.css'; +import useFlowStore from '../VisProgStores'; +import { TextField } from '../../../../components/TextField'; + +/** + * The default data structure for a BasicBelief node + * + * Represents configuration for a node that activates when a specific condition is met, + * such as keywords being spoken or emotions detected. + * + * @property label: the display label of this BasicBelief node. + * @property droppable: Whether this node can be dropped from the toolbar (default: true). + * @property BasicBeliefType - The type of BasicBelief ("keywords" or a custom string). + * @property BasicBeliefs - The list of keyword BasicBeliefs (if applicable). + * @property hasReduce - Whether this node supports reduction logic. + */ +export type BasicBeliefNodeData = { + label: string; + droppable: boolean; + belief: BasicBeliefType; + hasReduce: boolean; +}; + +// These are all the types a basic belief could be. +type BasicBeliefType = Keyword | Semantic | Object | Emotion +type Keyword = { type: "keyword", id: string, value: string, label: "Keyword said:"}; +type Semantic = { type: "semantic", id: string, value: string, label: "Detected with LLM:"}; +type Object = { type: "object", id: string, value: string, label: "Object found:"}; +type Emotion = { type: "emotion", id: string, value: string, label: "Emotion recognised:"}; + +export type BasicBeliefNode = Node + + +/** + * Determines whether a BasicBelief node can connect to another node or edge. + * + * @param connection - The connection or edge being attempted to connect towards. + * @returns `true` if the connection is defined; otherwise, `false`. + */ +export function BasicBeliefNodeCanConnect(connection: Connection | Edge): boolean { + return (connection != undefined); +} + +/** + * Defines how a BasicBelief node should be rendered + * @param props - Node properties provided by React Flow, including `id` and `data`. + * @returns The rendered BasicBeliefNode React element (React.JSX.Element). + */ +export default function BasicBeliefNode(props: NodeProps) { + const data = props.data; + const {updateNodeData} = useFlowStore(); + const updateValue = (value: string) => updateNodeData(props.id, {...data, belief: {...data.belief, value: value}}); + const label_input_id = `basic_belief_${props.id}_label_input`; + + type BeliefString = BasicBeliefType["type"]; + + function updateBeliefType(newType: BeliefString) { + updateNodeData(props.id, { + ...data, + belief: { + ...data.belief, + type: newType, + }, + }); + } + + + // Use this + const emotionOptions = ["Happy", "Angry", "Sad", "Cheerful"] + + + let placeholder = "" + let wrapping = "" + switch (props.data.belief.type) { + case ("keyword"): + placeholder = "keyword..." + wrapping = '"' + break; + case ("semantic"): + placeholder = "word..." + wrapping = '"' + break; + case ("object"): + placeholder = "object..." + break; + case ("emotion"): + // TODO: emotion should probably be a drop-down menu rather than a string + // So this placeholder won't hold for always + placeholder = "emotion..." + break; + default: + break; + } + + return ( + <> + +
+
+ +
+
+ + {wrapping} + + {data.belief.type === "emotion" && ( + + )} + + + {data.belief.type !== "emotion" && + ()} + {wrapping} +
+ +
+ + ); +}; + +/** + * Reduces each BasicBelief, including its children down into its core data. + * @param node - The BasicBelief node to reduce. + * @param _nodes - The list of all nodes in the current flow graph. + * @returns A simplified object containing the node label and its list of BasicBeliefs. + */ +export function BasicBeliefReduce(node: BasicBeliefNode, _nodes: Node[]) { + const data = node.data; + return { + id: node.id, + type: data.belief.type, + value: data.belief.value + } +} + +/** + * This function is called whenever a connection is made with this node type (BasicBelief) + * @param _thisNode the node of this node type which function is called + * @param _otherNode the other node which was part of the connection + * @param _isThisSource whether this instance of the node was the source in the connection, true = yes. + */ +export function BasicBeliefConnects(_thisNode: Node, _otherNode: Node, _isThisSource: boolean) { +} \ No newline at end of file