|  | @@ -944,10 +944,34 @@ laPropContainer* tnsget_ObjectType(tnsObject* o){
 | 
	
		
			
				|  |  |  void laget_AnimationActionHolderCategory(void* a_unused, laActionHolder* ah, char* copy, char** ptr){
 | 
	
		
			
				|  |  |      if(ah->CategoryTitle&&ah->CategoryTitle->Ptr) *ptr=ah->CategoryTitle->Ptr;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  int laget_AnimationActionCurrentFrame(laAction* aa){
 | 
	
		
			
				|  |  |      return LA_ACTION_FRAME(aa);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +void laget_AnimationPropStr(laActionProp* ap, char* str, char** here){
 | 
	
		
			
				|  |  | +    sprintf(str,"%s.%s",ap->Prop->Container->Identifier,ap->Prop->Identifier);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +void laread_AnimationPropStr(laActionProp* ap, char* str){
 | 
	
		
			
				|  |  | +    if(!str || !str[0]) return;
 | 
	
		
			
				|  |  | +    laStringSplitor* ss=strSplitPath(str,0); if(ss->NumberParts!=2) goto anim_set_prop_str_cleanup;
 | 
	
		
			
				|  |  | +    laStringPart* sp1=ss->parts.pFirst,*sp2=ss->parts.pLast;
 | 
	
		
			
				|  |  | +    laPropContainer* pc=la_ContainerLookup(sp1->Content); if(!pc) goto anim_set_prop_str_cleanup;
 | 
	
		
			
				|  |  | +    laProp* p=la_PropLookup(&pc->Props,sp2->Content); if(!p) goto anim_set_prop_str_cleanup;
 | 
	
		
			
				|  |  | +    ap->Prop=p;
 | 
	
		
			
				|  |  | +anim_set_prop_str_cleanup:
 | 
	
		
			
				|  |  | +    strDestroyStringSplitor(&ss);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +void* lagetraw_ActionKeyData(laActionKey* ak, int* r_size, int* ret_is_copy){
 | 
	
		
			
				|  |  | +    *r_size=ak->DataSize; *ret_is_copy=1;
 | 
	
		
			
				|  |  | +    void* data=malloc(ak->DataSize); memcpy(data,ak->Data,ak->DataSize);
 | 
	
		
			
				|  |  | +    return data;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +void lasetraw_ActionKeyData(laActionKey* ak, void* data, int DataSize){
 | 
	
		
			
				|  |  | +    ak->DataSize=DataSize; ak->Data=memAcquireSimple(DataSize); memcpy(ak->Data,data,DataSize);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +void laset_AnimationPlayHead(void* unused,real data){
 | 
	
		
			
				|  |  | +    if(data<0){ data=0; }
 | 
	
		
			
				|  |  | +    laAnimationSetPlayHead(data); la_AnimationEvaluateActions(1); laNotifyUsers("la.animation");
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  int laaction_VerifyRootObject(void* Parent, laPropContainer* ParentType, void* Child, laPropContainer* ChildType){
 | 
	
		
			
				|  |  |      if(ParentType!=ChildType) return 0;
 | 
	
	
		
			
				|  | @@ -1182,7 +1206,8 @@ void la_RegisterTNSProps(){
 | 
	
		
			
				|  |  |          TNS_PC_OBJECT_ROOT=p;
 | 
	
		
			
				|  |  |          laAddStringProperty(p, "name", "Object Name", "The Name Of The Object", 0,0,0,0,1, offsetof(tnsObject, Name), 0,0,0,0,LA_AS_IDENTIFIER);
 | 
	
		
			
				|  |  |          laAddSubGroup(p, "base", "Base", "Object base", "tns_object",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
 | 
	
		
			
				|  |  | -        laAddSubGroup(p, "__actions__", "Actions", "Animation actions", "la_animation_action",0,0,0,-1,0,laget_CurrentAnimationAction,0,laset_CurrentAnimationAction,0,0,offsetof(tnsObject, Actions), 0);
 | 
	
		
			
				|  |  | +        laAddSubGroup(p, "__actions__", "Actions", "Animation actions", "la_animation_action",0,0,0,-1,0,laget_CurrentAnimationAction,0,laset_CurrentAnimationAction,0,0,offsetof(tnsRootObject, Actions), 0);
 | 
	
		
			
				|  |  | +        laAddSubGroup(p, "__action_props__", "Action Props", "Action properties", "la_animation_prop",0,0,0,-1,0,0,0,0,0,0,offsetof(tnsRootObject, ActionProps), 0);
 | 
	
		
			
				|  |  |          laAddSubGroup(p, "active_camera", "Active Camera", "Active camera of this root object", "tns_object",0,0,0,offsetof(tnsRootObject, ActiveCamera),0,0,0,0,0,0,0,LA_UDF_REFER|LA_READ_ONLY);
 | 
	
		
			
				|  |  |          ep = laAddEnumProperty(p, "is_2d", "Is 2D", "Is 2D root object", 0,0,0,0,0,offsetof(tnsRootObject, Is2D), 0,tnsset_RootObjectIs2D,0,0,0,0,0,0,0,0);{
 | 
	
		
			
				|  |  |              laAddEnumItemAs(ep, "3D", "3D", "Root object is in 3D", 0, 0);
 | 
	
	
		
			
				|  | @@ -1346,6 +1371,7 @@ void la_RegisterInternalProps(){
 | 
	
		
			
				|  |  |              p = laDefineRoot();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              laAddPropertyContainer("any_pointer", "Any Pointer", "A pointer that is not exposed to access", 0,0,sizeof(void*), 0,0,LA_PROP_OTHER_ALLOC);
 | 
	
		
			
				|  |  | +            laAddPropertyContainer("any_pointer_h2", "Any Pointer (h2)", "A pointer that is not exposed to access", 0,0,sizeof(void*), 0,0,2);
 | 
	
		
			
				|  |  |              
 | 
	
		
			
				|  |  |              laAddSubGroup(p, "tns","TNS", "TNS Kernel Main Structure", "tns_main",0,0,0,-1, tnsget_TnsMain, 0,0,0,0,0,0,LA_UDF_SINGLE | LA_UDF_LOCAL);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1517,7 +1543,7 @@ void la_RegisterInternalProps(){
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          p = laAddPropertyContainer("la_resource_folder", "Resource Folder", "A resource folder to search for UDF references.", 0,laui_ResourceFolderItem, sizeof(laResourceFolder), 0,0,1);{
 | 
	
		
			
				|  |  |              laAddStringProperty(p, "path", "Path", "Path", 0,0,0,0,1, offsetof(laResourceFolder, Path), 0,0,laset_ResourcePath, 0,0);
 | 
	
		
			
				|  |  | -            laAddOperatorProperty(p, "remove", "Remove", "Remove this resource folder entry", "LA_remove_resource_folder", U'❌', 0);
 | 
	
		
			
				|  |  | +            laAddOperatorProperty(p, "remove", "Remove", "Remove this resource folder entry", "LA_remove_resource_folder", U'🞫', 0);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          p = laAddPropertyContainer("managed_udf", "Managed UDF", "Managed UDF files", U'🖹', laui_ManagedUDFItem, sizeof(laManagedUDF), 0,0,0);{
 | 
	
	
		
			
				|  | @@ -1726,12 +1752,12 @@ void la_RegisterInternalProps(){
 | 
	
		
			
				|  |  |              laAddIntProperty(p, "mode", "Mode", "Normal/Floating/Static/Modal etc.", 0,0,0,0,0,1, 0,0,offsetof(laPanel, Mode), 0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
 | 
	
		
			
				|  |  |              ep = laAddEnumProperty(p, "is_menu_panel", "Is Menu Panel", "Is Menu Panel", 0,0,0,0,0,offsetof(laPanel, IsMenuPanel), 0,0,0,0,0,0,0,0,0,0);{
 | 
	
		
			
				|  |  |                  ep->ElementBytes = 1;
 | 
	
		
			
				|  |  | -                laAddEnumItem(ep, "false", "False", "Not A Menu Panel", U'❌');
 | 
	
		
			
				|  |  | +                laAddEnumItem(ep, "false", "False", "Not A Menu Panel", U'🞫');
 | 
	
		
			
				|  |  |                  laAddEnumItem(ep, "true", "IsTrue", "Is A Menu Panel", U'🗩');
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              laAddOperatorProperty(p, "hide", "Hide", "Hide this panel", "LA_hide_panel", U'🗕', 0);
 | 
	
		
			
				|  |  |              laAddOperatorProperty(p, "dock", "Dock", "Dock this panel", "LA_dock_panel", U'🗖', 0);
 | 
	
		
			
				|  |  | -            laAddOperatorProperty(p, "close", "Close", "Close this panel", "LA_block_close_panel", U'❌', 0);
 | 
	
		
			
				|  |  | +            laAddOperatorProperty(p, "close", "Close", "Close this panel", "LA_block_close_panel", U'🞫', 0);
 | 
	
		
			
				|  |  |              //laAddSubGroup(p, "Detached Props", "Detached Props", "detached_prop",0,0,0,0,0,0,0,0,0,0,0,0,offsetof(laPanel, PropLinkContainer->Props), 0);
 | 
	
		
			
				|  |  |              laAddSubGroup(p, "uil","Ui List", "Panel Main Ui List", "ui_list",0,0,0,offsetof(laPanel, UI), 0,0,0,0,0,0,0,LA_UDF_IGNORE);
 | 
	
		
			
				|  |  |              laAddSubGroup(p, "title_uil","Title Ui List", "Panel Title Ui List", "ui_list",0,0,0, offsetof(laPanel, TitleBar), 0,0,0,0,0,0,0,LA_UDF_IGNORE);
 | 
	
	
		
			
				|  | @@ -1880,7 +1906,7 @@ void la_RegisterInternalProps(){
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              laAddSubGroup(p, "current_action", "Current Action", "Current action","la_animation_action",0,0,0,offsetof(laAnimation,CurrentAction),0,0,0,0,0,0,0,LA_UDF_REFER|LA_READ_ONLY);
 | 
	
		
			
				|  |  |              
 | 
	
		
			
				|  |  | -            laAddFloatProperty(p, "play_head","Play Head","Animation viewer global playhead",0,0,"s",0,0,0.1,0,0,offsetof(laAnimation,PlayHead),0,0,0,0,0,0,0,0,0,0,0);
 | 
	
		
			
				|  |  | +            laAddFloatProperty(p, "play_head","Play Head","Animation viewer global playhead",0,0,"s",0,0,0.01,0,0,offsetof(laAnimation,PlayHead),0,laset_AnimationPlayHead,0,0,0,0,0,0,0,0,0);
 | 
	
		
			
				|  |  |              ep=laAddEnumProperty(p, "play_status", "Play Status", "Animation viewer global play status", 0,0,0,0,0,offsetof(laAnimation, PlayStatus),0,0,0,0,0,0,0,0,0,0);
 | 
	
		
			
				|  |  |              laAddEnumItemAs(ep, "PAUSED", "Paused", "Animation is playing", LA_ANIMATION_STATUS_PAUSED, U'⏸');
 | 
	
		
			
				|  |  |              laAddEnumItemAs(ep, "PLAY_FWD", "Playing", "File data is untouched", LA_ANIMATION_STATUS_PLAY_FWD,U'▶');
 | 
	
	
		
			
				|  | @@ -1911,6 +1937,7 @@ void la_RegisterInternalProps(){
 | 
	
		
			
				|  |  |                  laAddEnumItemAs(ep, "REPLACE", "Replace", "Replace previously set values", LA_ANIMATION_MIX_REPLACE,0);
 | 
	
		
			
				|  |  |                  laAddEnumItemAs(ep, "ADD", "Add", "Add on top of previously set values", LA_ANIMATION_MIX_ADD,0);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +            laAddOperatorProperty(p,"remove","Remove","Remove this action","LA_animation_remove_action",L'🞫',0);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          p = laAddPropertyContainer("la_animation_channel", "Channel", "Action channel",0,0,sizeof(laActionChannel),0,0,1);{
 | 
	
		
			
				|  |  |              laAddSubGroup(p, "keys", "Keys", "Key Frames", "la_animation_key",0,0,0,-1,0,0,0,0,0,0,offsetof(laActionChannel, Keys),0);
 | 
	
	
		
			
				|  | @@ -1918,13 +1945,14 @@ void la_RegisterInternalProps(){
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          p = laAddPropertyContainer("la_animation_prop", "Property", "Animation property",0,0,sizeof(laActionProp),0,0,1);{
 | 
	
		
			
				|  |  |              laAddIntProperty(p, "data_size","Data Size","Data size of the channel",0,0,0,0,0,0,0,0,offsetof(laActionProp,DataSize),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
 | 
	
		
			
				|  |  | -            laAddSubGroup(p, "prop", "Property", "Property of this channel", "property_item",0,0,0,offsetof(laActionProp, Prop), 0,0,0,0,0,0,0,LA_UDF_REFER | LA_UDF_IGNORE);
 | 
	
		
			
				|  |  | -            // XXX: Prop needs a string "container.prop" to be able to be able to r/w.
 | 
	
		
			
				|  |  | +            laAddStringProperty(p,"prop_str","Property String","Property of this channel",0,0,0,0,0,0,0,laget_AnimationPropStr,0,laread_AnimationPropStr,LA_READ_ONLY);
 | 
	
		
			
				|  |  | +            laAddStringProperty(p,"cached_str","Cached String","Property name of this channel",0,0,0,0,1,offsetof(laActionProp,CachedName),0,0,0,0,LA_READ_ONLY|LA_AS_IDENTIFIER);
 | 
	
		
			
				|  |  |              laAddSubGroup(p, "for", "For", "Target data block", "any_pointer",0,0,0,offsetof(laActionProp, For), 0,0,0,0,0,0,0,LA_UDF_REFER);
 | 
	
		
			
				|  |  | +            laAddSubGroup(p, "for_h2", "For H2", "Target data block (hyper 2)", "any_pointer_h2",0,0,0,offsetof(laActionProp, For), 0,0,0,0,0,0,0,LA_UDF_REFER);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          p = laAddPropertyContainer("la_animation_key", "key", "Action channel",0,0,sizeof(laActionKey),0,0,1);{
 | 
	
		
			
				|  |  |              laAddIntProperty(p, "at","At","Frame number of this key frame",0,0,0,0,0,0,0,0,offsetof(laActionKey,At),0,0,0,0,0,0,0,0,0,0,0);
 | 
	
		
			
				|  |  | -            // XXX: RAW for r/w.
 | 
	
		
			
				|  |  | +            laAddRawProperty(p,"data","Data","Data of this key frame",0,0,lagetraw_ActionKeyData,lasetraw_ActionKeyData,0);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          p = laAddPropertyContainer("la_animation_action_holder", "Action Holder", "Action holder",0,0,sizeof(laActionHolder),0,0,1);{
 | 
	
		
			
				|  |  |              laAddStringProperty(p,"name","Name","Name of the action",0,0,0,0,1,offsetof(laActionHolder,Name),0,0,0,0,LA_AS_IDENTIFIER);
 |