*/}}
Browse Source

Basic toolbox and editor

YimingWu 4 months ago
parent
commit
0870506743

+ 6 - 0
la_interface.h

@@ -1569,6 +1569,9 @@ STRUCTURE(laInputMappingBundle){
     void* _pad;
     laListHandle InputMappings;
     laInputMapping* CurrentInputMapping;
+    laListHandle Toolboxes;
+    laInputMapping* CurrentToolbox;
+    int ToolboxLayout;
 };
 
 #define LA_SIGNAL_NEW 10000
@@ -2392,6 +2395,9 @@ laInputMappingEntry* laNewInputMappingMouseEntryP(laInputMapping* im, int MouseE
 void laRemoveInputMappingEntry(laInputMapping* im, laInputMappingEntry* e);
 void laRemoveInputMapping(laInputMapping* im);
 
+laInputMapping* laNewToolbox(char* Name);
+void laRemoveToolbox(laInputMapping* im);
+
 laCustomSignal* laNewCustomSignal(char* Name, int Signal);
 void laRemoveCustomSignal(laCustomSignal* cs);
 

+ 26 - 7
la_kernel.c

@@ -1806,6 +1806,19 @@ void laRemoveInputMapping(laInputMapping* im){
     lstRemoveItem(&MAIN.InputMapping->InputMappings,im); strSafeDestroy(&im->Name); memFree(im);
 }
 
+laInputMapping* laNewToolbox(char* Name){
+    laInputMapping* im=memAcquireHyper(sizeof(laInputMapping)); lstAppendItem(&MAIN.InputMapping->Toolboxes,im);
+    memAssignRef(MAIN.InputMapping,&MAIN.InputMapping->CurrentToolbox,im);
+    strSafeSet(&im->Name,Name);
+    return im;
+}
+void laRemoveToolbox(laInputMapping* im){
+    laInputMappingEntry* e; while(e=im->Entries.pFirst){ laRemoveInputMappingEntry(im,e); }
+    laInputMapping* use=im->Item.pNext?im->Item.pNext:im->Item.pPrev;
+    memAssignRef(MAIN.InputMapping,&MAIN.InputMapping->CurrentToolbox,use);
+    lstRemoveItem(&MAIN.InputMapping->Toolboxes,im); strSafeDestroy(&im->Name); memFree(im);
+}
+
 laCustomSignal* laNewCustomSignal(char* Name, int Signal){
     laCustomSignal* cs=memAcquire(sizeof(laCustomSignal)); lstAppendItem(&MAIN.CustomSignals,cs);
     strSafeSet(&cs->Name,Name); cs->Signal = Signal;
@@ -2544,8 +2557,8 @@ void laEnsurePanelInBound(laPanel *p, laUiList *uil){
         }
     }
 
-    if((!p->IsMenuPanel) && (p->Mode!=LA_PANEL_FLOATING_PASSIVE)){
-        if(p->W<LA_RH*4) p->W=LA_RH*4;
+    if((!p->IsMenuPanel) && (p->Mode!=LA_PANEL_FLOATING_PASSIVE) && (!p->Block)){
+        if(p->W<LA_RH*3) p->W=LA_RH*3;
         if(p->H<LA_RH*2) p->H=LA_RH*2;
     }
 
@@ -5997,7 +6010,8 @@ int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast
                 laUiDefineFunc Template = ui->Template ? ui->Template : laGetPropertyUiDefine(&ui->PP, TInstance);
 
                 int Begin = ui->TB;
-                int EL = ui->TL, ER = Spread?(Spread*LA_RH+ui->TL):ui->TR;
+                int SpreadWidth = Spread*LA_RH; if((!uil->AllowScale) && (SpreadWidth > ui->TR-ui->TL)){ SpreadWidth=ui->TR-ui->TL; }
+                int EL = ui->TL, ER = Spread?(SpreadWidth+ui->TL):ui->TR; int MaxER=ER;
                 int ElementB = ui->TU;
                 real ElementWidth = ElementLimit ? 1.0f / ElementLimit : 1.0;
                 int MaxB = ElementB;
@@ -6043,7 +6057,7 @@ int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast
 
                     if (ElementLimit){
                         EL = tnsInterpolate(ui->TL, ui->TR, (Col)*ElementWidth);
-                        ER = tnsInterpolate(ui->TL, ui->TR, (Col + 1) * ElementWidth);
+                        ER = tnsInterpolate(ui->TL, ui->TR, (Col + 1) * ElementWidth); MaxER=TNS_MAX2(ER,MaxER);
                     }
 
                     while (iuil && iuil->Instance != TInstance){
@@ -6086,8 +6100,13 @@ int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast
                             Begin = ElementB + bt->TM;
                         }
                     }elif(Spread){
-                        EL+=Spread*LA_RH;
-                        ER+=Spread*LA_RH;
+                        EL+=SpreadWidth;
+                        ER+=SpreadWidth;
+                        MaxER=TNS_MAX2(ER,MaxER);
+                        if((!uil->AllowScale) && (ER > ui->TR)){
+                            EL=ui->TL; ER=SpreadWidth+EL;
+                            Begin = ElementB + bt->TM;
+                        }
                     }else{
                         Row += 1;
                         Begin = ElementB + bt->TM;
@@ -6104,7 +6123,7 @@ int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast
                 while (iuil=lstPopItem(&TempPages)){ la_DestroyTabPage(0, iuil, 0); }
                 ui->PP.EndInstance = laGetActiveInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, &pi);
                 ui->TB = MaxB;
-                if(Spread){ ui->TR=ER-Spread*LA_RH; if(ui->TR>MaxR) MaxR=ui->TR; }
+                if(Spread){ ui->TR=MaxER-SpreadWidth; if(ui->TR>MaxR) MaxR=ui->TR; }
                 if (!WaitAnimation){ ui->L = ui->TL; ui->R = ui->TR; ui->U = ui->TU; ui->B = ui->TB = MaxB; }
             }else if (ui->Type == _LA_UI_COLLECTION_SELECTOR || ui->Type == _LA_UI_COLLECTION_SINGLE){
                 if(ui->Flags&LA_UI_COLLECTION_SIMPLE_SELECTOR){

+ 47 - 14
resources/la_operators.c

@@ -21,30 +21,31 @@
 extern LA MAIN;
 extern struct _tnsMain *T;
 
-void la_PanelActiviatorParser(laStringSplitor *ss, uint32_t *IconID, char *DisplayString){
+void la_DefaultOperatorParser(laStringSplitor *ss, uint32_t *IconID, char *DisplayString){
     char *StrArg;
+    laStringPart *sp;
     if (ss && ss->parts.pFirst){
         if (StrArg = strGetArgumentString(ss, "text")){
             strCopyFull(DisplayString, StrArg);
-        }else if (StrArg = strGetArgumentString(ss, "panel_id")){
-            laUiTemplate* uit = laFindUiTemplate(StrArg);
-            strCopyFull(DisplayString, transLate("Show "));
-            strAppend(DisplayString, uit->Title->Ptr);
         }
-    }else{
-        strCopyFull(DisplayString, transLate("Activate A Panel"));
+        if (StrArg = strGetArgumentString(ss, "icon")){
+            int adv=0; *IconID = laToUnicode(StrArg, &adv);
+        }
     }
 }
-void la_DefaultOperatorParser(laStringSplitor *ss, uint32_t *IconID, char *DisplayString){
+void la_PanelActiviatorParser(laStringSplitor *ss, uint32_t *IconID, char *DisplayString){
     char *StrArg;
-    laStringPart *sp;
+    la_DefaultOperatorParser(ss,IconID,DisplayString);
     if (ss && ss->parts.pFirst){
         if (StrArg = strGetArgumentString(ss, "text")){
             strCopyFull(DisplayString, StrArg);
+        }else if (StrArg = strGetArgumentString(ss, "panel_id")){
+            laUiTemplate* uit = laFindUiTemplate(StrArg);
+            strCopyFull(DisplayString, transLate("Show "));
+            strAppend(DisplayString, uit->Title->Ptr);
         }
-        if (StrArg = strGetArgumentString(ss, "icon")){
-            int adv=0; *IconID = laToUnicode(StrArg, &adv);
-        }
+    }else{
+        strCopyFull(DisplayString, transLate("Activate A Panel"));
     }
 }
 
@@ -52,6 +53,7 @@ laProp *la_PropLookup(laListHandle *lst, char *ID);
 void la_EnsurePanelSnapping(laPanel *p, int CW, int CH);
 void la_RecalcBlockRecursive(laBlock *b, int X, int Y, int W, int H);
 void la_ConditionNodeFreeRecursive(laUiConditionNode *ucn);
+void la_SendSignalEvent(SYSWINDOW* hwnd, int signal);
 
 int OPMOD_FinishOnData(laOperator* a, laEvent* e){
     if(a->ConfirmData){
@@ -927,6 +929,33 @@ int OPINV_UDFPropagate(laOperator *a, laEvent *e){
     return LA_FINISHED;
 }
 
+int OPINV_SendSignal(laOperator *a, laEvent *e){
+    const char* sig=strGetArgumentString(&a->ExtraInstructionsP,"signal"); if((!sig) || (!sig[0])) return LA_FINISHED;
+    laCustomSignal* cs=laFindSignal(sig);
+    if(cs){ la_SendSignalEvent(e->window->win, cs->Signal); }
+    return LA_FINISHED;
+}
+
+int OPINV_NewToolbox(laOperator *a, laEvent *e){
+    laNewToolbox("New Toolbox"); laNotifyUsers("la.input_mapping"); return LA_FINISHED;
+}
+int OPINV_RemoveToolbox(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance) return LA_CANCELED; laInputMapping* im=a->This->EndInstance;
+    char* buf[256];sprintf(buf,"%s \"%s\".",transLate("Will remove toolbox"),SSTR(im->Name));
+    laEnableYesNoPanel(0, 0, "Confirm?", buf, e->x, e->y, 200, e);
+    return LA_RUNNING;
+}
+int OPMOD_RemoveToolbox(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance) return LA_CANCELED; laInputMapping* im=a->This->EndInstance;
+    if(a->ConfirmData){
+        if(a->ConfirmData->Mode == LA_CONFIRM_OK){
+            laRemoveToolbox(im); laNotifyUsers("la.input_mapping");
+        }
+        return LA_FINISHED;
+    }
+    return LA_RUNNING;
+}
+
 int OPINV_NewInputMapping(laOperator *a, laEvent *e){
     laNewInputMapping("New Mapping"); laNotifyUsers("la.input_mapping"); return LA_FINISHED;
 }
@@ -938,7 +967,7 @@ int OPINV_RemoveInputMapping(laOperator *a, laEvent *e){
 }
 int OPINV_NewInputMappingEntry(laOperator *a, laEvent *e){
     if(!a->This || !a->This->EndInstance) return LA_CANCELED; laInputMapping* im=a->This->EndInstance;
-    laInputMappingEntry* ime=laNewInputMappingEntry(im,0,0,"a",0,"none");
+    laInputMappingEntry* ime=laNewInputMappingEntry(im,0,0,"",0,"none");
     if(strArgumentMatch(a->ExtraInstructionsP,"position","top")){
         lstRemoveItem(&im->Entries,ime);
         lstPushItem(&im->Entries,ime);
@@ -2630,7 +2659,11 @@ void la_RegisterBuiltinOperators(){
                                0, 0, 0, OPINV_AddResourceFolder, 0, U'🞧', LA_ACTUATOR_SYSTEM);
     laCreateOperatorType("LA_remove_resource_folder", "Remove Resource Folder", "Remove a resource folder entry",
                                0, 0, 0, OPINV_RemoveResourceFolder, 0, U'🞫', LA_ACTUATOR_SYSTEM);
-
+    
+    laCreateOperatorType("LA_send_signal", "Send Signal", "Send signal to the UI", 0, 0, 0, OPINV_SendSignal, 0, 0, LA_ACTUATOR_SYSTEM);
+    
+    laCreateOperatorType("LA_new_toolbox", "New Toolbox", "New custom toolbox", 0, 0, 0, OPINV_NewToolbox, 0, '+', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_remove_toolbox", "Remove Toolbox", "Remove custom toolbox", 0, 0, 0, OPINV_RemoveToolbox, OPINV_RemoveToolbox, U'🞫', LA_ACTUATOR_SYSTEM);
     laCreateOperatorType("LA_new_input_mapping", "New Mapping", "New input mapping", 0, 0, 0, OPINV_NewInputMapping, 0, '+', LA_ACTUATOR_SYSTEM);
     laCreateOperatorType("LA_new_input_mapping_entry", "New Entry", "New input mapping entry", 0, 0, 0, OPINV_NewInputMappingEntry, 0, '+', LA_ACTUATOR_SYSTEM);
     laCreateOperatorType("LA_remove_input_mapping", "Remove Mapping", "Remove input mapping", 0, 0, 0, OPINV_RemoveInputMapping, OPMOD_RemoveInputMapping, U'🞫', LA_ACTUATOR_SYSTEM);

+ 24 - 0
resources/la_properties.c

@@ -844,6 +844,15 @@ void* laget_FirstInputMapping(void* unused1,void* unused2){
 void* laget_CurrentInputMapping(laInputMappingBundle* imb){
     return imb->CurrentInputMapping;
 }
+void* laget_FirstToolbox(void* unused1,void* unused2){
+    return MAIN.InputMapping->Toolboxes.pFirst;
+}
+void* laget_CurrentToolbox(laInputMappingBundle* imb){
+    return imb->CurrentToolbox;
+}
+void *laget_detached_FirstToolbox(void *UNUSED1, void *UNUSED2){
+    return MAIN.InputMapping->Toolboxes.pFirst;
+}
 void* laget_FirstCustomSignal(void* unused1,void* unused2){
     return MAIN.CustomSignals.pFirst;
 }
@@ -1847,6 +1856,15 @@ void la_RegisterInternalProps(){
         p = laAddPropertyContainer("la_input_mapping_bundle", "Input Mapping Bundle", "Bundle of input mapping data", 0,0,sizeof(laInputMappingBundle), 0,0,1);{
             laAddSubGroup(p, "mappings","Mappings","Input mappings","la_input_mapping",0,0,0,-1,0,laget_CurrentInputMapping,0,0,0,0,offsetof(laInputMappingBundle,InputMappings),0);
             laAddSubGroup(p, "current","Current Mapping","Current input mapping","la_input_mapping",0,0,0,offsetof(laInputMappingBundle,CurrentInputMapping),laget_FirstInputMapping,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);
+            laAddSubGroup(p, "toolboxes","Toolboxes","Custom toolboxes","la_toolbox",0,0,0,-1,0,laget_CurrentInputMapping,0,0,0,0,offsetof(laInputMappingBundle,Toolboxes),0);
+            sp=laAddSubGroup(p, "current_toolbox","Current Toolbox","Current tool box","la_toolbox",0,0,0,offsetof(laInputMappingBundle,CurrentToolbox),laget_FirstToolbox,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);
+            laSubGroupDetachable(sp, laget_detached_FirstToolbox, laget_ListNext);
+            ep=laAddEnumProperty(p,"toolbox_layout","Toolbox Layout","Toolbox layout",0,0,0,0,0,offsetof(laInputMappingBundle,ToolboxLayout),0,0,0,0,0,0,0,0,0,0);
+            laAddEnumItemAs(ep, "LIST", "#", "Display as list", 0, 0);
+            laAddEnumItemAs(ep, "W3", "W3", "Width of 3", 3, 0);
+            laAddEnumItemAs(ep, "W5", "W5", "Width of 5", 5, 0);
+            laAddEnumItemAs(ep, "W8", "W8", "Width of 8", 8, 0);
+            laAddEnumItemAs(ep, "W13", "W13", "Width of 13", 13, 0);
         }
         p = laAddPropertyContainer("la_input_mapping", "Input Mapping", "Input mapping data", 0,0,sizeof(laInputMapping), 0,0,2);{
             laAddStringProperty(p, "name", "Name", "The name of this mapping", 0,0,0,"Mapping", 1, offsetof(laInputMapping, Name), 0,0,0,0,LA_AS_IDENTIFIER);
@@ -1854,6 +1872,12 @@ void la_RegisterInternalProps(){
             laAddOperatorProperty(p,"remove","Remove","Remove this mapping","LA_remove_input_mapping",U'🞫',0);
             laAddOperatorProperty(p,"new_entry","New Entry","New mapping entry","LA_new_input_mapping_entry",'+',0);
         }
+        p = laAddPropertyContainer("la_toolbox", "Toolbox", "Toolbox data", 0,0,sizeof(laInputMapping), 0,0,2);{
+            laAddStringProperty(p, "name", "Name", "The name of this toolbox", 0,0,0,"Toolbox", 1, offsetof(laInputMapping, Name), 0,0,0,0,LA_AS_IDENTIFIER);
+            laAddSubGroup(p, "entries","Entries","Toolbox entries","la_input_mapping_entry",0,0,0,-1,0,0,0,0,0,0,offsetof(laInputMapping,Entries),0);
+            laAddOperatorProperty(p,"remove","Remove","Remove this mapping","LA_remove_toolbox",U'🞫',0);
+            laAddOperatorProperty(p,"new_entry","New Entry","New toolbox entry","LA_new_input_mapping_entry",'+',0);
+        }
         p = laAddPropertyContainer("la_input_mapping_entry", "Input Mapping Entry", "Input mapping entry", 0,0,sizeof(laInputMappingEntry), 0,0,1);{
             laAddIntProperty(p,"__move","Move Slider","Move Slider",LA_WIDGET_HEIGHT_ADJUSTER,0,0,0,0,0,0,0,0,0,laset_InputMappingEntryMove,0,0,0,0,0,0,0,0,LA_UDF_IGNORE);
             ep=laAddEnumProperty(p,"disabled","Enabled","Enable or disable this input mapping entry",0,0,0,0,0,offsetof(laInputMappingEntry,Disabled),0,0,0,0,0,0,0,0,0,0);

+ 163 - 4
resources/la_templates.c

@@ -1660,6 +1660,7 @@ void laui_GameController(laUiList *uil, laPropPack *This, laPropPack *Extra, laC
 void lauidetached_GameController(laPanel* p){
     la_MakeDetachedProp(p, "la.controllers", "controllers");
 }
+
 void laui_OperatorTypeEntry(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *ExtraColumns, int context){
     laColumn* c=ExtraColumns;
     laShowItem(uil,c,This,"name")->Flags|=LA_UI_FLAGS_PLAIN;
@@ -1679,7 +1680,7 @@ void laui_InputMappingEntry(laUiList *uil, laPropPack *This, laPropPack *Extra,
     laShowItem(uil,crl,This,"disabled")->Flags=LA_UI_FLAGS_ICON|LA_UI_FLAGS_HIGHLIGHT|LA_UI_FLAGS_CYCLE;
     b1=laOnConditionToggle(uil,cl,0,0,0,0,0);{
         laEndRow(uil,b);
-        laShowLabel(uil,cl,"Mode:\n ",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT|LA_UI_FLAGS_DISABLED|LA_TEXT_LINE_WRAP;
+        laShowLabel(uil,cl,"Mode\n ",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT|LA_UI_FLAGS_DISABLED|LA_TEXT_LINE_WRAP;
 
         b2=laBeginRow(uil,crl,0,0);{
             laShowItem(uil,crl,This,"use_operator")->Flags=LA_UI_FLAGS_ICON|LA_UI_FLAGS_PLAIN|LA_UI_FLAGS_DISABLED;
@@ -1719,7 +1720,7 @@ void laui_InputMappingEntry(laUiList *uil, laPropPack *This, laPropPack *Extra,
                     ui1->Flags|=LA_UI_FLAGS_EXPAND;ui1->Expand=10;
                     laEndRow(uil,b3);
                     laShowItem(uil,crl,This,"operator_arguments");
-                    laShowLabel(uil,cl,"Args:",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT|LA_UI_FLAGS_DISABLED;
+                    laShowLabel(uil,cl,"Args",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT|LA_UI_FLAGS_DISABLED;
                 }laElse(uil,b4);{
                     laEndRow(uil,b3);
                 }laEndCondition(uil,b4);
@@ -1803,6 +1804,162 @@ void laui_InputMappingBundle(laUiList *uil, laPropPack *This, laPropPack *Extra,
         laShowItemFull(guil,gc,0,"la.input_mapping.current",LA_WIDGET_COLLECTION_SINGLE,0,laui_InputMapping,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
     }laEndCondition(uil,b3);
 }
+
+void laui_ToolboxEntryButton(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil);
+    laInputMappingEntry* ime=This?This->EndInstance:0; if(!ime){ laShowLabel(uil,c,"?",0,0); return; }
+    if(ime->UseOperator){
+        char buf[256]; if(SSTR(ime->Key)[0]){ sprintf(buf,"text=%s;",SSTR(ime->Key),SSTR(ime->OperatorArguments)); }
+        else{ sprintf(buf,"%s",SSTR(ime->OperatorArguments)); }
+        laShowItemFull(uil,c,0,SSTR(ime->Operator),0,buf,0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
+    }else{
+        char* display=SSTR(ime->Key);
+        char buf[256]; sprintf(buf,"signal=%s;text=%s;",SSTR(ime->Signal),display[0]?display:SSTR(ime->Signal));
+        laShowItemFull(uil,c,0,"LA_send_signal",0,buf,0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
+    }
+}
+void laui_ToolboxEntry(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *ExtraColumns, int context){
+    laColumn* c=ExtraColumns;
+    laColumn* cl=laLeftColumn(c,3),*cr=laRightColumn(c,0);
+
+    laUiItem* b,*b1,*b2,*b3,*b4;
+
+    b=laBeginRow(uil,cl,1,1);
+    laShowItem(uil,cl,This,"__move");
+    laShowItem(uil,cl,This,"key")->Flags|=LA_UI_FLAGS_PLAIN|LA_TEXT_ALIGN_CENTER;
+    b1=laOnConditionToggle(uil,cl,0,0,0,0,0);{
+        laEndRow(uil,b);
+        laShowLabel(uil,cl,"Mode",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT|LA_UI_FLAGS_DISABLED;
+
+        b2=laBeginRow(uil,cr,0,0);{
+            laShowItem(uil,cr,This,"use_operator")->Flags=LA_UI_FLAGS_ICON|LA_UI_FLAGS_PLAIN|LA_UI_FLAGS_DISABLED;
+            b3=laOnConditionThat(uil,cr,laPropExpression(This,"use_operator"));{
+                laUiItem* bui=laShowItemFull(uil,cr,This,"select_operator",0,"icon= ;",0,0);
+                bui->Expand=1; bui->Flags|=LA_UI_FLAGS_ICON|LA_UI_FLAGS_UNDERNEATH;
+                laUiItem* ui=laShowItem(uil,cr,This,"operator");
+                ui->Expand=1; ui->Flags|=LA_UI_FLAGS_PLAIN;
+            }laElse(uil,b3);{
+                laUiItem* bui=laShowItemFull(uil,cr,This,"select_signal",0,"icon= ;",0,0);
+                bui->Expand=1; bui->Flags|=LA_UI_FLAGS_ICON|LA_UI_FLAGS_UNDERNEATH;
+                laUiItem* ui=laShowItem(uil,cr,This,"signal");
+                ui->Expand=1; ui->Flags|=LA_UI_FLAGS_PLAIN;
+            }laEndCondition(uil,b3);
+            laShowItem(uil,cr,This,"remove")->Flags|=LA_UI_FLAGS_ICON;
+        }laEndRow(uil,b2);
+        
+
+        //b2=laBeginRow(uil,crr,0,0);{
+        //    laShowSeparator(uil,crr)->Expand=1;
+        //    laShowItem(uil,crr,This,"reset");
+        //}laEndRow(uil,b2);
+        laUiItem* ui=laShowItem(uil,cr,This,"use_operator"); ui->Flags|=LA_UI_FLAGS_EXPAND;
+        b4=laOnConditionThat(uil,cr,laPropExpression(&ui->PP,""));{\
+            laShowLabel(uil,cl,"Args",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT|LA_UI_FLAGS_DISABLED;
+            laShowItem(uil,cr,This,"operator_arguments");
+        }laEndCondition(uil,b4);
+
+        laShowLabel(uil,cl,"Disp",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT|LA_UI_FLAGS_DISABLED;
+        laShowItem(uil,cr,This,"key");
+
+        laShowSeparator(uil,c);
+
+    }laElse(uil,b1);{
+        laEndRow(uil,b);
+        b2=laBeginRow(uil,cr,0,0);{
+            laShowItem(uil,cr,This,"use_operator")->Flags=LA_UI_FLAGS_ICON|LA_UI_FLAGS_PLAIN;
+            b3=laOnConditionThat(uil,cr,laPropExpression(This,"use_operator"));{
+                laUiItem* ui=laShowItem(uil,cr,This,"operator_name");ui->Expand=1;ui->Flags|=LA_UI_FLAGS_PLAIN;
+            }laElse(uil,b3);{
+                laUiItem* ui=laShowItem(uil,cr,This,"signal");ui->Expand=1;ui->Flags|=LA_UI_FLAGS_PLAIN;
+            }laEndCondition(uil,b3);
+            laShowItem(uil,cr,This,"remove")->Flags|=LA_UI_FLAGS_ICON;
+        }laEndRow(uil,b2);
+    }laEndCondition(uil,b1);
+}
+void laui_ToolboxListing(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil);laSplitColumn(uil,c,0.25);
+    laColumn* cl=laLeftColumn(c,3),*cr=laRightColumn(c,0);
+
+    laUiItem* b=laBeginRow(uil,c,0,0);
+    laShowItemFull(uil,c,This,"new_entry",0,"position=top;",0,0);
+    laEndRow(uil,b);
+    laShowSeparator(uil,c);
+
+    //laShowColumnAdjuster(uil,c);
+    //laShowLabel(uil,cl,"✓",0,0)->Flags|=LA_TEXT_ALIGN_CENTER|LA_UI_FLAGS_DISABLED;
+    //laShowLabel(uil,crl,"Operation",0,0)->Flags|=LA_TEXT_ALIGN_CENTER|LA_UI_FLAGS_DISABLED;
+    //laShowLabel(uil,crr,"Input",0,0)->Flags|=LA_TEXT_ALIGN_CENTER|LA_UI_FLAGS_DISABLED;
+
+    laShowItemFull(uil,c,This,"entries",0,0,laui_ToolboxEntry,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
+
+    laShowSeparator(uil,c);
+    b=laBeginRow(uil,c,0,0);
+    laShowItem(uil,c,This,"new_entry");
+    laEndRow(uil,b);
+}
+void lauidetached_Toolbox(laPanel* p){
+    la_MakeDetachedProp(p, "la.input_mapping.current_toolbox", "toolbox");
+    la_MakeDetachedProp(p, "la.input_mapping.toolbox_layout","layout");
+}
+void laui_Toolbox(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil); laSplitColumn(uil,c,0.2);
+    laColumn* cl=laLeftColumn(c,1), *cr=laRightColumn(c,0);
+    laUiItem* cui=laShowInvisibleItem(uil,c,Extra,"layout");
+
+    laUiItem* b0=laOnConditionThat(uil,c,laEqual(laPropExpression(&cui->PP,""),laIntExpression(0)));{
+        laUiItem* ui=laShowItemFull(uil,c,Extra,"toolbox.entries",0,0,laui_ToolboxEntryButton,0);
+        ui->Flags|=LA_UI_FLAGS_NO_DECAL;
+        laUiItem* b=laBeginRow(uil,c,0,0);{
+            laUiList* muil=laMakeMenuPageEx(uil,c,"☰",LA_UI_FLAGS_NO_DECAL); laColumn* mc=laFirstColumn(muil);
+            laUiItem* b1=laBeginRow(muil,mc,0,0);{
+                laShowItemFull(muil,mc,Extra,"toolbox",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0)->Flags|=LA_UI_COLLECTION_SIMPLE_SELECTOR;
+                laShowItemFull(muil,mc, 0, "LA_panel_activator", 0, "panel_id=LAUI_toolbox_editor;icon=🖍;", 0, 0)->Flags|=LA_UI_FLAGS_ICON;
+                laShowItemFull(muil,mc,Extra,"layout",0,0,0,0)->Flags|=LA_UI_FLAGS_EXPAND;
+            }laEndRow(muil,b1);
+        }laEndRow(uil,b);
+    }laElse(uil,b0);{
+        laUiItem* b=laBeginRow(uil,cl,0,0);{
+            laUiList* muil=laMakeMenuPageEx(uil,cl,"☰",LA_UI_FLAGS_NO_DECAL); laColumn* mc=laFirstColumn(muil);
+            laUiItem* b1=laBeginRow(muil,mc,0,0);{
+                laShowItemFull(muil,mc,Extra,"toolbox",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0)->Flags|=LA_UI_COLLECTION_SIMPLE_SELECTOR;
+                laShowItemFull(muil,mc, 0, "LA_panel_activator", 0, "panel_id=LAUI_toolbox_editor;icon=🖍;", 0, 0)->Flags|=LA_UI_FLAGS_ICON;
+                laShowItemFull(muil,mc,Extra,"layout",0,0,0,0)->Flags|=LA_UI_FLAGS_EXPAND;
+            }laEndRow(muil,b1);
+        }laEndRow(uil,b);
+    }laEndCondition(uil,b0);
+
+#define ADD_WIDTH_OF(n) \
+    b0=laOnConditionThat(uil,cr,laEqual(laPropExpression(&cui->PP,""),laIntExpression(n)));{ \
+        laUiItem* ui=laShowItemFull(uil,cr,Extra,"toolbox.entries",0,0,laui_ToolboxEntryButton,0); \
+        ui->Flags|=LA_UI_FLAGS_NO_DECAL;  ui->Expand=n; \
+    }laEndCondition(uil,b0)
+    
+    ADD_WIDTH_OF(3);
+    ADD_WIDTH_OF(5);
+    ADD_WIDTH_OF(8);
+    ADD_WIDTH_OF(13);
+}
+void laui_ToolboxEditor(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil);
+    laUiItem* b=laBeginRow(uil,c,0,0);
+    laShowItemFull(uil,c,0,"la.input_mapping.current_toolbox",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0)
+        ->Flags|=LA_UI_COLLECTION_SIMPLE_SELECTOR;
+    laUiItem* b3=laOnConditionThat(uil,c,laPropExpression(0,"la.input_mapping.current_toolbox"));{
+        laShowItem(uil,c,0,"la.input_mapping.current_toolbox.name");
+        laShowItem(uil,c,0,"LA_new_toolbox")->Flags|=LA_UI_FLAGS_ICON;
+        laShowSeparator(uil,c);
+        laUiItem* cp=laShowInvisibleItem(uil,c,0,"la.input_mapping.current_toolbox");
+        laShowItem(uil,c,&cp->PP,"remove");
+    }laElse(uil,b3);{
+        laShowItem(uil,c,0,"LA_new_toolbox");
+    }laEndCondition(uil,b3);
+    laEndRow(uil,b);
+    b3=laOnConditionThat(uil,c,laPropExpression(0,"la.input_mapping.current_toolbox"));{
+        laUiItem* gui=laMakeEmptyGroup(uil,c,0,0); laUiList* guil=gui->Page; laColumn* gc=laFirstColumn(guil); guil->HeightCoeff=-1;
+        laShowItemFull(guil,gc,0,"la.input_mapping.current_toolbox",LA_WIDGET_COLLECTION_SINGLE,0,laui_ToolboxListing,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
+    }laEndCondition(uil,b3);
+}
+
 void lauidetached_Drivers(laPanel* p){
     la_MakeDetachedProp(p, "la.detached_view_switch", "detached");
     la_MakeDetachedProp(p, "tns.world.root_objects", "root_object");
@@ -2335,8 +2492,7 @@ void la_RegisterBuiltinTemplates(){
     int his=MAIN.InitArgs.HasHistories;
     int ter=MAIN.InitArgs.HasTerminal;
     int act=MAIN.InitArgs.HasAction&&obj;
-            laRegisterUiTemplate("LAUI_input_mapping","Input Mapping",laui_InputMappingBundle,0,0,"Controlling",0,0,0);
-            laRegisterUiTemplate("LAUI_controllers", "Controllers", laui_GameController, lauidetached_GameController, 0,0,0,0,0);
+            laRegisterUiTemplate("LAUI_toolbox","Toolbox",laui_Toolbox,lauidetached_Toolbox,0,"Toolboxes",0,0,0);
     if(obj) laRegisterUiTemplate("LAUI_scene", "Scene", tnsui_ScenePanel, tnsui_DetachedScenePanel, 0, 0, 0,25,25);
     if(obj) laRegisterUiTemplate("LAUI_world_hierachy","World",tnsui_WorldHierachy,0,0,0,0,0,0);
     if(obj) laRegisterUiTemplate("LAUI_object_properties", "Properties", tnsui_ObjectProperties, tnsuidetached_ObjectProperties, 0, 0, 0,15,25);
@@ -2346,6 +2502,9 @@ void la_RegisterBuiltinTemplates(){
     if(obj) laRegisterUiTemplate("LAUI_materials","Materials",laui_Materials,lauidetached_Materials,0,0,0,0,0);
             
             laRegisterUiTemplate("LAUI_user_preferences", "User Preferences", laui_UserPreference, 0, 0, "System",0,25,25);
+            laRegisterUiTemplate("LAUI_toolbox_editor","Toolbox Editor",laui_ToolboxEditor,0,0,0,0,0,0);
+            laRegisterUiTemplate("LAUI_input_mapping","Input Mapping",laui_InputMappingBundle,0,0,0,0,0,0);
+            laRegisterUiTemplate("LAUI_controllers", "Controllers", laui_GameController, lauidetached_GameController, 0,0,0,0,0);\
     if(tex) laRegisterUiTemplate("LAUI_texture_inspector", "Texture Inspector", laui_TextureInspector, lauidetached_TextureInspector, 0, 0, 0,0,0);
             laRegisterUiTemplate("LAUI_data_manager", "Data Manager", laui_IdleDataManager, lauidetached_IdleDataManager, 0, 0, 0,25,25);
     if(his) laRegisterUiTemplate("LAUI_histories", "Histories", laui_UndoHistories, 0, 0, 0, 0,10,25);

+ 2 - 1
resources/la_translations_es-ES.c

@@ -24,6 +24,8 @@
 #include "la_5.h"
 
 static const char *entries[]={
+"Toolbox","Caja de instrumento",
+"Toolboxes","Cajas de herramientas",
 "Performance Overlay", "Superposición de Rendimiento"
 "Menu","Menú",
 "☰ Menu","☰ Menú",
@@ -338,7 +340,6 @@ static const char *entries[]={
 "System","Sistema",
 "Input Mapping","Mapeo de Entrada",
 "Terminal","Terminal",
-"Controlling","Controlando",
 "Tools","Herramientas",
 "Texture Inspector","Inspector de Texturas",
 "Yiming's Blog","Blog de Yiming",

+ 2 - 1
resources/la_translations_zh-hans.c

@@ -19,6 +19,8 @@
 #include "la_5.h"
 
 static const char *entries[]={
+"Toolbox","工具箱",
+"Toolboxes","工具箱",
 "Performance Overlay","性能参数叠加",
 "Menu","菜单",
 "☰ Menu","☰ 菜单",
@@ -333,7 +335,6 @@ static const char *entries[]={
 "System","系统",
 "Input Mapping","输入映射",
 "Terminal","终端",
-"Controlling","控制",
 "Tools","工具",
 "Texture Inspector","纹理检查工具",
 "Yiming's Blog","吴奕茗的博客",

+ 3 - 2
resources/la_widgets.c

@@ -1998,6 +1998,7 @@ void la_ScopeDraw(laUiItem *ui, int h){
     if(s->FromSynth && laget_SynthPlaying(s->FromSynth)){ laDeferredRedraw(MAIN.CurrentPanel); }
 }
 
+void la_DefaultOperatorParser(laStringSplitor *ss, uint32_t *IconID, char *DisplayString);
 void la_MouseActionReporterDraw(laUiItem *ui, int h){
     laBoxedTheme *bt = (*ui->Type->Theme);
     char buf[LA_RAW_CSTR_MAX_LEN] = {0};
@@ -3304,10 +3305,10 @@ int OPMOD_CollectionSelector(laOperator *a, laEvent *e){
     int ReadOnly=laIsPropertyReadOnly(&ui->PP);
     int Simple=ui->Flags&LA_UI_COLLECTION_SIMPLE_SELECTOR;
 
-    if (a->ConfirmData /* && a->ConfirmData->Mode == LA_CONFIRM_DATA*/){
+    if (laConfirmSameDataIfAny(a)){
         ui->State = LA_UI_NORMAL;
         laRecalcCurrentPanel();
-        return LA_RUNNING;
+        return LA_RUNNING_PASS;
     }
 
     if (!laIsInUiItem(ui, e->x, e->y)){