*/}}
Browse Source

Node category stuff and minor fixes

Yiming Wu 2 years ago
parent
commit
a4bcef2684

+ 1 - 1
source/lagui/la_data.c

@@ -3877,7 +3877,7 @@ int la_AddStringDBProp(laDBInst* dbi, laDBProp* dbp, laDiff* diff, laPropPack *p
 }
 int la_AddEnumDBProp(laDBInst* dbi, laDBProp* dbp, laDiff* diff, laPropPack *pp){
     laProp *p = pp->LastPs->p; laEnumItem **Data=0; int len = laGetArrayLength(pp); int ret=0;
-    Data= memAcquireSimple(sizeof(laEnumItem*)*len); 
+    Data= memAcquireSimple(sizeof(laEnumItem*)*len); printf("len %s %d\n",p->Identifier,len);
     laGetEnumArray(pp, Data); if(diff&&dbp){
         if(memcmp(dbp->Data, Data, sizeof(laEnumItem*)*len)){ la_GiveDiffCommand(diff, dbi, p, dbp->Data); dbp->Data=Data; ret=1; } else memFree(Data);
     }else laAddDBProp(dbi, p, Data);

+ 30 - 15
source/lagui/la_interface.h

@@ -220,6 +220,7 @@ STRUCTURE(laNodeInSocket){
 
 NEED_STRUCTURE(laBaseNodeType);
 NEED_STRUCTURE(laRackPage);
+NEED_STRUCTURE(laNodeCategory);
 
 STRUCTURE(laRackPageCollection){
     laRackPage* CurrentPage;
@@ -405,6 +406,9 @@ STRUCTURE(LA){
 
     laRackPageCollection* InputMapping;
     laRackPageCollection* Drivers;
+    laListHandle NodeCategories;
+    laNodeCategory* CurrentNodeCategory;
+    int FilterNodeCategory;
 
     laBaseNodeType** NodeTypes; int NodeTypeNext, NodeTypeMax;
     laUiDefineFunc ExtraAddInputNodes;
@@ -1220,19 +1224,19 @@ int la_RunDrivers();
 laBaseNode* la_CreateDriverNode(laNodeRack* ir, laBaseNodeType* NodeType);
 laBaseNode* la_CreateInputMapperNode(laNodeRack* ir, laBaseNodeType* NodeType);
 
-#define LA_NODE_CATEGORY_INPUT (1<<0)
-#define LA_NODE_CATEGORY_DRIVER (1<<1)
-
 laPropContainer* laget_BaseNodeType(laBaseNode* bn);
-void laRegisterNode(laBaseNodeType* type, laPropContainer* pc, laBaseNodeInitF init, laBaseNodeDestroyF destroy, laBaseNodeVisitF visit, laBaseNodeEvalF eval, int nodesize, char* udf_string);
-void laSetExtraNodeFunctions(laUiDefineFunc AddInputNodes, laUiDefineFunc AddDriverNodes, laGetBaseNodeTypeF GetInputNodeType, laGetBaseNodeTypeF GetDriverNodeType);
+void laRegisterNode(laBaseNodeType* type, laPropContainer* pc,
+                    laBaseNodeInitF init, laBaseNodeDestroyF destroy, laBaseNodeVisitF visit, laBaseNodeEvalF eval,
+                    int nodesize, char* udf_string, char* type_string, char* UiText, int icon);
+
+void latouched_NodeInSocket(void* unused, int hint);
 
 #define LA_BASE_NODE_HEADER(uil,c,This)\
     {laSplitColumn(uil,c,0.2);laColumn*c1=laLeftColumn(c,1);c=laRightColumn(c,0);\
     laShowHeightAdjuster(uil,c1,This,"base.__gap",0);}
 
-#define LA_IDN_REGISTER(a,pc,init,destroy,visit,eval,type)\
-    laRegisterNode(&a,pc,init,destroy,visit,eval,sizeof(type),"UDFRES_" #type);
+#define LA_IDN_REGISTER(uitext,icon,a,pc,init,destroy,visit,eval,type)\
+    laRegisterNode(&a,pc,init,destroy,visit,eval,sizeof(type),"UDFRES_" #type, #type, uitext,icon);
 
 #define LA_SRC_AND_PARENT(socket)\
     ((socket)->Source && (socket)->Source->Parent)
@@ -1258,6 +1262,11 @@ extern laBaseNodeType LA_IDN_MATH;
 extern laBaseNodeType TNS_IDN_TRANSFORM;
 extern laBaseNodeType TNS_IDN_MAKE_TRANSFORM;
 
+extern laNodeCategory* LA_NODE_CATEGORY_INPUT;
+extern laNodeCategory* LA_NODE_CATEGORY_MATH;
+extern laNodeCategory* LA_NODE_CATEGORY_ROUTE;
+extern laNodeCategory* LA_NODE_CATEGORY_DRIVER;
+
 #define LA_VALUES_NODE_FLOAT 0
 #define LA_VALUES_NODE_INT 1
 #define LA_VALUES_NODE_ENUM 2
@@ -1284,13 +1293,9 @@ STRUCTURE(laRackPage){
     laSafeString* Name;
     laListHandle Racks;
 };
-STRUCTURE(laDriverRack){
-    laListItem Item;
-    laSafeString* Name;
-    laListHandle Nodes;
-};
-#define LA_RACK_TYPE_INPUT 0
-#define LA_RACK_TYPE_DRIVER 1
+#define LA_RACK_TYPE_INPUT (1<<0)
+#define LA_RACK_TYPE_DRIVER (1<<1)
+#define LA_RACK_TYPE_ALL (LA_RACK_TYPE_DRIVER|LA_RACK_TYPE_INPUT)
 STRUCTURE(laNodeRack){
     laListItem Item;
     laSafeString* Name;
@@ -1368,6 +1373,14 @@ STRUCTURE(laMathNode){
     int Operation;
 };
 
+STRUCTURE(laNodeCategory){
+    laListItem Item;
+    laSafeString* Name;
+    laListHandle NodeTypes;//lip
+    laUiDefineFunc Ui;
+    int For;
+};
+
 #define LA_INPUT_CONTROLLER_NODE_MODE_BTN 0
 #define LA_INPUT_CONTROLLER_NODE_MODE_AXIS 1
 
@@ -1432,6 +1445,7 @@ void laui_FileBrowserFileList(laUiList *uil, laPropPack *THIS_UNUSED, laPropPack
 void laui_DataRestorePage(laUiList *uil, laPropPack *THIS_UNUSED, laPropPack *Operator, laColumn *UNUSED, int context);
 void laui_ResourceFolderItem(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
 void laui_LogItem(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+void laui_NodeCategory(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context);
 
 int OPINV_UiItem(laOperator *a, laEvent *e);
 int OPEXT_UiItem(laOperator *a, int ExitCode);
@@ -1735,7 +1749,8 @@ laNodeOutSocket* laCreateOutSocket(void* NodeParentOptional, char* label, int Da
 laNodeInSocket* laCreateInSocket(char* label, int DataType);
 void laDestroyInSocket(laNodeInSocket* s);
 void laDestroyOutSocket(laNodeOutSocket* s);
-
+laNodeCategory* laAddNodeCategory(char* Name,laUiDefineFunc* Ui,int ForRackTypes);
+void laNodeCategoryAddNodeTypes(laNodeCategory* nc, ...);
 
 void laFreeKeyMapItem(laKeyMapItem* kmi);
 laKeyMapItem *laAssignNewKey(laKeyMapper *km, char *Path, char *Operation, char SelectBase, int SpecialKeyBits, int EventType, int Key, char *ExtraInstructions);

+ 5 - 24
source/lagui/la_kernel.c

@@ -4394,8 +4394,8 @@ int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast
                     ui->TB = (ui->Page->HeightCoeff > 0 ? ui->TU + ui->Page->HeightCoeff * LA_RH :
                             (ui->Page->HeightCoeff < 0 ? B + (ui->Page->HeightCoeff+1) * LA_RH : SubB)) + bt->BM;
                     int subh = ui->TB-ui->TU-LA_RH-bt->TM-bt->BM;
-                    if((ui->Page->TR>ui->TR-bt->RM && (!ui->Page->ScrollerShownH)) ||
-                        (ui->Page->TR<=ui->TR-bt->RM  && ui->Page->ScrollerShownH)){
+                    if((ui->Page->TR>ui->TR-(NoDecal?0:bt->RM) && (!ui->Page->ScrollerShownH)) ||
+                        (ui->Page->TR<=ui->TR-(NoDecal?0:bt->RM)  && ui->Page->ScrollerShownH)){
                         ui->Page->ScrollerShownH=!ui->Page->ScrollerShownH;
                     }
                     if(ui->Page->AllowScale){ui->Page->ScrollerShownH=1;}
@@ -4869,14 +4869,14 @@ int la_DrawUiListRecursive(laUiListDraw *uild, laUiList *uil, int L, int R, int
                 ui->Type == _LA_UI_COLLECTION_SINGLE ||
                 ui->Type == _LA_UI_COLLECTION_SELECTOR && (ui->Subs.pFirst || ui->Page)){
                 if (!ui->Page){ ui = ui->Item.pNext; continue; }
-                tnsFlush(); int DoNodes=RegisterNodes;
+                tnsFlush(); int DoNodes=RegisterNodes; int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
                 if(ui->Flags&LA_UI_FLAGS_NODE_CONTAINER){ la_InitSocketRecord(uild, ui->Page); DoNodes=1; }
-                Ret += la_DrawUiListRecursive(uild, ui->Page, ui->L+bt->LM, ui->R-bt->RM, U, B,
+                Ret += la_DrawUiListRecursive(uild, ui->Page, ui->L+(NoDecal?0:bt->LM), ui->R-(NoDecal?0:bt->RM), U, B,
                     (ui->Page->HeightCoeff ? ui->B - ui->Page->U : 10000), ConditionStackLevel, GlobalX, GlobalY, DoNodes);
                 if (ui->Page->ScrollerShownH){ la_DrawUiListScrollerH(ui->Page, ui->Page->PanX,
                     ui->Page->R-ui->Page->L-bt->RM-bt->LM, ui->R-ui->Page->L-bt->RM-bt->LM-(ui->Page->ScrollerShownV?LA_SCROLL_W:0),ui->B); }
                 if (ui->Page->HeightCoeff) la_DrawUiListScrollerV(ui->Page, ui->Page->PanY,
-                    ui->Page->B-ui->Page->U-bt->TM-bt->BM, ui->B-ui->Page->U-bt->TM-bt->BM-(ui->Page->ScrollerShownH?LA_SCROLL_W+bt->RM:0),ui->R);
+                    ui->Page->B-ui->Page->U-(NoDecal?0:bt->TM-bt->BM), ui->B-ui->Page->U-(NoDecal?0:bt->TM-bt->BM)-(ui->Page->ScrollerShownH?LA_SCROLL_W+bt->RM:0),ui->R);
                 if (ui->Page->AllowScale){ la_DrawUiListArrows(ui->Page,ui->L, ui->R, ui->Page->U, ui->B-LA_SCROLL_W-bt->BM*2, laThemeColor(bt, LA_BT_BORDER)); }
             }elif (ui->Type == _LA_UI_COLLECTION){
                 int CanGetState = laCanGetState(ui->PP.LastPs->p);
@@ -5317,25 +5317,6 @@ void la_InitLLVM(){
 
 //==================================================================================================
 
-laNodeOutSocket* laCreateOutSocket(void* NodeParentOptional, char* label, int DataType){
-    laNodeOutSocket* os=memAcquire(sizeof(laNodeOutSocket));
-    strSafeSet(&os->Label, label); os->DataType = DataType; os->Parent=NodeParentOptional;
-    return os;
-}
-laNodeInSocket* laCreateInSocket(char* label, int DataType){
-    laNodeInSocket* is=memAcquire(sizeof(laNodeInSocket));
-    strSafeSet(&is->Label, label); is->DataType = DataType;
-    return is;
-}
-void laDestroyInSocket(laNodeInSocket* s){
-    strSafeDestroy(&s->Label); memFree(s);
-}
-void laDestroyOutSocket(laNodeOutSocket* s){
-    strSafeDestroy(&s->Label); memFree(s);
-}
-
-//==================================================================================================
-
 void la_FreeKeyMapItem(laKeyMapItem* kmi){
     if(kmi->Instructions) strSafeDestroy(&kmi->Instructions);
     if(kmi->Operation) strSafeDestroy(&kmi->Operation);

+ 3 - 0
source/lagui/la_util.h

@@ -354,6 +354,9 @@ STRUCTURE(laBaseNodeType){
     laBaseNodeVisitF   Visit;
     laBaseNodeEvalF    Eval;
     laPropContainer*   pc;
+	char* TypeName;
+	char* Name;
+	int Icon;
     int NodeSize;
 };
 NEED_STRUCTURE(laNodeRack);

+ 97 - 60
source/lagui/resources/la_nodes_basic.c

@@ -26,6 +26,11 @@ laPropContainer* LA_PC_IDN_VALUES;
 laPropContainer* LA_PC_IDN_MATRIX;
 laPropContainer* LA_PC_IDN_MATH;
 
+laNodeCategory* LA_NODE_CATEGORY_INPUT;
+laNodeCategory* LA_NODE_CATEGORY_MATH;
+laNodeCategory* LA_NODE_CATEGORY_ROUTE;
+laNodeCategory* LA_NODE_CATEGORY_DRIVER;
+
 #define LA_IDN_CONTROLLER_RESET_SOCKET(ns)\
     {ns->IntVal[0]=0; ns->Out->DataType=LA_PROP_INT; ns->Offset=0; ns->Out->Data=&ns->IntVal;}
 
@@ -113,7 +118,7 @@ void IDN_InputVisualizeDestroy(laInputVisualizerNode* n){
 }
 int IDN_InputVisualizeVisit(laInputVisualizerNode* n, laListHandle* l){
     n->Base.Eval=LA_DAG_FLAG_TEMP;
-    if(n->In->Source){ laBaseNode* sn=n->In->Source->Parent;LA_VISIT_NODE(sn); }
+    if(LA_SRC_AND_PARENT(n->In)){ laBaseNode* sn=n->In->Source->Parent;LA_VISIT_NODE(sn); }
     n->Base.Eval=LA_DAG_FLAG_PERM;
     lstAppendPointer(l, n);
     return LA_DAG_FLAG_PERM;
@@ -486,10 +491,11 @@ int OPINV_RebuildInputMapping(laOperator* a, laEvent *e){
     return LA_FINISHED;
 }
 
-laBaseNode* la_CreateInputMapperNode(laNodeRack* ir, laBaseNodeType* NodeType){
+laBaseNode* la_CreateNode(laNodeRack* ir, laBaseNodeType* NodeType){
     laBaseNode* bn=memAcquire(NodeType->NodeSize);
     bn->Type=NodeType; NodeType->Init(bn); lstAppendItem(&ir->Nodes, bn); bn->InRack=ir;
-    laNotifyUsers("la.input_mapping"); laRecordAndPush(0,"la.input_mapping","Add node", 0);
+    if(ir->RackType==LA_RACK_TYPE_INPUT){ laNotifyUsers("la.input_mapping"); laRecordAndPush(0,"la.input_mapping","Add node", 0); }
+    else{ laNotifyUsers("la.drivers"); laRecordAndPush(0,"la.drivers","Add node", 0); }
     return bn;
 }
 void la_DestroyInputMapperNode(laBaseNode* bn){
@@ -498,45 +504,42 @@ void la_DestroyInputMapperNode(laBaseNode* bn){
     memFree(bn);
 }
 
-int OPINV_AddInputMapperNode(laOperator* a, laEvent *e){
+int OPINV_AddNode(laOperator* a, laEvent *e){
     laNodeRack* ir=a->This?a->This->EndInstance:0; if(!ir) return LA_CANCELED;
     laBaseNodeType* bnt=0;
+    if(!MAIN.CurrentNodeCategory) MAIN.CurrentNodeCategory=MAIN.NodeCategories.pFirst;
 
+    char* target=strGetArgumentString(a->ExtraInstructionsP,"target");
+    if(!target || strSame(target,"INPUT")){ MAIN.FilterNodeCategory=LA_RACK_TYPE_INPUT;
+        if(!(MAIN.CurrentNodeCategory->For&LA_RACK_TYPE_INPUT)) MAIN.CurrentNodeCategory=LA_NODE_CATEGORY_INPUT; }
+    else{ MAIN.FilterNodeCategory=LA_RACK_TYPE_DRIVER;
+        if(!(MAIN.CurrentNodeCategory->For&LA_RACK_TYPE_DRIVER)) MAIN.CurrentNodeCategory=LA_NODE_CATEGORY_DRIVER; }
     char* type=strGetArgumentString(a->ExtraInstructionsP,"type");
-    if(!type){ laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING; }
-    elif(strSame(type, "KEYBOARD")){}
-    elif(strSame(type, "MOUSE")){}
-    elif(strSame(type, "CONTROLLER")){ la_CreateInputMapperNode(ir, &LA_IDN_CONTROLLER); }
-    elif(strSame(type, "VISUALIZER")){ la_CreateInputMapperNode(ir, &LA_IDN_VISUALIZER); }
-    elif(strSame(type, "SPLIT")){ la_CreateInputMapperNode(ir, &LA_IDN_SPLIT); }
-    elif(strSame(type, "SWITCH")){ la_CreateInputMapperNode(ir, &LA_IDN_SWITCH); }
-    elif(strSame(type, "COMBINE")){ la_CreateInputMapperNode(ir, &LA_IDN_COMBINE); }
-    elif(strSame(type, "VALUES")){ la_CreateInputMapperNode(ir, &LA_IDN_VALUES); }
-    elif(strSame(type, "MATRIX")){ la_CreateInputMapperNode(ir, &LA_IDN_MATRIX); }
-    elif(strSame(type, "MATH")){ la_CreateInputMapperNode(ir, &LA_IDN_MATH); }
-    elif(MAIN.ExtraGetInputNodeType && (bnt=MAIN.ExtraGetInputNodeType(type))){ la_CreateInputMapperNode(ir, bnt); }
-
+    if(!type){ laEnableOperatorPanel(a,a->This,e->x-LA_RH*4,e->y-LA_RH,200,200,0,0,LA_RH*15,0,0,0,0,0,e); return LA_RUNNING; }
+    else{
+        for(int i=0;i<MAIN.NodeTypeNext;i++){
+            if(strSame(MAIN.NodeTypes[i]->TypeName,type)){ la_CreateNode(ir, MAIN.NodeTypes[i]); }
+        }
+    }
     return LA_FINISHED;
 }
-void laui_AddInputMapperNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
-    laColumn* c=laFirstColumn(uil);
-    if(MAIN.ExtraAddInputNodes){
-        MAIN.ExtraAddInputNodes(uil,This,Extra,0,0);
+int OPMOD_AddNode(laOperator* a, laEvent *e){
+    laNodeRack* r=a->This->EndInstance;
+    if(a->ConfirmData){
+        if(a->ConfirmData->StrData){
+            for(int i=0;i<MAIN.NodeTypeNext;i++){
+                if(strSame(MAIN.NodeTypes[i]->TypeName,a->ConfirmData->StrData)){ la_CreateNode(r, MAIN.NodeTypes[i]); break; }
+            }
+        }
+        return LA_FINISHED;
     }
-    laShowLabel(uil,c,"Sources:",0,0);
-    laShowItemFull(uil,c,This,"add_node_input",0,"type=KEYBOARD;text=Keyboard",0,0);
-    laShowItemFull(uil,c,This,"add_node_input",0,"type=MOUSE;text=Mouse",0,0);
-    laShowItemFull(uil,c,This,"add_node_input",0,"type=CONTROLLER;text=Controller",0,0);
-    laShowLabel(uil,c,"Operations:",0,0);
-    laShowItemFull(uil,c,This,"add_node_input",0,"type=SPLIT;text=Split",0,0);
-    laShowItemFull(uil,c,This,"add_node_input",0,"type=SWITCH;text=Switch",0,0);
-    laShowItemFull(uil,c,This,"add_node_input",0,"type=COMBINE;text=Combine",0,0);
-    laShowItemFull(uil,c,This,"add_node_input",0,"type=VALUES;text=Values",0,0);
-    laShowLabel(uil,c,"Math:",0,0);
-    laShowItemFull(uil,c,This,"add_node_input",0,"type=MATH;text=Math",0,0);
-    laShowItemFull(uil,c,This,"add_node_input",0,"type=MATRIX;text=Matrix",0,0);
-    laShowLabel(uil,c,"Visualizations:",0,0);
-    laShowItemFull(uil,c,This,"add_node_input",0,"type=VISUALIZER;text=Visualizer",0,0);
+    return LA_RUNNING;
+}
+void laui_AddNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil),*cl,*cr; laSplitColumn(uil,c,0.4); cl=laLeftColumn(c,4); cr=laRightColumn(c,0);
+    laShowItemFull(uil,cl,0,"la.node_categories",LA_WIDGET_COLLECTION,"feedback=NONE;",0,0);
+    laUiItem* g=laMakeEmptyGroup(uil,cr,"Nodes",0); laUiList* gu=g->Page; laColumn* gc=laFirstColumn(gu); g->Flags|=LA_UI_FLAGS_NO_DECAL|LA_UI_FLAGS_NO_GAP;
+    laShowItemFull(gu,gc,0,"la.node_categories",LA_WIDGET_COLLECTION_SINGLE,0,laui_NodeCategory,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
 }
 
 int OPINV_MoveNodeToRack(laOperator* a, laEvent *e){
@@ -639,9 +642,12 @@ laBoxedTheme* laget_NodeGetTheme(laNodeRack* rack_unused, laBaseNode* n){
     return 0;
 }
 
-void laRegisterNode(laBaseNodeType* type, laPropContainer* pc, laBaseNodeInitF init, laBaseNodeDestroyF destroy, laBaseNodeVisitF visit, laBaseNodeEvalF eval, int nodesize, char* udf_string){
+void laRegisterNode(laBaseNodeType* type, laPropContainer* pc,
+                    laBaseNodeInitF init, laBaseNodeDestroyF destroy, laBaseNodeVisitF visit, laBaseNodeEvalF eval,
+                    int nodesize, char* udf_string, char* type_string, char* UiText, int icon){
     arrEnsureLength(&MAIN.NodeTypes, MAIN.NodeTypeNext, &MAIN.NodeTypeMax, sizeof(laBaseNode*));
     type->Init = init; type->Destroy = destroy; type->Visit=visit; type->Eval=eval; type->NodeSize=nodesize; type->pc=pc;
+    type->TypeName=type_string;type->Name=UiText;type->Icon=icon;
     MAIN.NodeTypes[MAIN.NodeTypeNext]=type; MAIN.NodeTypeNext++;
     la_UDFAppendSharedTypePointer(udf_string, type);
 }
@@ -662,8 +668,8 @@ void la_RegisterInputMapperOperators(){
 
     laCreateOperatorType("LA_add_input_mapping_page", "Add Page", "Add a page for inpur mapping", 0,0,0,OPINV_AddInputMapperPage,0,'+',0);
     laCreateOperatorType("LA_add_rack", "Add Rack", "Add a rack for nodes", 0,0,0,OPINV_AddNodesRack,0,'+',0);
-    at=laCreateOperatorType("LA_add_input_mapper_node", "Add Node", "Add a input mapper node",0,0,0,OPINV_AddInputMapperNode,OPMOD_FinishOnData,'+',0);
-    at->UiDefine=laui_AddInputMapperNode;
+    at=laCreateOperatorType("OPINV_AddNode", "Add Node", "Add a node to the rack",0,0,0,OPINV_AddNode,OPMOD_AddNode,'+',0);
+    at->UiDefine=laui_AddNode;
     laCreateOperatorType("LA_input_mapping_rebuild", "Rebuild Input Mapping", "Rebuild input mapping for evaluation",0,0,0,OPINV_RebuildInputMapping,0,L'⭮',0);
     laCreateOperatorType("LA_move_node_to_rack", "Move Node", "Move node to another rack",0,0,0,OPINV_MoveNodeToRack,0,0,0);
     laCreateOperatorType("LA_delete_node", "Delete Node", "Delete this node",0,0,0,OPINV_DeleteNode,0,0,0);
@@ -678,8 +684,7 @@ void la_RegisterInputMapperOperators(){
     laSubGroupExtraFunctions(p,0,laget_NodeGetTheme,laget_BaseNodeGap);
     laAddSubGroup(pc,"parent_page","Parent Page","Parent page of this rack","la_rack_page",0,0,0,offsetof(laNodeRack,ParentPage),0,0,0,0,0,0,0,LA_UDF_REFER);
     laAddIntProperty(pc,"type", "Type", "Type of the rack", 0,0,0,0,0,0,0,0,offsetof(laNodeRack,RackType),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
-    laAddOperatorProperty(pc,"add_node_input","Add Node","Add a node into this rack","LA_add_input_mapper_node",'+',0);
-    laAddOperatorProperty(pc,"add_node_driver","Add Node","Add a node into this rack","LA_add_driver_node",'+',0);
+    laAddOperatorProperty(pc,"add_node","Add Node","Add a node into this rack","OPINV_AddNode",'+',0);
     laAddOperatorProperty(pc,"insert_rack","Insert Rack","Insert a rack","LA_insert_rack",'+',0);
     laAddOperatorProperty(pc,"move","Move Rack","Move this rack","LA_move_rack",0,0);
     laAddOperatorProperty(pc,"delete","Delete Rack","Delete this rack","LA_delete_rack",0,0);
@@ -708,9 +713,9 @@ void la_RegisterInputMapperOperators(){
 
     pc=laAddPropertyContainer("la_input_controller_node_socket", "Controller Socket", "One value from a controller output",0,0,sizeof(laInputControllerNodeSocket),0,0,1|LA_PROP_OTHER_ALLOC);
     laAddStringProperty(pc,"which","Which","Select which output from the controller",0,0,0,0,1,offsetof(laInputControllerNodeSocket,Which),0,0,laset_InputControllerNodeSocketWhich,0,LA_AS_IDENTIFIER);
-    laAddFloatProperty(pc,"axis", "🡘", "Axis value", LA_WIDGET_VALUE_METER,0,0,1,-1,0,0,0,offsetof(laInputControllerNodeSocket,RealVal),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
-    laAddFloatProperty(pc,"axis2d", "2D Axis", "2D Axis value", LA_WIDGET_VALUE_METER,0,0,1,-1,0,0,0,offsetof(laInputControllerNodeSocket,RealVal),0,0,2,0,0,0,0,0,0,0,LA_READ_ONLY);
-    p=laAddEnumProperty(pc,"switch", "SW", "Switch value", LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(laInputControllerNodeSocket,IntVal),0,0,0,laget_SocketEnumArrayLength,0,0,0,0,0,LA_READ_ONLY);
+    laAddFloatProperty(pc,"axis", "🡘", "Axis value", LA_WIDGET_VALUE_METER,0,0,1,-1,0,0,0,offsetof(laInputControllerNodeSocket,RealVal),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
+    laAddFloatProperty(pc,"axis2d", "2D Axis", "2D Axis value", LA_WIDGET_VALUE_METER,0,0,1,-1,0,0,0,offsetof(laInputControllerNodeSocket,RealVal),0,0,2,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
+    p=laAddEnumProperty(pc,"switch", "SW", "Switch value", LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(laInputControllerNodeSocket,IntVal),0,0,0,laget_SocketEnumArrayLength,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
     laAddEnumItemAs(p,"IDLE", "Idle", "Button is not pressed", 0, 0);
     laAddEnumItemAs(p,"ACTIVE", "Active", "Button is pressed", 1, 0);
     laAddSubGroup(pc, "out", "Out","Output value","la_out_socket",0,0,0,offsetof(laInputControllerNodeSocket,Out),0,0,0,0,0,0,0,LA_UDF_SINGLE);
@@ -719,9 +724,9 @@ void la_RegisterInputMapperOperators(){
     LA_PC_IDN_VISUALIZER=pc; laPropContainerExtraFunctions(pc,0,0,0,laui_DefaultNodeOperationsPropUiDefine);
     laAddSubGroup(pc,"base","Base","Base node","la_base_node",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
     laAddSubGroup(pc, "in", "In","Input value","la_in_socket",0,0,0,offsetof(laInputVisualizerNode,In),0,0,0,0,0,0,0,LA_UDF_SINGLE);
-    laAddFloatProperty(pc,"axis", "🡘", "Axis value", LA_WIDGET_VALUE_METER,0,0,1,-1,0,0,0,offsetof(laInputVisualizerNode,RealVal),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
-    laAddFloatProperty(pc,"axis2d", "2D Axis", "2D Axis value", LA_WIDGET_VALUE_METER_2D,0,0,1,-1,0,0,0,offsetof(laInputVisualizerNode,RealVal),0,0,2,0,0,0,0,0,0,0,LA_READ_ONLY);
-    p=laAddEnumProperty(pc,"switch", "SW", "Switch value", LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(laInputVisualizerNode,IntVal),0,0,0,laget_VisualizerArrayLength,0,0,0,0,0,LA_READ_ONLY);
+    laAddFloatProperty(pc,"axis", "🡘", "Axis value", LA_WIDGET_VALUE_METER,0,0,1,-1,0,0,0,offsetof(laInputVisualizerNode,RealVal),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
+    laAddFloatProperty(pc,"axis2d", "2D Axis", "2D Axis value", LA_WIDGET_VALUE_METER_2D,0,0,1,-1,0,0,0,offsetof(laInputVisualizerNode,RealVal),0,0,2,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
+    p=laAddEnumProperty(pc,"switch", "SW", "Switch value", LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(laInputVisualizerNode,IntVal),0,0,0,laget_VisualizerArrayLength,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
     laAddEnumItemAs(p,"IDLE", "Idle", "Button is not pressed", 0, 0);
     laAddEnumItemAs(p,"ACTIVE", "Active", "Button is pressed", 1, 0);
 
@@ -853,23 +858,25 @@ void la_RegisterInputMapperOperators(){
     laAddEnumItemAs(p,"ATAN", "Arctangent", "atan(L)", LA_MATH_NODE_OP_ATAN, 0);
     laAddEnumItemAs(p,"ATAN2", "Atan2", "atan2(L,R) where L or R can be zero", LA_MATH_NODE_OP_ATAN2, 0);
 
-    LA_IDN_REGISTER(LA_IDN_CONTROLLER,LA_PC_IDN_CONTROLLER, IDN_ControllerInit, IDN_ControllerDestroy, IDN_ControllerVisit, IDN_ControllerEval, laInputControllerNode);
-    LA_IDN_REGISTER(LA_IDN_VISUALIZER,LA_PC_IDN_VISUALIZER, IDN_InputVisualizeInit, IDN_InputVisualizeDestroy, IDN_InputVisualizeVisit, IDN_InputVisualizerEval, laInputVisualizerNode);
-    LA_IDN_REGISTER(LA_IDN_SPLIT,LA_PC_IDN_SPLIT, IDN_SplitInit, IDN_SplitDestroy, IDN_SplitVisit, IDN_SplitEval, laSplitNode);
-    LA_IDN_REGISTER(LA_IDN_SWITCH,LA_PC_IDN_SWITCH, IDN_SwitchInit, IDN_SwitchDestroy, IDN_SwitchVisit, IDN_SwitchEval, laSwitchNode);
-    LA_IDN_REGISTER(LA_IDN_COMBINE,LA_PC_IDN_COMBINE, IDN_CombineInit, IDN_CombineDestroy, IDN_CombineVisit, IDN_CombineEval, laCombineNode);
-    LA_IDN_REGISTER(LA_IDN_VALUES,LA_PC_IDN_VALUES, IDN_ValuesInit, IDN_ValuesDestroy, IDN_ValuesVisit, IDN_ValuesEval, laValuesNode);
-    LA_IDN_REGISTER(LA_IDN_MATRIX,LA_PC_IDN_MATRIX, IDN_MatrixInit, IDN_MatrixDestroy, IDN_MatrixVisit, IDN_MatrixEval, laMatrixNode);
-    LA_IDN_REGISTER(LA_IDN_MATH,LA_PC_IDN_MATH, IDN_MathInit, IDN_MathDestroy, IDN_MathVisit, IDN_MathEval, laMathNode);
+    LA_IDN_REGISTER("Controller",L'🕹',LA_IDN_CONTROLLER,LA_PC_IDN_CONTROLLER, IDN_ControllerInit, IDN_ControllerDestroy, IDN_ControllerVisit, IDN_ControllerEval, laInputControllerNode);
+    LA_IDN_REGISTER("Visualizer",L'🔍',LA_IDN_VISUALIZER,LA_PC_IDN_VISUALIZER, IDN_InputVisualizeInit, IDN_InputVisualizeDestroy, IDN_InputVisualizeVisit, IDN_InputVisualizerEval, laInputVisualizerNode);
+    LA_IDN_REGISTER("Split",L'⚟',LA_IDN_SPLIT,LA_PC_IDN_SPLIT, IDN_SplitInit, IDN_SplitDestroy, IDN_SplitVisit, IDN_SplitEval, laSplitNode);
+    LA_IDN_REGISTER("Switch",L'🚦',LA_IDN_SWITCH,LA_PC_IDN_SWITCH, IDN_SwitchInit, IDN_SwitchDestroy, IDN_SwitchVisit, IDN_SwitchEval, laSwitchNode);
+    LA_IDN_REGISTER("Combine",L'⚞',LA_IDN_COMBINE,LA_PC_IDN_COMBINE, IDN_CombineInit, IDN_CombineDestroy, IDN_CombineVisit, IDN_CombineEval, laCombineNode);
+    LA_IDN_REGISTER("Values",0,LA_IDN_VALUES,LA_PC_IDN_VALUES, IDN_ValuesInit, IDN_ValuesDestroy, IDN_ValuesVisit, IDN_ValuesEval, laValuesNode);
+    LA_IDN_REGISTER("Matrix",0,LA_IDN_MATRIX,LA_PC_IDN_MATRIX, IDN_MatrixInit, IDN_MatrixDestroy, IDN_MatrixVisit, IDN_MatrixEval, laMatrixNode);
+    LA_IDN_REGISTER("Math",0,LA_IDN_MATH,LA_PC_IDN_MATH, IDN_MathInit, IDN_MathDestroy, IDN_MathVisit, IDN_MathEval, laMathNode);
 
-}
+    LA_NODE_CATEGORY_INPUT=laAddNodeCategory("Input",0,LA_RACK_TYPE_INPUT);
+    LA_NODE_CATEGORY_MATH=laAddNodeCategory("Math",0,LA_RACK_TYPE_ALL);
+    LA_NODE_CATEGORY_ROUTE=laAddNodeCategory("Route",0,LA_RACK_TYPE_ALL);
 
+    laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_INPUT, &LA_IDN_CONTROLLER,0);
+    laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_MATH, &LA_IDN_MATRIX,&LA_IDN_MATH,0);
+    laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_ROUTE, &LA_IDN_SPLIT, &LA_IDN_SWITCH, &LA_IDN_COMBINE, &LA_IDN_VALUES, &LA_IDN_VISUALIZER,0);
+}
 
 
-void laSetExtraNodeFunctions(laUiDefineFunc AddInputNodes, laUiDefineFunc AddDriverNodes, laGetBaseNodeTypeF GetInputNodeType, laGetBaseNodeTypeF GetDriverNodeType){
-    MAIN.ExtraAddInputNodes=AddInputNodes; MAIN.ExtraAddDriverNodes=AddDriverNodes;
-    MAIN.ExtraGetInputNodeType=GetInputNodeType; MAIN.ExtraGetDriverNodeType=GetDriverNodeType;
-}
 
 void laMappingRequestRebuild(){ MAIN.InputMapping->NeedRebuild=1; }
 void laMappingRequestEval(){ MAIN.InputMapping->NeedEval=1; }
@@ -895,4 +902,34 @@ int la_RebuildInputMapping(){
     }
     if(result==LA_DAG_FLAG_ERR){ while(lstPopPointer(&MAIN.InputMapping->Eval)); return LA_DAG_FLAG_ERR; }
     return LA_DAG_FLAG_PERM;
-}
+}
+
+//==================================================================================================
+
+laNodeOutSocket* laCreateOutSocket(void* NodeParentOptional, char* label, int DataType){
+    laNodeOutSocket* os=memAcquire(sizeof(laNodeOutSocket));
+    strSafeSet(&os->Label, label); os->DataType = DataType; os->Parent=NodeParentOptional;
+    return os;
+}
+laNodeInSocket* laCreateInSocket(char* label, int DataType){
+    laNodeInSocket* is=memAcquire(sizeof(laNodeInSocket));
+    strSafeSet(&is->Label, label); is->DataType = DataType;
+    return is;
+}
+void laDestroyInSocket(laNodeInSocket* s){ strSafeDestroy(&s->Label); memLeave(s); }
+void laDestroyOutSocket(laNodeOutSocket* s){ strSafeDestroy(&s->Label); memLeave(s); }
+
+laNodeCategory* laAddNodeCategory(char* Name,laUiDefineFunc* Ui,int ForRackTypes){
+    laNodeCategory* nc=memAcquire(sizeof(laNodeCategory));
+    lstAppendItem(&MAIN.NodeCategories,nc);
+    strSafeSet(&nc->Name, Name); nc->Ui=Ui;  nc->For=ForRackTypes;
+    return nc;
+}
+void laNodeCategoryAddNodeTypes(laNodeCategory* nc, ...){
+    va_list list; va_start(list,nc);
+    laBaseNodeType* nt;
+    while(nt=va_arg(list,laBaseNodeType*)){
+        lstAppendPointer(&nc->NodeTypes, nt);
+    }
+    va_end(list);
+}

+ 1 - 1
source/lagui/resources/la_operators.c

@@ -879,7 +879,7 @@ int OPMOD_NewPanel(laOperator *a, laEvent *e){
         if (!p){
             p = laCreateTopPanel(MAIN.CurrentWindow, np->SelectedTemplate->Identifier->Ptr, e->x, e->y,400,400,0,0,0,0,0,0,0,0);
         }
-        laShowPanelWithExpandEffect(p); laPopPanel(p);
+        laShowPanelWithExpandEffect(p); laPopPanel(p); free(np);
         return LA_FINISHED;
     }
 

+ 18 - 1
source/lagui/resources/la_properties.c

@@ -675,6 +675,14 @@ void lapost_DetachedProp(laProp *Prop){
     Prop->Identifier = id;
 }
 
+void latouched_NodeInSocket(void* unused, int hint){
+    laDriverRequestRebuild(); laMappingRequestRebuild();
+}
+
+int lafilter_NodeCategory(void* unused, laNodeCategory* c){
+    if(c->For&MAIN.FilterNodeCategory) return 1; return 0;
+}
+
 void tnspost_Object(tnsObject *o){
     /* what */
 }
@@ -897,7 +905,10 @@ void la_RegisterInternalProps(){
             sp=laAddSubGroup(p, "controllers", "Controllers", "Detected game controllers","la_controller",laget_ControllerType,0,0,-1,0,0,0,0,0,0,offsetof(LA,Controllers),0);
             laSubGroupDetachable(sp, laget_DetachedControllerFirst, laget_ListNext);
             LA_PROP_CONTROLLER=sp;
-            
+
+            sp=laAddSubGroup(p, "node_categories", "Node Categories", "Node categories","la_node_category",0,0,0,offsetof(LA,CurrentNodeCategory),0,0,0,0,0,0,offsetof(LA,NodeCategories),0);
+            laSubGroupExtraFunctions(sp,lafilter_NodeCategory,0,0);
+
             laAddSubGroup(p, "input_mapping", "Input Mapping", "Input mapping page collection","la_input_mapping_collection",0,0,0,offsetof(LA,InputMapping),0,0,0,0,0,0,0,LA_UDF_SINGLE);
             laAddSubGroup(p, "drivers", "Drivers", "Driver page collection","la_driver_collection",0,0,0,offsetof(LA,Drivers),0,0,0,0,0,0,0,LA_UDF_SINGLE);
 
@@ -908,6 +919,11 @@ void la_RegisterInternalProps(){
             laAddStringProperty(p, "example_string", "Example String", "Example string", 0, 0, 0, 0, 1, offsetof(LA,example_string), 0, 0, 0, 0, 0);
         }
 
+        p = laAddPropertyContainer("la_node_category", "Node Category", "Node category", 0, laui_IdentifierOnly, sizeof(laNodeCategory), 0, 0, 1);{
+            laAddStringProperty(p, "name", "Name", "Name of the page", 0, 0, 0, 0, 1, offsetof(laNodeCategory, Name), 0, 0, 0, 0, LA_AS_IDENTIFIER);
+            laAddIntProperty(p, "for_racks", "For Rack Types", "For rack types", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laNodeCategory, For), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_READ_ONLY);
+        }
+
         p = laAddPropertyContainer("la_input_mapping_collection", "Input Mapping Collection", "Input mapping collection", 0, 0, sizeof(laRackPageCollection), 0, 0, 1);{
             laAddSubGroup(p, "pages", "Pages", "Rack pages","la_rack_page",0,0,0,offsetof(laRackPageCollection,CurrentPage),0,0,0,0,0,0,offsetof(laRackPageCollection,Pages),0);
             laAddSubGroup(p, "current_page", "Current Page", "Current page","la_rack_page",0,0,0,offsetof(laRackPageCollection,CurrentPage),0,0,0,0,0,0,0,LA_UDF_REFER);
@@ -1202,6 +1218,7 @@ void la_RegisterInternalProps(){
             laAddIntProperty(p, "color_id", "Color ID", "Color ID of the source wire", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laNodeInSocket, ColorId), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0);
             laAddIntProperty(p, "array_length", "Array Length", "Array length of data", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laNodeInSocket, ArrLen), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
         } LA_PC_SOCKET_IN = p;
+        laPropContainerExtraFunctions(p,0,latouched_NodeInSocket,0,0);
 
         // PROPERTIES ==========================================================================================
 

+ 15 - 7
source/lagui/resources/la_templates.c

@@ -1133,8 +1133,7 @@ void laui_NodeRack(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn
     laShowItem(uil,c,This,"nodes")->Flags|=LA_UI_FLAGS_NO_DECAL;
     laShowLabel(uil,c,"\n",0,0);
     b=laBeginRow(uil,c,0,0);
-    if(r->RackType==LA_RACK_TYPE_INPUT){ laShowItem(uil,c,This,"add_node_input")->Expand=1; }
-    else{ laShowItem(uil,c,This,"add_node_driver")->Expand=1; }
+    laShowItemFull(uil,c,This,"add_node",0,(context==LA_RACK_TYPE_DRIVER)?"target=DRIVER;":"target=INPUT;",0,0)->Expand=1;
     laShowItem(uil,c,This,"delete")->Flags|=LA_UI_FLAGS_ICON;
     laShowItem(uil,c,This,"insert_rack");
     laEndRow(uil,b);
@@ -1144,9 +1143,18 @@ void laui_RackPage(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn
     laColumn* c=laFirstColumn(uil);
     laUiItem* g=laMakeGroup(uil,c,"Racks",0);{ g->Flags|=/*LA_UI_FLAGS_NO_GAP|LA_UI_FLAGS_NO_DECAL|*/LA_UI_FLAGS_NODE_CONTAINER;
         laUiList* gu=g->Page; laColumn* gc=laFirstColumn(gu); gu->AllowScale=1; gu->HeightCoeff=-3; g->State=LA_UI_ACTIVE;
-        laUiItem* hui=laShowItemFull(gu,gc,This,"racks",0,0,laui_NodeRack,0); hui->Expand=15; hui->Flags|=LA_UI_FLAGS_NO_DECAL;
+        laUiItem* hui=laShowItemFull(gu,gc,This,"racks",0,0,laui_NodeRack,context); hui->Expand=15; hui->Flags|=LA_UI_FLAGS_NO_DECAL;
+    }
+    laShowItemFull(uil,c,This,"add_rack",0,(context==LA_RACK_TYPE_DRIVER)?"type=DRIVER;":0,0,0);
+}
+void laui_NodeCategory(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil); laNodeCategory* nc=This->EndInstance;
+    if(nc->Ui){ nc->Ui(uil,This,Extra,0,context); return; }
+    char buf[256];
+    for(laListItemPointer* lip=nc->NodeTypes.pFirst;lip;lip=lip->pNext){
+        laBaseNodeType* nt=lip->p; sprintf(buf,"feedback=%s;text=%s;icon=%lc;",nt->TypeName,nt->Name,nt->Icon?nt->Icon:' ');
+        laShowItemFull(uil,c,0,"LA_confirm",0,buf,0,0);
     }
-    laShowItemFull(uil,c,This,"add_rack",0,context?"type=DRIVER;":0,0,0);
 }
 
 
@@ -1464,10 +1472,10 @@ void laui_InputMapper(laUiList *uil, laPropPack *This, laPropPack *Extra, laColu
         laShowItemFull(uil,cr,0,"la.input_mapping.pages",LA_WIDGET_COLLECTION_SELECTOR,0,0,0);
     }laEndCondition(uil,b2);
     
-    laShowItemFull(uil,c,0,"la.input_mapping.current_page",LA_WIDGET_COLLECTION_SINGLE,0,laui_RackPage,0);
+    laShowItemFull(uil,c,0,"la.input_mapping.current_page",LA_WIDGET_COLLECTION_SINGLE,0,laui_RackPage,LA_RACK_TYPE_INPUT);
 }
 void lauidetached_Drivers(laPanel* p){
-    la_MakeDetachedProp(p, "la.drivers.pages", "page");
+    la_MakeDetachedProp(p, "la.drivers.current_page", "page");
 }
 void laui_Drivers(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
     laColumn* c=laFirstColumn(uil),*cl, *cr;
@@ -1486,7 +1494,7 @@ void laui_Drivers(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *
         laShowItemFull(uil,cr,Extra,"page",LA_WIDGET_COLLECTION_SELECTOR,0,0,0);
     }laEndCondition(uil,b2);
     
-    laShowItemFull(uil,c,Extra,"page",LA_WIDGET_COLLECTION_SINGLE,0,laui_RackPage,1);
+    laShowItemFull(uil,c,Extra,"page",LA_WIDGET_COLLECTION_SINGLE,0,laui_RackPage,LA_RACK_TYPE_DRIVER);
 }
 
 

+ 7 - 56
source/lagui/resources/la_tns_drivers.c

@@ -120,63 +120,11 @@ int OPINV_AddDriverPage(laOperator* a, laEvent *e){
     laNotifyUsers("la.drivers.pages"); laRecordAndPush(0,"la.drivers","Add page", 0);
     return LA_FINISHED;
 }
-
-laBaseNode* la_CreateDriverNode(laNodeRack* ir, laBaseNodeType* NodeType){
-    laBaseNode* bn=memAcquire(NodeType->NodeSize);
-    bn->Type=NodeType; NodeType->Init(bn); lstAppendItem(&ir->Nodes, bn); bn->InRack=ir;
-    laNotifyUsers("la.drivers.pages"); laRecordAndPush(0,"la.drivers","Add node", 0);
-    return bn;
-}
-void la_DestroyDriverNode(laBaseNode* bn){
-    lstRemoveItem(bn->InRack, bn); bn->Type->Destroy(bn);
-    laNotifyUsers("la.drivers.pages"); laRecordAndPush(0,"la.drivers","Delete node", 0);
-    memFree(bn);
-}
-int OPINV_AddDriverNode(laOperator* a, laEvent *e){
-    laNodeRack* ir=a->This?a->This->EndInstance:0; if(!ir) return LA_CANCELED;
-    laBaseNodeType* bnt=0;
-
-    char* type=strGetArgumentString(a->ExtraInstructionsP,"type");
-    if(!type){ laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING; }
-    elif(strSame(type, "TRANSFORM")){ la_CreateDriverNode(ir, &TNS_IDN_TRANSFORM); }
-    elif(strSame(type, "MAKE_TRANSFORM")){ la_CreateDriverNode(ir, &TNS_IDN_MAKE_TRANSFORM); }
-    elif(strSame(type, "VISUALIZER")){ la_CreateDriverNode(ir, &LA_IDN_VISUALIZER); }
-    elif(strSame(type, "SPLIT")){ la_CreateDriverNode(ir, &LA_IDN_SPLIT); }
-    elif(strSame(type, "SWITCH")){ la_CreateDriverNode(ir, &LA_IDN_SWITCH); }
-    elif(strSame(type, "COMBINE")){ la_CreateDriverNode(ir, &LA_IDN_COMBINE); }
-    elif(strSame(type, "VALUES")){ la_CreateDriverNode(ir, &LA_IDN_VALUES); }
-    elif(strSame(type, "MATRIX")){ la_CreateDriverNode(ir, &LA_IDN_MATRIX); }
-    elif(strSame(type, "MATH")){ la_CreateDriverNode(ir, &LA_IDN_MATH); }
-    elif(MAIN.ExtraGetDriverNodeType && (bnt=MAIN.ExtraGetDriverNodeType(type))){ la_CreateDriverNode(ir, bnt); }
-
-    return LA_FINISHED;
-}
-void laui_AddDriverNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
-    laColumn* c=laFirstColumn(uil);
-    if(MAIN.ExtraAddDriverNodes){
-        MAIN.ExtraAddDriverNodes(uil,This,Extra,0,0);
-    }
-    laShowLabel(uil,c,"Operations:",0,0);
-    laShowItemFull(uil,c,This,"add_node_driver",0,"type=SPLIT;text=Split",0,0);
-    laShowItemFull(uil,c,This,"add_node_driver",0,"type=SWITCH;text=Switch",0,0);
-    laShowItemFull(uil,c,This,"add_node_driver",0,"type=COMBINE;text=Combine",0,0);
-    laShowItemFull(uil,c,This,"add_node_driver",0,"type=VALUES;text=Values",0,0);
-    laShowLabel(uil,c,"Visualizations:",0,0);
-    laShowItemFull(uil,c,This,"add_node_driver",0,"type=VISUALIZER;text=Visualizer",0,0);
-    laShowLabel(uil,c,"Math:",0,0);
-    laShowItemFull(uil,c,This,"add_node_driver",0,"type=MATH;text=Math",0,0);
-    laShowItemFull(uil,c,This,"add_node_driver",0,"type=MATRIX;text=Matrix",0,0);
-    laShowItemFull(uil,c,This,"add_node_driver",0,"type=MAKE_TRANSFORM;text=Make Transform",0,0);
-    laShowLabel(uil,c,"Drivers:",0,0);
-    laShowItemFull(uil,c,This,"add_node_driver",0,"type=TRANSFORM;text=Transform Objects",0,0);
-}
-
 int OPINV_RebuildDrivers(laOperator* a, laEvent *e){
     laDriverRequestRebuild();
     return LA_FINISHED;
 }
 
-
 tnsObject* tnsget_FirstObject(void* unused, void* unused2){
     return T->World.AllObjects.pFirst;
 }
@@ -187,8 +135,6 @@ void tns_RegisterNodes(){
     laEnumProp *ep;
 
     laCreateOperatorType("LA_add_driver_page", "New Page", "Add a driver page", 0,0,0,OPINV_AddDriverPage,0,'+',0);
-    at=laCreateOperatorType("LA_add_driver_node", "Add Node", "Add a input mapper node",0,0,0,OPINV_AddDriverNode,OPMOD_FinishOnData,'+',0);
-    at->UiDefine=laui_AddDriverNode;
     laCreateOperatorType("LA_driver_rebuild", "Rebuild Drivers", "Rebuild drivers for evaluation",0,0,0,OPINV_RebuildDrivers,0,L'⭮',0);
 
     pc=laAddPropertyContainer("tns_transform_node", "Transform", "Transform objects",0,tnsui_TransformNode,sizeof(tnsTransformNode),0,0,1);
@@ -210,8 +156,13 @@ void tns_RegisterNodes(){
     laAddFloatProperty(pc,"use_sca", "Scale", "Use Scale",0,0,0,0,0,0.05,0,0,offsetof(tnsMakeTransformNode, UseSca),0,0,0,0,0,0,0,0,0,0,0);
     laAddFloatProperty(pc,"use_angle", "Angle", "Use Angle",0,0,0,0,0,0.05,0,0,offsetof(tnsMakeTransformNode, UseAngle),0,0,0,0,0,0,0,0,0,0,0);
     
-    LA_IDN_REGISTER(TNS_IDN_TRANSFORM,TNS_PC_IDN_TRANSFORM, IDN_TransformInit, IDN_TransformDestroy, IDN_TransformVisit, IDN_TransformEval, tnsTransformNode);
-    LA_IDN_REGISTER(TNS_IDN_MAKE_TRANSFORM,TNS_PC_IDN_MAKE_TRANSFORM, IDN_MakeTransformInit, IDN_MakeTransformDestroy, IDN_MakeTransformVisit, IDN_MakeTransformEval, tnsMakeTransformNode);
+    LA_IDN_REGISTER("Transform",0,TNS_IDN_TRANSFORM,TNS_PC_IDN_TRANSFORM, IDN_TransformInit, IDN_TransformDestroy, IDN_TransformVisit, IDN_TransformEval, tnsTransformNode);
+    LA_IDN_REGISTER("Make Transform",0,TNS_IDN_MAKE_TRANSFORM,TNS_PC_IDN_MAKE_TRANSFORM, IDN_MakeTransformInit, IDN_MakeTransformDestroy, IDN_MakeTransformVisit, IDN_MakeTransformEval, tnsMakeTransformNode);
+
+    LA_NODE_CATEGORY_DRIVER=laAddNodeCategory("Driver",0,LA_RACK_TYPE_DRIVER);
+
+    laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_MATH, &TNS_IDN_MAKE_TRANSFORM,0);
+    laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_DRIVER, &TNS_IDN_TRANSFORM,0);
 }
 
 void laDriverRequestRebuild(){ MAIN.Drivers->NeedRebuild=1; }

+ 11 - 22
source/lagui/resources/la_widgets.c

@@ -2456,19 +2456,6 @@ int OPMOD_Collection(laOperator *a, laEvent *e){
     int at = 0;
     laUiList* ToUil = a->ToPanel->MenuRefer?a->ToPanel->MenuRefer:&a->ToPanel->UI;
 
-    if (a->ConfirmData){
-        if (a->ConfirmData->StrData){
-            laUDF *udf = laPrepareUDF(a->ConfirmData->StrData);
-            laPropPack PP = {0};
-            PP.RawThis = &ui->PP;
-            PP.LastPs = ui->PP.LastPs;
-            PP.EndInstance = uit->Ptr1;
-            laWritePropP(udf, &PP);
-            laPackUDF(udf, 0);
-            return LA_RUNNING;
-        }
-    }
-
     if (!laIsInUiItem(ui, e->x, e->y) /* || e->y>(ui->Subs.pFirst?((laUiList*)ui->Subs.pFirst)->HeightCoeff:10000)*/){
         return LA_FINISHED_PASS;
     }
@@ -2509,11 +2496,13 @@ int OPMOD_Collection(laOperator *a, laEvent *e){
         for (uil = ui->Subs.pFirst; uil; uil = uil->Item.pNext){
             if (a->ConfirmData) return LA_RUNNING;
             if (laIsInBound(e->x, e->y, uil->L, uil->R, uil->U, uil->B)){
-                laRedrawCurrentPanel();
+                laRecalcCurrentPanel();
                 laPropPack PP={0}; la_CopyPropPack(&ui->PP, &PP); //needed because layout can be switched after set active.
                 laSetActiveInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, uil->Instance);
                 laRecordAndPushProp(&PP,0); laMarkPropChanged(&PP);
-                laConfirmInt(a, 0, LA_CONFIRM_DATA);
+                char* cmd; if ((!(cmd = strGetArgumentString(ui->Instructions, "feedback")))||(!strSame(cmd,"NONE"))){
+                    laConfirmInt(a, 0, LA_CONFIRM_DATA);
+                }
                 return LA_RUNNING_PASS;
             }
         }
@@ -2633,17 +2622,17 @@ int OPMOD_NodeSocket(laOperator *a, laEvent *e){
             laNodeInSocket* s=ui->PP.EndInstance;
             uit->Ptr2 = s->Source;
             if(!s->Source){
-                s->ColorId=MAIN.NextWireColor; s->Source=&MAIN.tNodeOut;
+                s->ColorId=MAIN.NextWireColor; s->Source=&MAIN.tNodeOut; latouched_NodeInSocket(0,0);
                 MAIN.tNodeOut.RuntimeX=MAIN.tNodeOut.RuntimeY=MAIN.tNodeOut.RuntimePX=MAIN.tNodeOut.RuntimePY=0;
             }else{
                 MAIN.tNodeIn.Source = s->Source;
                 MAIN.tNodeIn.RuntimeX=MAIN.tNodeIn.RuntimeY=MAIN.tNodeIn.RuntimePX=MAIN.tNodeIn.RuntimePY=0;
                 MAIN.tNodeIn.RuntimePX=-(s->Source->RuntimeX+s->Source->RuntimePX)+(s->RuntimeX+s->RuntimePX);
                 MAIN.tNodeIn.RuntimePY=-(s->Source->RuntimeY+s->Source->RuntimePY)+(s->RuntimeY+s->RuntimePY);
-                s->Source=0; MAIN.tNodeIn.ColorId=s->ColorId;
+                s->Source=0; MAIN.tNodeIn.ColorId=s->ColorId; latouched_NodeInSocket(0,0);
             }
         }
-        elif(pc==LA_PC_SOCKET_OUT){ MAIN.tNodeIn.Source=ui->PP.EndInstance;
+        elif(pc==LA_PC_SOCKET_OUT){ MAIN.tNodeIn.Source=ui->PP.EndInstance; latouched_NodeInSocket(0,0);
             MAIN.tNodeIn.RuntimeX=MAIN.tNodeIn.RuntimeY=MAIN.tNodeIn.RuntimePX=MAIN.tNodeIn.RuntimePY=0;
             MAIN.tNodeIn.ColorId=MAIN.NextWireColor;  }
         uit->LastX = e->x; uit->LastY = e->y;
@@ -2667,14 +2656,14 @@ int OPMOD_NodeSocket(laOperator *a, laEvent *e){
         laUiItem* tui=uit->Ptr1; void* soc=tui?tui->PP.EndInstance:0;
         if(pc == LA_PC_SOCKET_IN){
             if(!uit->Ptr2){ if(!tui){ laNodeInSocket* s=ui->PP.EndInstance; s->Source=0; return LA_RUNNING; }
-                laNodeInSocket* s=ui->PP.EndInstance; s->Source=0; memAssignRef(s,&s->Source,soc);
+                laNodeInSocket* s=ui->PP.EndInstance; s->Source=0; memAssignRef(s,&s->Source,soc); latouched_NodeInSocket(0,0);
                 s->ColorId=MAIN.NextWireColor; laRecordAndPushProp(&ui->PP, 0); laMarkPropChanged(&ui->PP);
             }else{
                 if(!tui){
-                    laNodeInSocket* s=ui->PP.EndInstance; s->Source=uit->Ptr2; memAssignRef(s,&s->Source,0);
+                    laNodeInSocket* s=ui->PP.EndInstance; s->Source=uit->Ptr2; memAssignRef(s,&s->Source,0); latouched_NodeInSocket(0,0);
                     laRecordAndPushProp(&ui->PP, 0); laMarkPropChanged(&ui->PP);
                 }else{
-                    laNodeInSocket* s=soc; if(s->Source){ uit->Ptr2=0; return LA_RUNNING; }
+                    laNodeInSocket* s=soc; if(s->Source){ uit->Ptr2=0; return LA_RUNNING; }  latouched_NodeInSocket(0,0);
                     memAssignRef(s,&s->Source,uit->Ptr2); s->ColorId=((laNodeInSocket*)ui->PP.EndInstance)->ColorId;
                     laRecordDifferences(&ui->PP,0); laRecordDifferences(&tui->PP,0); laPushDifferences("Socket status changed", 0);
                     laMarkPropChanged(&tui->PP); laMarkPropChanged(&ui->PP);
@@ -2683,7 +2672,7 @@ int OPMOD_NodeSocket(laOperator *a, laEvent *e){
         }
         else{
             if(!tui){ return LA_RUNNING; }
-            laNodeInSocket* s=soc; s->Source=0; memAssignRef(s,&s->Source,ui->PP.EndInstance);
+            laNodeInSocket* s=soc; s->Source=0; memAssignRef(s,&s->Source,ui->PP.EndInstance); latouched_NodeInSocket(0,0);
             s->ColorId=MAIN.NextWireColor; laRecordAndPushProp(&tui->PP, 0); laMarkPropChanged(&tui->PP);
         }