*/}}
YimingWu преди 4 месеца
родител
ревизия
c529530232
променени са 5 файла, в които са добавени 219 реда и са изтрити 19 реда
  1. 8 0
      la_interface.h
  2. 7 3
      la_kernel.c
  3. 39 3
      resources/la_operators.c
  4. 62 2
      resources/la_properties.c
  5. 103 11
      resources/la_templates.c

+ 8 - 0
la_interface.h

@@ -502,6 +502,8 @@ STRUCTURE(LA){
     //laHash256 CustomCommandHash;
     laSafeString* SignalFilter;
     laListHandle CustomSignals;
+    laSafeString* OperatorFilter;
+    laListHandle OperatorList;
     laSafeString* ThumbnailProp;
 
     laListHandle ExtraExtensions;
@@ -1478,6 +1480,7 @@ typedef int (*laSystemFunc)(laOperator *, laEvent *);
 
 STRUCTURE(laOperatorType){
     laListItem Item;
+    laListItem ListItem;
 
     const char *Identifier;
     const char *Name;
@@ -1560,12 +1563,16 @@ STRUCTURE(laInputMapping){
 };
 STRUCTURE(laInputMappingEntry){
     laListItem Item;
+    int Disabled;
     laInputMapping* Parent;
     int DeviceType;
     int JoystickDevice; int Axis, Button;
     laSafeString* Key; int KeyValue;
     int SpecialKeyBits;
     laSafeString* Signal; int SignalValue;
+    int UseOperator;
+    laSafeString* Operator,*OperatorName,*OperatorArguments;
+    int OperatorBase;
 };
 STRUCTURE(laInputMappingBundle){
     void* _pad;
@@ -2204,6 +2211,7 @@ void laui_ManagedUDFOps(laUiList *uil, laPropPack *Base, laPropPack *OperatorIns
 void laui_ManagedProp(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
 void laui_ManagedSavePanel(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
 void laui_ManagedUDFPanel(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+void laui_OperatorTypeEntry(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *ExtraColumns, int context);
 void laui_FileBrowserFileList(laUiList *uil, laPropPack *THIS_UNUSED, laPropPack *Operator, laColumn *UNUSED, int context);
 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);

+ 7 - 3
la_kernel.c

@@ -1418,12 +1418,14 @@ int laGetReadyWith(laInitArguments* ia){
     la_RegisterMainThemes();
     la_RegisterMainOperators();
     la_RegisterMainUiTypes();
-    la_RegisterModellingOperators();
-    la_RegisterShapeOperators();
     la_RegisterInternalProps();
     la_RegisterAnimationResources();
     la_RegisterWindowKeys();
 
+    if(MAIN.InitArgs.HasWorldObjects){
+        la_RegisterModellingOperators();
+        la_RegisterShapeOperators();
+    }
     if(MAIN.InitArgs.HasAudio) laInitAudio();
 
     laFinalizeUiTemplates();
@@ -1767,10 +1769,11 @@ laInputMappingEntry* laNewInputMappingEntry(laInputMapping* im, int DeviceType,
     e->SpecialKeyBits=SpecialKeyBit;
     char buf[64],*_next=buf;
     la_InputMappingGetKeyName(e->KeyValue,e->SpecialKeyBits,buf); strSafeSet(&e->Key,buf);
+    return e;
 }
 laInputMappingEntry* laNewInputMappingEntryP(laInputMapping* im, int DeviceType, int JoystickDevice, char* Key, int SpecialKeyBit, int Signal){
     laCustomSignal* cs; if(!(cs=laFindSignalByID(Signal))) return 0;
-    laNewInputMappingEntry(im,DeviceType,JoystickDevice,Key,SpecialKeyBit,SSTR(cs->Name));
+    return laNewInputMappingEntry(im,DeviceType,JoystickDevice,Key,SpecialKeyBit,SSTR(cs->Name));
 }
 void laRemoveInputMappingEntry(laInputMapping* im, laInputMappingEntry* e){
     memAssignRef(e,&e->Parent,0); lstRemoveItem(&im->Entries,e); strSafeDestroy(&e->Signal); strSafeDestroy(&e->Key); memFree(e);
@@ -7173,6 +7176,7 @@ laOperatorType *laCreateOperatorType(const char *ID, const char *Name, const cha
     at->ParseArgs = la_DefaultOperatorParser;
 
     hsh256InsertItemCSTR(&MAIN.OperatorTypeHash, at, at->Identifier);
+    lstAppendItem2(&MAIN.OperatorList, at);
 
     return at;
 }

+ 39 - 3
resources/la_operators.c

@@ -938,7 +938,12 @@ 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;
-    laNewInputMappingEntry(im,0,0,"a",0,"none"); laNotifyUsers("la.input_mapping"); return LA_FINISHED;
+    laInputMappingEntry* ime=laNewInputMappingEntry(im,0,0,"a",0,"none");
+    if(strArgumentMatch(a->ExtraInstructionsP,"position","top")){
+        lstRemoveItem(&im->Entries,ime);
+        lstPushItem(&im->Entries,ime);
+    }
+    laNotifyUsers("la.input_mapping"); return LA_FINISHED;
 }
 int OPINV_RemoveInputMappingEntry(laOperator *a, laEvent *e){
     if(!a->This || !a->This->EndInstance) return LA_CANCELED; laInputMappingEntry* ie=a->This->EndInstance;
@@ -969,7 +974,7 @@ int OPMOD_RemoveInputMappingEntry(laOperator *a, laEvent *e){
 
 int OPINV_InputMappingEntrySelectSignal(laOperator *a, laEvent *e){
     if(!a->This || !a->This->EndInstance) return LA_CANCELED; laInputMappingEntry* ime=a->This->EndInstance;
-    laEnableOperatorPanel(a,a->This,e->x-LA_RH*5,e->y-LA_RH,LA_RH*10,LA_RH*10,LA_RH*30,LA_RH*30,0,0,0,0,0,0,e);
+    laEnableOperatorPanel(a,a->This,e->x-LA_RH*5,e->y-LA_RH,LA_RH*15,LA_RH*15,LA_RH*30,LA_RH*30,0,0,0,0,0,0,e);
     return LA_RUNNING;
 }
 int OPMOD_InputMappingEntrySelectSignal(laOperator *a, laEvent *e){
@@ -995,6 +1000,35 @@ void laui_InputMappingEntrySignalSelector(laUiList *uil, laPropPack *Base, laPro
     laShowItemFull(guil,gc,0,"la.filtered_signals",LA_WIDGET_COLLECTION,0,0,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
 }
 
+int OPINV_InputMappingEntrySelectOperator(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance) return LA_CANCELED; laInputMappingEntry* ime=a->This->EndInstance;
+    laEnableOperatorPanel(a,a->This,e->x-LA_RH*5,e->y-LA_RH,LA_RH*15,LA_RH*20,LA_RH*30,LA_RH*35,0,0,0,0,0,0,e);
+    return LA_RUNNING;
+}
+int OPMOD_InputMappingEntrySelectOperator(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance) return LA_CANCELED; laInputMappingEntry* ime=a->This->EndInstance;
+    if(a->ConfirmData){
+        if(a->ConfirmData->Mode == LA_CONFIRM_DATA && a->ConfirmData->PointerData && strSame(a->ConfirmData->PointerType->Identifier,"la_operator_type")){
+            laOperatorType* at=a->ConfirmData->PointerData;
+            strSafeSet(&ime->Operator,at->Identifier);
+            strSafeSet(&ime->OperatorName,at->Name);
+            laNotifyUsers("la.input_mapping");
+        }
+        return LA_FINISHED;
+    }
+    return LA_RUNNING;
+}
+void laui_InputMappingEntryOperatorSelector(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn* c=laFirstColumn(uil);
+
+    laUiItem* b=laBeginRow(uil,c,0,0);
+    laShowLabel(uil,c,"🔍",0,0);
+    laUiItem* ui=laShowItem(uil,c,0,"la.operator_filter");ui->Expand=1;ui->Flags|=LA_UI_FLAGS_IMMEDIATE_INPUT;
+    laEndRow(uil,b);
+    laUiItem* g=laMakeEmptyGroup(uil,c,0,0); laUiList* guil=g->Page; laColumn* gc=laFirstColumn(guil); guil->HeightCoeff=20;
+    laShowItemFull(guil,gc,0,"la.filtered_operators",LA_WIDGET_COLLECTION,0,laui_OperatorTypeEntry,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
+}
+
 STRUCTURE(laKeyDetectorData){
     int pad;
     int IsController;
@@ -1046,7 +1080,7 @@ int OPMOD_InputMappingEntrySelectKey(laOperator *a, laEvent *e){
 void laui_InputMappingEntryKeySelector(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
     laColumn* c=laFirstColumn(uil);
 
-    laShowLabel(uil,c,"Press a Key:",0,0);
+    laShowLabel(uil,c,"Press a key:",0,0);
     laShowItem(uil,c,OperatorInst,"pressed_string")->Flags|=LA_UI_FLAGS_PLAIN;
 
     laUiItem* b=laBeginRow(uil,c,0,0);
@@ -2569,6 +2603,8 @@ void la_RegisterBuiltinOperators(){
     laCreateOperatorType("LA_remove_input_mapping_entry", "Remove Entry", "Remove input mapping entry", 0, 0, 0, OPINV_RemoveInputMappingEntry, OPMOD_RemoveInputMappingEntry, U'🞫', LA_ACTUATOR_SYSTEM);
     at = laCreateOperatorType("LA_input_mapping_entry_select_signal", "Select Signal", "Select signal for this entry", 0, 0, 0, OPINV_InputMappingEntrySelectSignal, OPMOD_InputMappingEntrySelectSignal, U'⯆', LA_ACTUATOR_SYSTEM);
     at->UiDefine = laui_InputMappingEntrySignalSelector;
+    at = laCreateOperatorType("LA_input_mapping_entry_select_operator", "Select Operator", "Select operator for this entry", 0, 0, 0, OPINV_InputMappingEntrySelectOperator, OPMOD_InputMappingEntrySelectOperator, U'⯆', LA_ACTUATOR_SYSTEM);
+    at->UiDefine = laui_InputMappingEntryOperatorSelector;
     at = laCreateOperatorType("LA_input_mapping_entry_select_key", "Select Key", "Select key for this entry", 0, 0, OPEXT_InputMappingEntrySelectKey, OPINV_InputMappingEntrySelectKey, OPMOD_InputMappingEntrySelectKey, U'K', LA_ACTUATOR_SYSTEM);
     at->UiDefine = laui_InputMappingEntryKeySelector;
     pc = laDefineOperatorProps(at, 1);

+ 62 - 2
resources/la_properties.c

@@ -857,6 +857,20 @@ void laset_InputMappingEntryKeyString(laInputMappingEntry* ime, char* key){
 void laset_InputMappingEntrySignalString(laInputMappingEntry* ime, char* sig){
     strSafeSet(&ime->Signal,sig); laInputMappingUpdateSignal(ime); 
 }
+void laset_InputMappingEntryMove(laInputMappingEntry* ime, int move){
+    laInputMapping* im = ime->Parent;
+    if(move<0 && ime->Item.pPrev){ lstMoveUp(&im->Entries, ime); laNotifyUsers("la.input_mapping"); }
+    elif(move>0 && ime->Item.pNext){ lstMoveDown(&im->Entries, ime); laNotifyUsers("la.input_mapping"); }
+}
+void laset_InputMappingEntryOperatorString(laInputMappingEntry* ime, char* string){
+    strSafeSet(&ime->Operator,string);
+    laOperatorType* at=laGetOperatorType(string);
+    if(at){
+        strSafeSet(&ime->OperatorName, at->Name);
+    }else{
+        strSafeDestroy(&ime->OperatorName);
+    }
+}
 void laset_SignalFilter(void* unused, char* sig){
     strSafeSet(&MAIN.SignalFilter,sig);
     laNotifyUsers("la.filtered_signals");
@@ -871,6 +885,30 @@ void* lagetnext_FilteredSignal(laCustomSignal* p, laPropIterator* pi){
     while(!strstr(SSTR(p->Name),SSTR(MAIN.SignalFilter))){ p=p->Item.pNext; if(!p){ return 0; } }
     return p;
 }
+void laset_OperatorFilter(void* unused, char* sig){
+    strSafeSet(&MAIN.OperatorFilter,sig);
+    laNotifyUsers("la.filtered_operators");
+}
+void* laget_FirstFilteredOperator(void* unused1,laPropIterator* pi){
+    laOperatorType* at = MAIN.OperatorList.pFirst;
+    while(at->ExtraMark & (LA_ACTUATOR_HIDDEN|LA_ACTUATOR_SYSTEM)){
+        at=at->ListItem.pNext; if(!at){ return 0; }
+    }
+    while((!strstr(at->Name,SSTR(MAIN.OperatorFilter))) && (!strstr(at->Identifier,SSTR(MAIN.OperatorFilter)))){
+        at=at->ListItem.pNext; if(!at){ return 0; }
+    }
+    return at;
+}
+void* lagetnext_FilteredOperator(laOperatorType* at, laPropIterator* pi){
+    at=at->ListItem.pNext; if(!at){ return 0; }
+    while(at->ExtraMark & (LA_ACTUATOR_HIDDEN|LA_ACTUATOR_SYSTEM)){
+        at=at->ListItem.pNext; if(!at){ return 0; }
+    }
+    while((!strstr(at->Name,SSTR(MAIN.OperatorFilter))) && (!strstr(at->Identifier,SSTR(MAIN.OperatorFilter)))){
+        at=at->ListItem.pNext; if(!at){ return 0; }
+    }
+    return at;
+}
 
 void tnspost_World(tnsWorld *w){
     tnsRefreshMaterialLibraries();
@@ -1581,8 +1619,10 @@ void la_RegisterInternalProps(){
 
             laAddSubGroup(p,"input_mapping","Input Mapping","Input mapping bundle","la_input_mapping_bundle",0,0,0,offsetof(LA,InputMapping),0,0,0,0,0,0,0,LA_UDF_SINGLE);
             laAddStringProperty(p,"signal_filter","Signal Filter","Filter displayed signals",0,0,0,0,1,offsetof(LA,SignalFilter),0,0,laset_SignalFilter,0,0);
+            laAddStringProperty(p,"operator_filter","Operator Filter","Filter displayed operators",0,0,0,0,1,offsetof(LA,OperatorFilter),0,0,laset_OperatorFilter,0,0);
             laAddSubGroup(p,"custom_signals","Signals","Registered custom signals","la_custom_signal",0,0,laui_IdentifierOnly,-1,laget_FirstCustomSignal,0,laget_ListNext,0,0,0,0,LA_UDF_IGNORE);
             laAddSubGroup(p,"filtered_signals","Filtered Signals","Filtered custom signals","la_custom_signal",0,0,laui_IdentifierOnly,-1,laget_FirstFilteredCustomSignal,0,lagetnext_FilteredSignal,0,0,0,0,LA_UDF_IGNORE);
+            laAddSubGroup(p,"filtered_operators","Filtered Operators","Filtered operators","la_operator_type",0,0,laui_IdentifierOnly,-1,laget_FirstFilteredOperator,0,lagetnext_FilteredOperator,0,0,0,0,LA_UDF_IGNORE);
             
             laAddStringProperty(p, "identifier", "Identifier", "Identifier", 0,0,0,0,0,0,0,laget_MainIdentifier, 0,0,LA_AS_IDENTIFIER|LA_READ_ONLY);
   
@@ -1814,21 +1854,41 @@ void la_RegisterInternalProps(){
             laAddOperatorProperty(p,"new_entry","New Entry","New mapping 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);
+            laAddEnumItemAs(ep, "ENABLED", "Enabled", "Entry enabled", 0, U'✓');
+            laAddEnumItemAs(ep, "DISABLED", "Disabled", "Entry disabled", 1, U'✗');
             ep=laAddEnumProperty(p,"device_type","Device Type","Device type of the input event",0,0,0,0,0,offsetof(laInputMappingEntry,DeviceType),0,0,0,0,0,0,0,0,0,0);
-            laAddEnumItemAs(ep, "KEYBOARD", "Keyboard", "Keyboard input", LA_INPUT_DEVICE_KEYBOARD, 0);
-            laAddEnumItemAs(ep, "JOYSTICK", "Joystick", "Joystick input", LA_INPUT_DEVICE_JOYSTICK, 0);
+            laAddEnumItemAs(ep, "KEYBOARD", "Keyboard", "Keyboard input", LA_INPUT_DEVICE_KEYBOARD, U'🖮');
+            laAddEnumItemAs(ep, "JOYSTICK", "Joystick", "Joystick input", LA_INPUT_DEVICE_JOYSTICK, U'🕹');
             laAddIntProperty(p,"joystick_device","Joystick Device","Joystick device number",0,0,0,0,0,0,0,0,offsetof(laInputMappingEntry,JoystickDevice),0,0,0,0,0,0,0,0,0,0,0);
             laAddStringProperty(p,"key","Key","Event key",0,0,0,0,1,offsetof(laInputMappingEntry,Key),0,0,laset_InputMappingEntryKeyString,0,0);
             laAddStringProperty(p,"signal","Signal","Target signal",0,0,0,0,1,offsetof(laInputMappingEntry,Signal),0,0,laset_InputMappingEntrySignalString,0,0);
             laAddSubGroup(p,"signal_selection","Signal","Signal selection","la_custom_signal",0,0,laui_IdentifierOnly,-1,laget_FirstCustomSignal,0,laget_ListNext,laset_InputMappingEntrySignal,0,0,0,LA_UDF_IGNORE);
             laAddOperatorProperty(p,"remove","Remove","Remove this entry","LA_remove_input_mapping_entry",U'🞫',0);
             laAddOperatorProperty(p,"select_signal","Select","Select signal","LA_input_mapping_entry_select_signal",0,0);
+            laAddOperatorProperty(p,"select_operator","Select","Select operator","LA_input_mapping_entry_select_operator",0,0);
             laAddOperatorProperty(p,"select_key","Select Key","Select key","LA_input_mapping_entry_select_key",0,0);
             laAddSubGroup(p,"parent","Parent","Parent group","la_input_mapping",0,0,0,offsetof(laInputMappingEntry,Parent),0,0,0,0,0,0,0,LA_UDF_REFER);
+            ep=laAddEnumProperty(p,"use_operator","Device Type","Device type of the input event",0,0,0,0,0,offsetof(laInputMappingEntry,UseOperator),0,0,0,0,0,0,0,0,0,0);
+            laAddEnumItemAs(ep, "SIGNAL", "Signal", "Send signal upon input", 0, U'⚟');
+            laAddEnumItemAs(ep, "OPERATOR", "Operator", "Run operator upon input", 1, U'🏃');
+            laAddStringProperty(p,"operator","Operator","Operator to call",0,0,0,0,1,offsetof(laInputMappingEntry,Operator),0,0,laset_InputMappingEntryOperatorString,0,0);
+            laAddStringProperty(p,"operator_name","Operator Name","Target operator name",0,0,0,0,1,offsetof(laInputMappingEntry,OperatorName),0,0,0,0,LA_READ_ONLY);
+            laAddStringProperty(p,"operator_arguments","Arguments","Extra arguments for the operator",0,0,0,0,1,offsetof(laInputMappingEntry,OperatorArguments),0,0,0,0,0);
+            ep=laAddEnumProperty(p,"operator_base","Operator Base","Operator parent context base",0,0,0,0,0,offsetof(laInputMappingEntry,OperatorBase),0,0,0,0,0,0,0,0,0,0);
+            laAddEnumItemAs(ep, "NONE", "None", "Run operator directly", 0, 0);
+            laAddEnumItemAs(ep, "WIDGET", "Widget", "Run operator with extra reference of current UI", LA_KM_SEL_UI_EXTRA, 0);
+            laAddEnumItemAs(ep, "PANEL", "Panel", "Run operator with extra reference of current panel", LA_KM_SEL_PANEL, 0);
         }
         p = laAddPropertyContainer("la_custom_signal", "Custom Signal", "Custom signal", 0,0,sizeof(laCustomSignal), 0,0,1);{
             laAddStringProperty(p, "name", "Name", "The name of this mapping", 0,0,0,"Mapping", 1, offsetof(laCustomSignal, Name), 0,0,0,0,LA_AS_IDENTIFIER);
         }
+        p = laAddPropertyContainer("la_operator_type", "Operator Type", "Operator type", 0,laui_OperatorTypeEntry,sizeof(laOperatorType), 0,0,1);{
+            laAddStringProperty(p, "identifier", "Identifier", "The identifier of the operator", 0,0,0, "none", 0, offsetof(laOperatorType, Identifier), 0,0,0,0,LA_AS_IDENTIFIER|LA_READ_ONLY);
+            laAddStringProperty(p, "name", "Name", "The name of operator", 0,0,0, "none", 0, offsetof(laOperatorType, Name), 0,0,0,0,LA_READ_ONLY);
+            laAddStringProperty(p, "description", "Description", "Description of the operator", 0,0,0, "none", 0, offsetof(laOperatorType, Description), 0,0,0,0,LA_READ_ONLY);
+        }
 
         p = laAddPropertyContainer("la_translation_language", "Language", "Translation language pack", 0,0,sizeof(laTranslationNode), 0,0,1);{
             laAddStringProperty(p, "name", "Name", "The name of this language", 0,0,0,"Unknown", 1, offsetof(laTranslationNode, LanguageName), 0,0,0,0,LA_AS_IDENTIFIER);

+ 103 - 11
resources/la_templates.c

@@ -622,7 +622,9 @@ void laui_DefaultMenuBarActual(laUiList *uil, laPropPack *pp, laPropPack *actins
         if(MAIN.MenuExtras){ laShowSeparator(uil,c); MAIN.MenuExtras(uil,0,0,0,0); }
 
         laUiItem* b1=laOnConditionThat(uil,c,laPropExpression(0,"la.windows.panels_hidden"));
+#ifndef LAGUI_ANDROID
             laShowSeparator(uil,c);
+#endif
             muil = laMakeMenuPage(uil, c, "🡻 Minimized");{
                 mc = laFirstColumn(muil);
                 laShowItemFull(muil, mc, 0, "la.windows.panels_hidden", 0,0, laui_IdentifierOnly,0);
@@ -1658,36 +1660,126 @@ void laui_GameController(laUiList *uil, laPropPack *This, laPropPack *Extra, laC
 void lauidetached_GameController(laPanel* p){
     la_MakeDetachedProp(p, "la.controllers", "controllers");
 }
-void laui_InputMappingEntry(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
-    laColumn* c=laFirstColumn(uil);
+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;
+    laShowItem(uil,c,This,"identifier")->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED|LA_UI_FLAGS_PLAIN;
+    laShowSeparator(uil,c);
+}
+void laui_InputMappingEntry(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *ExtraColumns, int context){
+    laColumn* c=ExtraColumns;
+    laColumn* cl=laLeftColumn(c,3),*cr=laRightColumn(c,0);
+    laColumn* crl=laLeftColumn(cr,0),*crr=laRightColumn(cr,0);
 
-    laUiItem* b=laBeginRow(uil,c,0,0);
+    laUiItem* b,*b1,*b2,*b3,*b4;
 
-    laShowItem(uil,c,This,"remove")->Flags|=LA_UI_FLAGS_ICON;
+#if 1
+    b=laBeginRow(uil,cl,0,0);
+    laShowItem(uil,cl,This,"__move");
+    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;
+
+        b2=laBeginRow(uil,crl,0,0);{
+            b3=laOnConditionThat(uil,crl,laPropExpression(This,"use_operator"));{
+                laUiItem* pui = laShowInvisibleItem(uil,crl,This,"operator");
+                laShowItemFull(uil,crl,&pui->PP,"restore",0,"icon=🧹",0,0)->Flags|=LA_UI_FLAGS_ICON;
+                laUiItem* bui=laShowItemFull(uil,crl,This,"select_operator",0,"icon= ;",0,0);
+                bui->Expand=1; bui->Flags|=LA_UI_FLAGS_ICON|LA_UI_FLAGS_UNDERNEATH;
+                laUiItem* ui=laShowItem(uil,crl,&pui->PP,"");
+                ui->Expand=1; ui->Flags|=LA_UI_FLAGS_PLAIN;
+            }laElse(uil,b3);{
+                laUiItem* pui = laShowInvisibleItem(uil,crl,This,"signal");
+                laShowItemFull(uil,crl,&pui->PP,"restore",0,"icon=🧹",0,0)->Flags|=LA_UI_FLAGS_ICON;
+                laUiItem* bui=laShowItemFull(uil,crl,This,"select_signal",0,"icon= ;",0,0);
+                bui->Expand=1; bui->Flags|=LA_UI_FLAGS_ICON|LA_UI_FLAGS_UNDERNEATH;
+                laUiItem* ui=laShowItem(uil,crl,&pui->PP,"");
+                ui->Expand=1; ui->Flags|=LA_UI_FLAGS_PLAIN;
+            }laEndCondition(uil,b3);
+        }laEndRow(uil,b2);
+        
+        b2=laBeginRow(uil,crr,0,0);{
+            laShowSeparator(uil,crr);
+            laUiItem* pui = laShowInvisibleItem(uil,crr,This,"key");
+            laShowItemFull(uil,crr,&pui->PP,"restore",0,"icon=🧹",0,0)->Flags|=LA_UI_FLAGS_ICON;
+            laUiItem* bui=laShowItemFull(uil,crr,This,"select_key",0,"icon= ;",0,0);
+            bui->Expand=1; bui->Flags|=LA_UI_FLAGS_ICON|LA_UI_FLAGS_UNDERNEATH;
+            laUiItem* ui=laShowItem(uil,crr,&pui->PP,"");
+            ui->Expand=1; ui->Flags|=LA_UI_FLAGS_PLAIN;
+            laShowItem(uil,crr,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,"device_type")->Flags|=LA_UI_FLAGS_EXPAND|LA_UI_FLAGS_TRANSPOSE;
+        }laEndRow(uil,b2);
+        b2=laBeginRow(uil,crl,0,0);{
+            b3=laBeginRow(uil,crl,0,0);{
+                laUiItem* ui=laShowItem(uil,crl,This,"use_operator"); ui->Flags|=LA_UI_FLAGS_EXPAND|LA_UI_FLAGS_TRANSPOSE;
+                b4=laOnConditionThat(uil,crr,laPropExpression(&ui->PP,""));{
+                    laUiItem* ui1=laShowItem(uil,crl,This,"operator_base");
+                    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;
+                }laElse(uil,b4);{
+                    laEndRow(uil,b3);
+                }laEndCondition(uil,b4);
+            }
+            laEndRow(uil,b3);
+        }laEndRow(uil,b2);
+        laShowSeparator(uil,c);
+    }laElse(uil,b1);{
+        laEndRow(uil,b);
+        b2=laBeginRow(uil,crl,0,0);{
+            laShowItem(uil,crl,This,"use_operator")->Flags=LA_UI_FLAGS_ICON|LA_UI_FLAGS_PLAIN;
+            b3=laOnConditionThat(uil,crl,laPropExpression(This,"use_operator"));{
+                laUiItem* ui=laShowItem(uil,crl,This,"operator_name");ui->Expand=1;ui->Flags|=LA_UI_FLAGS_PLAIN;
+            }laElse(uil,b3);{
+                laUiItem* ui=laShowItem(uil,crl,This,"signal");ui->Expand=1;ui->Flags|=LA_UI_FLAGS_PLAIN;
+            }laEndCondition(uil,b3);
+        }laEndRow(uil,b2);
+        b2=laBeginRow(uil,crr,0,0);{
+            laShowSeparator(uil,crr);
+            laShowItem(uil,crr,This,"device_type")->Flags|=LA_UI_FLAGS_ICON|LA_UI_FLAGS_PLAIN;
+            //laUiItem* uib=laShowItemFull(uil,crr,This,"select_key",0,"icon= ;",0,0);
+            //uib->Expand=1; uib->Flags|=LA_UI_FLAGS_ICON|LA_UI_FLAGS_UNDERNEATH;
+            laUiItem* ui=laShowItem(uil,crr,This,"key"); ui->Expand=1;ui->Flags|=LA_UI_FLAGS_PLAIN;
+            laShowItem(uil,crr,This,"remove")->Flags|=LA_UI_FLAGS_ICON;
+        }laEndRow(uil,b2);
+    }laEndCondition(uil,b1);
 
+#else
+    laUiItem* b=laBeginRow(uil,c,0,0);
+    laShowItem(uil,c,This,"remove")->Flags|=LA_UI_FLAGS_ICON;
     laShowItem(uil,c,This,"device_type");
     laUiItem* b1=laOnConditionThat(uil,c,laEqual(laPropExpression(This,"device_type"),laIntExpression(LA_INPUT_DEVICE_JOYSTICK)));{
         laShowItem(uil,c,This,"joystick_device");
     }laEndCondition(uil,b1);
-
     laShowItem(uil,c,This,"key")->Expand=1;
     laShowItem(uil,c,This,"select_key")->Flags|=LA_UI_FLAGS_ICON;
-
-    
     laShowItem(uil,c,This,"signal")->Expand=1;
     //laShowItemFull(uil,c,This,"signal_selection",LA_WIDGET_COLLECTION_SELECTOR,0,0,0)->Flags|=LA_UI_COLLECTION_SIMPLE_SELECTOR;
     laShowItem(uil,c,This,"select_signal")->Flags|=LA_UI_FLAGS_ICON;
-
     laEndRow(uil,b);
+#endif
 }
 void laui_InputMapping(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
-    laColumn* c=laFirstColumn(uil);
+    laColumn* c=laFirstColumn(uil);laSplitColumn(uil,c,0.3);
+    laColumn* cl=laLeftColumn(c,3),*cr=laRightColumn(c,0);laSplitColumn(uil,cr,0.6);
+    laColumn* crl=laLeftColumn(cr,0),*crr=laRightColumn(cr,0);
 
     laUiItem* b=laBeginRow(uil,c,0,0);
-    laShowItem(uil,c,This,"new_entry");
+    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_InputMappingEntry,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
 
     laShowSeparator(uil,c);